mirror of https://git.sr.ht/~sircmpwn/hub.sr.ht
Stub out todo.sr.ht support
This commit is contained in:
parent
43d493f8ba
commit
b98a88e47f
|
@ -15,6 +15,7 @@ class HubApp(SrhtFlask):
|
|||
from hubsrht.blueprints.projects import projects
|
||||
from hubsrht.blueprints.public import public
|
||||
from hubsrht.blueprints.sources import sources
|
||||
from hubsrht.blueprints.trackers import trackers
|
||||
from hubsrht.blueprints.users import users
|
||||
from hubsrht.blueprints.webhooks import webhooks
|
||||
|
||||
|
@ -22,6 +23,7 @@ class HubApp(SrhtFlask):
|
|||
self.register_blueprint(projects)
|
||||
self.register_blueprint(public)
|
||||
self.register_blueprint(sources)
|
||||
self.register_blueprint(trackers)
|
||||
self.register_blueprint(users)
|
||||
self.register_blueprint(webhooks)
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
from flask import Blueprint, render_template, request, redirect, url_for
|
||||
from hubsrht.projects import ProjectAccess, get_project
|
||||
from hubsrht.services import todo
|
||||
from hubsrht.types import Event, EventType, Tracker
|
||||
from srht.database import db
|
||||
from srht.flask import paginate_query
|
||||
from srht.oauth import loginrequired
|
||||
from srht.search import search_by
|
||||
from srht.validation import Validation
|
||||
|
||||
trackers = Blueprint("trackers", __name__)
|
||||
|
||||
@trackers.route("/<owner>/<project_name>/trackers/new")
|
||||
@loginrequired
|
||||
def new_GET(owner, project_name):
|
||||
owner, project = get_project(owner, project_name, ProjectAccess.write)
|
||||
# TODO: Pagination
|
||||
trackers = todo.get_trackers(owner)
|
||||
trackers = sorted(trackers, key=lambda r: r["updated"], reverse=True)
|
||||
return render_template("tracker-new.html", view="new-resource",
|
||||
owner=owner, project=project, trackers=trackers)
|
|
@ -6,6 +6,7 @@ from srht.config import get_origin
|
|||
|
||||
_gitsrht = get_origin("git.sr.ht", external=True, default=None)
|
||||
_listsrht = get_origin("lists.sr.ht", external=True, default=None)
|
||||
_todosrht = get_origin("todo.sr.ht", external=True, default=None)
|
||||
origin = get_origin("hub.sr.ht")
|
||||
|
||||
class SrhtService(ABC):
|
||||
|
@ -51,7 +52,7 @@ class GitService(SrhtService):
|
|||
|
||||
def create_repo(self, user, valid):
|
||||
name = valid.require("name")
|
||||
description = valid.require("description")
|
||||
description = valid.optional("description")
|
||||
if not valid.ok:
|
||||
return None
|
||||
return self.post(user, valid, f"{_gitsrht}/api/repos", {
|
||||
|
@ -101,8 +102,7 @@ class ListService(SrhtService):
|
|||
|
||||
def create_list(self, user, valid):
|
||||
name = valid.require("name")
|
||||
description = valid.require("description")
|
||||
print(name, description)
|
||||
description = valid.optional("description")
|
||||
if not valid.ok:
|
||||
return None
|
||||
return self.post(user, valid, f"{_listsrht}/api/lists", {
|
||||
|
@ -110,5 +110,41 @@ class ListService(SrhtService):
|
|||
"description": description,
|
||||
})
|
||||
|
||||
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()
|
||||
|
||||
def ensure_tracker_webhooks(self, user, tracker_name):
|
||||
config = {
|
||||
origin + url_for("webhooks.tracker"): ["ticket:create"]
|
||||
}
|
||||
url = f"{_todosrht}/api/user/{user.canonical_name}/trackers/{tracker_name}/webhooks"
|
||||
ensure_webhooks(user, url, config)
|
||||
|
||||
def ensure_ticket_webhooks(self, user, tracker_name, ticket_id):
|
||||
config = {
|
||||
origin + url_for("webhooks.tracker_ticket"): ["event:create"]
|
||||
}
|
||||
url = f"{_todosrht}/api/user/{user.canonical_name}/trackers/{tracker_name}/tickets/{ticket_id}/webhooks"
|
||||
ensure_webhooks(user, url, config)
|
||||
|
||||
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,
|
||||
})
|
||||
|
||||
git = GitService()
|
||||
lists = ListService()
|
||||
todo = TodoService()
|
||||
|
|
|
@ -84,16 +84,17 @@
|
|||
value="{{ name or project.name }}" />
|
||||
{{ valid.summary("name") }}
|
||||
<div class="form-group">
|
||||
<label for="list_description">Description</label>
|
||||
<label for="description">Description</label>
|
||||
<textarea
|
||||
type="text"
|
||||
name="description"
|
||||
id="description"
|
||||
class="form-control {{valid.cls("description")}}"
|
||||
rows="5"
|
||||
aria-describedby="descriptionHelpText"
|
||||
>{{ description or project.description }}</textarea>
|
||||
<small id="descriptionHelpText" class="form-text text-muted pull-left">
|
||||
aria-describedby="description-help-text"
|
||||
placeholder="Introduce this mailing list to users and explain the posting rules."
|
||||
>{{ description or "" }}</textarea>
|
||||
<small id="description-help-text" class="form-text text-muted pull-left">
|
||||
Markdown supported
|
||||
</small>
|
||||
{{valid.summary("description")}}
|
||||
|
|
|
@ -58,7 +58,10 @@
|
|||
</li>
|
||||
<li>
|
||||
{{icon('plus-square', cls='text-info')}}
|
||||
<a href="#">Add bug trackers {{icon('arrow-right')}}</a>
|
||||
<a
|
||||
href="{{url_for("trackers.new_GET",
|
||||
owner=owner.canonical_name, project_name=project.name)}}"
|
||||
>Add bug trackers {{icon('arrow-right')}}</a>
|
||||
<br />
|
||||
<small class="text-muted">
|
||||
Bug trackers give you a place to organize your tasks and record
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
{% extends "resource-new.html" %}
|
||||
{% block content %}
|
||||
<form method="POST">
|
||||
{{csrf_token()}}
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<h3 style="margin-top: 1rem">
|
||||
Create a new ticket tracker
|
||||
</h3>
|
||||
<div class="form-group">
|
||||
<label for="{{ typename }}">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
class="form-control {{ valid.cls("name") }}"
|
||||
value="{{ name or project.name }}" />
|
||||
{{ valid.summary("name") }}
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<textarea
|
||||
type="text"
|
||||
name="description"
|
||||
id="description"
|
||||
class="form-control {{valid.cls("description")}}"
|
||||
rows="5"
|
||||
aria-describedby="description-help-text"
|
||||
placeholder="Give users an idea of how to submit a good ticket for this tracker."
|
||||
>{{ description or "" }}</textarea>
|
||||
<small id="description-help-text" class="form-text text-muted pull-left">
|
||||
Markdown supported
|
||||
</small>
|
||||
{{valid.summary("description")}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1 d-flex flex-row justify-content-end">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary align-self-end"
|
||||
name="create"
|
||||
>Create new tracker {{icon("caret-right")}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if any(trackers) %}
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<h3 style="margin-top: 1rem">
|
||||
Or add an existing tracker
|
||||
</h3>
|
||||
{# TODO: Pagination #}
|
||||
<div class="form-group">
|
||||
{# TODO: How exactly should this work #}
|
||||
<input
|
||||
name="search"
|
||||
type="text"
|
||||
placeholder="Search your ticket trackers"
|
||||
class="form-control"
|
||||
value="{{ search if search else "" }}" />
|
||||
</div>
|
||||
<div class="event-list select-resource">
|
||||
{% for tracker in trackers %}
|
||||
<div class="event">
|
||||
<h3>
|
||||
<button
|
||||
type="submit"
|
||||
name="existing-{{ tracker["name"] }}"
|
||||
class="pull-right btn btn-primary btn-lg"
|
||||
>Select tracker {{ icon("caret-right") }}</button>
|
||||
<a
|
||||
href="{{get_origin("todo.sr.ht",
|
||||
external=True)}}/{{ tracker["owner"]["canonical_name"] }}/{{tracker["name"]}}"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>{{ tracker["name"] }}</a>
|
||||
</h3>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -11,6 +11,7 @@ class Visibility(Enum):
|
|||
private = "private"
|
||||
|
||||
from hubsrht.types.event import Event, EventType
|
||||
from hubsrht.types.mailinglist import MailingList
|
||||
from hubsrht.types.project import Project
|
||||
from hubsrht.types.sourcerepo import SourceRepo, RepoType
|
||||
from hubsrht.types.mailinglist import MailingList
|
||||
from hubsrht.types.tracker import Tracker
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import sqlalchemy as sa
|
||||
from srht.config import get_origin
|
||||
from srht.database import Base
|
||||
|
||||
_todosrht = get_origin("todo.sr.ht", external=True, default=None)
|
||||
|
||||
class Tracker(Base):
|
||||
__tablename__ = "tracker"
|
||||
id = sa.Column(sa.Integer, primary_key=True)
|
||||
remote_id = sa.Column(sa.Integer, nullable=False)
|
||||
created = sa.Column(sa.DateTime, nullable=False)
|
||||
updated = sa.Column(sa.DateTime, nullable=False)
|
||||
|
||||
project_id = sa.Column(sa.Integer,
|
||||
sa.ForeignKey("project.id"), nullable=False)
|
||||
project = sa.orm.relationship("Project",
|
||||
backref=sa.orm.backref("trackers"),
|
||||
foreign_keys=[project_id])
|
||||
|
||||
# Note: in theory this may eventually be different from the project owner(?)
|
||||
owner_id = sa.Column(sa.Integer,
|
||||
sa.ForeignKey("user.id"), nullable=False)
|
||||
owner = sa.orm.relationship("User")
|
||||
|
||||
name = sa.Column(sa.Unicode(128), nullable=False)
|
||||
description = sa.Column(sa.Unicode(512), nullable=False)
|
||||
|
||||
def url(self):
|
||||
return f"{_todosrht}/{self.owner.canonical_name}/{self.name}"
|
Loading…
Reference in New Issue