hub.sr.ht/hubsrht/services.py

308 lines
11 KiB
Python
Raw Normal View History

import os.path
2020-03-24 15:26:15 +01:00
import requests
2020-03-31 21:08:00 +02:00
from abc import ABC
2020-03-31 22:09:33 +02:00
from flask import url_for
from jinja2 import Markup, escape
2020-03-24 15:26:15 +01:00
from srht.api import ensure_webhooks, get_authorization, get_results
from srht.markdown import markdown
2020-03-24 15:26:15 +01:00
from srht.config import get_origin
_gitsrht = get_origin("git.sr.ht", external=True, default=None)
2020-04-06 19:21:13 +02:00
_hgsrht = get_origin("hg.sr.ht", external=True, default=None)
2020-03-25 15:08:29 +01:00
_listsrht = get_origin("lists.sr.ht", external=True, default=None)
2020-04-02 00:51:14 +02:00
_todosrht = get_origin("todo.sr.ht", external=True, default=None)
2020-03-31 22:09:33 +02:00
origin = get_origin("hub.sr.ht")
2020-03-24 15:26:15 +01:00
readme_names = ["README.md", "README.markdown", "README"]
def format_readme(content, filename="", link_prefix=None):
markdown_exts = ['.md', '.markdown']
basename, ext = os.path.splitext(filename)
if ext in markdown_exts:
html = markdown(content, ["h1", "h2", "h3", "h4", "h5"],
link_prefix=link_prefix)
else:
html = f"<pre>{escape(content)}</pre>"
return Markup(html)
2020-03-31 21:08:00 +02:00
class SrhtService(ABC):
def __init__(self):
self.session = requests.Session()
def post(self, user, valid, url, payload):
r = self.session.post(url,
headers=get_authorization(user),
json=payload)
if r.status_code == 400:
for error in r.json()["errors"]:
valid.error(error["reason"], field=error.get("field"))
return None
elif r.status_code != 201:
raise Exception(r.text)
return r.json()
class GitService(SrhtService):
def __init__(self):
super().__init__()
2020-03-24 15:26:15 +01:00
def get_repos(self, user):
return get_results(f"{_gitsrht}/api/repos", user)
def get_repo(self, user, repo_name):
2020-03-31 21:08:00 +02:00
r = self.session.get(f"{_gitsrht}/api/repos/{repo_name}",
2020-03-24 15:26:15 +01:00
headers=get_authorization(user))
if r.status_code != 200:
2020-03-31 17:17:19 +02:00
raise Exception(r.text)
2020-03-24 15:26:15 +01:00
return r.json()
def get_readme(self, user, repo_name, repo_url):
# TODO: Cache?
# TODO: Use default branch
link_prefix = repo_url + "/blob/refs/heads/master/"
for readme_name in readme_names:
r = self.session.get(f"{_gitsrht}/api/repos/{repo_name}/blob/master/{readme_name}",
headers=get_authorization(user))
if r.status_code == 404:
continue
elif r.status_code != 200:
raise Exception(r.text)
return format_readme(r.text, readme_name, link_prefix)
return format_readme("")
2020-03-31 17:17:19 +02:00
def create_repo(self, user, valid):
name = valid.require("name")
2020-04-30 15:59:51 +02:00
description = valid.require("description")
2020-03-31 17:17:19 +02:00
if not valid.ok:
return None
2020-03-31 21:08:00 +02:00
return self.post(user, valid, f"{_gitsrht}/api/repos", {
"name": name,
"description": description,
"visibility": "public", # TODO: Should this be different?
})
2020-03-31 17:17:19 +02:00
2020-04-01 20:47:47 +02:00
def delete_repo(self, user, repo_name):
r = self.session.delete(f"{_gitsrht}/api/repos/{repo_name}",
headers=get_authorization(user))
if r.status_code != 204 and r.status_code != 404:
2020-04-01 20:47:47 +02:00
raise Exception(r.text)
2020-03-31 22:09:33 +02:00
def ensure_user_webhooks(self, user):
config = {
2020-04-06 22:15:52 +02:00
origin + url_for("webhooks.git_user", user_id=user.id):
2020-03-31 22:09:33 +02:00
["repo:update", "repo:delete"],
}
2020-03-24 15:26:15 +01:00
ensure_webhooks(user, f"{_gitsrht}/api/user/webhooks", config)
2020-04-23 17:32:15 +02:00
def ensure_user_webhooks(self, user):
config = { }
ensure_webhooks(user, f"{_gitsrht}/api/user/webhooks", config)
2020-04-06 22:15:52 +02:00
def ensure_repo_webhooks(self, repo):
2020-03-31 22:09:33 +02:00
config = {
2020-04-06 22:15:52 +02:00
origin + url_for("webhooks.git_repo", repo_id=repo.id):
["repo:post-update"],
2020-03-31 22:09:33 +02:00
}
2020-04-06 22:15:52 +02:00
owner = repo.owner
url = f"{_gitsrht}/api/{owner.canonical_name}/repos/{repo.name}/webhooks"
ensure_webhooks(owner, url, config)
2020-03-31 22:09:33 +02:00
2020-04-23 17:32:15 +02:00
def unensure_repo_webhooks(self, repo):
config = { }
owner = repo.owner
url = f"{_gitsrht}/api/{owner.canonical_name}/repos/{repo.name}/webhooks"
try:
ensure_webhooks(owner, url, config)
except:
pass # nbd, upstream was presumably deleted
2020-04-23 17:32:15 +02:00
2020-04-06 19:21:13 +02:00
class HgService(SrhtService):
def __init__(self):
super().__init__()
def get_repos(self, user):
return get_results(f"{_hgsrht}/api/repos", user)
def get_repo(self, user, repo_name):
r = self.session.get(f"{_hgsrht}/api/repos/{repo_name}",
headers=get_authorization(user))
if r.status_code != 200:
raise Exception(r.text)
return r.json()
def get_readme(self, user, repo_name, repo_url):
2020-04-06 19:21:13 +02:00
# TODO: Cache?
link_prefix = repo_url + "/raw/"
for readme_name in readme_names:
r = self.session.get(f"{_hgsrht}/api/repos/{repo_name}/raw/{readme_name}",
headers=get_authorization(user))
if r.status_code == 404:
continue
elif r.status_code != 200:
raise Exception(r.text)
return format_readme(r.text, readme_name, link_prefix)
return format_readme("")
2020-04-06 19:21:13 +02:00
def create_repo(self, user, valid):
name = valid.require("name")
2020-04-30 15:59:51 +02:00
description = valid.require("description")
2020-04-06 19:21:13 +02:00
if not valid.ok:
return None
return self.post(user, valid, f"{_hgsrht}/api/repos", {
"name": name,
"description": description,
"visibility": "public", # TODO: Should this be different?
})
def delete_repo(self, user, repo_name):
r = self.session.delete(f"{_hgsrht}/api/repos/{repo_name}",
headers=get_authorization(user))
if r.status_code != 204 and r.status_code != 404:
2020-04-06 19:21:13 +02:00
raise Exception(r.text)
def ensure_user_webhooks(self, user):
config = {
origin + url_for("webhooks.hg_user", user_id=user.id):
2020-04-06 19:21:13 +02:00
["repo:update", "repo:delete"],
}
ensure_webhooks(user, f"{_hgsrht}/api/user/webhooks", config)
2020-04-23 17:32:15 +02:00
def unensure_user_webhooks(self, user):
config = { }
try:
ensure_webhooks(user, f"{_hgsrht}/api/user/webhooks", config)
except:
pass # nbd, upstream was presumably deleted
2020-04-23 17:32:15 +02:00
2020-03-31 21:08:00 +02:00
class ListService(SrhtService):
2020-03-25 15:08:29 +01:00
def get_lists(self, user):
return get_results(f"{_listsrht}/api/lists", user)
def get_list(self, user, list_name):
2020-03-31 21:08:00 +02:00
r = self.session.get(f"{_listsrht}/api/lists/{list_name}",
2020-03-25 15:08:29 +01:00
headers=get_authorization(user))
if r.status_code != 200:
raise Exception(r.json())
return r.json()
2020-04-06 22:15:52 +02:00
def ensure_mailing_list_webhooks(self, mailing_list):
2020-03-31 22:09:33 +02:00
config = {
2020-04-06 22:15:52 +02:00
origin + url_for("webhooks.mailing_list", list_id=mailing_list.id):
2020-03-31 22:09:33 +02:00
["list:update", "list:delete", "post:received", "patchset:received"],
}
2020-04-06 22:15:52 +02:00
owner = mailing_list.owner
url = f"{_listsrht}/api/user/{owner.canonical_name}/lists/{mailing_list.name}/webhooks"
ensure_webhooks(owner, url, config)
2020-03-25 15:08:29 +01:00
2020-04-23 17:32:15 +02:00
def unensure_mailing_list_webhooks(self, mailing_list):
config = { }
owner = mailing_list.owner
url = f"{_listsrht}/api/user/{owner.canonical_name}/lists/{mailing_list.name}/webhooks"
try:
ensure_webhooks(owner, url, config)
except:
pass # nbd, upstream was presumably deleted
2020-04-23 17:32:15 +02:00
2020-03-31 21:08:00 +02:00
def create_list(self, user, valid):
name = valid.require("name")
2020-04-02 00:51:14 +02:00
description = valid.optional("description")
2020-03-31 21:08:00 +02:00
if not valid.ok:
return None
return self.post(user, valid, f"{_listsrht}/api/lists", {
"name": name,
"description": description,
})
2020-04-02 00:51:14 +02:00
class TodoService(SrhtService):
def get_trackers(self, user):
return get_results(f"{_todosrht}/api/trackers", user)
def get_tracker(self, user, tracker_name):
r = self.session.get(f"{_todosrht}/api/trackers/{tracker_name}",
headers=get_authorization(user))
if r.status_code != 200:
raise Exception(r.json())
return r.json()
2020-04-02 19:41:46 +02:00
def create_tracker(self, user, valid):
name = valid.require("name")
description = valid.optional("description")
if not valid.ok:
return None
return self.post(user, valid, f"{_todosrht}/api/trackers", {
"name": name,
"description": description,
})
2020-04-02 16:26:04 +02:00
def delete_tracker(self, user, tracker_name):
r = self.session.delete(f"{_todosrht}/api/trackers/{tracker_name}",
headers=get_authorization(user))
if r.status_code != 204 and r.status_code != 404:
2020-04-02 16:26:04 +02:00
raise Exception(r.text)
2020-04-02 15:24:29 +02:00
def ensure_user_webhooks(self, user):
config = {
2020-04-06 22:15:52 +02:00
origin + url_for("webhooks.todo_user", user_id=user.id):
["tracker:update", "tracker:delete"]
2020-04-02 15:24:29 +02:00
}
url = f"{_todosrht}/api/user/webhooks"
ensure_webhooks(user, url, config)
2020-04-23 17:32:15 +02:00
def unensure_user_webhooks(self, user):
config = { }
url = f"{_todosrht}/api/user/webhooks"
try:
ensure_webhooks(user, url, config)
except:
pass # nbd, upstream was presumably deleted
2020-04-23 17:32:15 +02:00
2020-04-06 22:15:52 +02:00
def ensure_tracker_webhooks(self, tracker):
2020-04-02 00:51:14 +02:00
config = {
2020-04-06 22:15:52 +02:00
origin + url_for("webhooks.todo_tracker", tracker_id=tracker.id):
["ticket:create"]
2020-04-02 00:51:14 +02:00
}
2020-04-06 22:15:52 +02:00
owner = tracker.owner
url = f"{_todosrht}/api/user/{owner.canonical_name}/trackers/{tracker.name}/webhooks"
ensure_webhooks(owner, url, config)
2020-04-02 00:51:14 +02:00
2020-04-23 17:32:15 +02:00
def unensure_tracker_webhooks(self, tracker):
config = { }
owner = tracker.owner
url = f"{_todosrht}/api/user/{owner.canonical_name}/trackers/{tracker.name}/webhooks"
try:
ensure_webhooks(owner, url, config)
except:
pass # nbd, upstream was presumably deleted
2020-04-23 17:32:15 +02:00
2020-04-06 22:15:52 +02:00
def ensure_ticket_webhooks(self, tracker, ticket_id):
2020-04-02 00:51:14 +02:00
config = {
2020-04-06 22:15:52 +02:00
origin + url_for("webhooks.todo_ticket", tracker_id=tracker.id):
["event:create"]
2020-04-02 00:51:14 +02:00
}
2020-04-06 22:15:52 +02:00
owner = tracker.owner
url = f"{_todosrht}/api/user/{owner.canonical_name}/trackers/{tracker.name}/tickets/{ticket_id}/webhooks"
ensure_webhooks(owner, url, config)
2020-04-02 00:51:14 +02:00
2020-04-23 17:32:15 +02:00
def unensure_ticket_webhooks(self, tracker, ticket_id):
config = { }
owner = tracker.owner
url = f"{_todosrht}/api/user/{owner.canonical_name}/trackers/{tracker.name}/tickets/{ticket_id}/webhooks"
try:
ensure_webhooks(owner, url, config)
except:
pass # nbd, upstream was presumably deleted
2020-04-23 17:32:15 +02:00
2020-04-02 00:51:14 +02:00
def create_tracker(self, user, valid):
name = valid.require("name")
description = valid.optional("description")
if not valid.ok:
return None
return self.post(user, valid, f"{_todosrht}/api/trackers", {
"name": name,
"description": description,
})
2020-03-24 15:26:15 +01:00
git = GitService()
2020-04-06 19:21:13 +02:00
hg = HgService()
2020-03-25 15:08:29 +01:00
lists = ListService()
2020-04-02 00:51:14 +02:00
todo = TodoService()