---
 todosrht/blueprints/tracker.py            | 52 ++++++++++++++-
 todosrht/templates/tracker-configure.html | 77 +++++++++++++++++++++++
 todosrht/templates/tracker.html           |  5 +-
 3 files changed, 130 insertions(+), 4 deletions(-)
 create mode 100644 todosrht/templates/tracker-configure.html

diff --git a/todosrht/blueprints/tracker.py b/todosrht/blueprints/tracker.py
index 19f9713..cef1d4e 100644
--- a/todosrht/blueprints/tracker.py
+++ b/todosrht/blueprints/tracker.py
@@ -169,10 +169,60 @@ def tracker_GET(owner, name):
         abort(404)
     return return_tracker(tracker, access)

+def parse_html_perms(short, valid):
+    result = 0
+    for sub_perm in TicketAccess:
+        new_perm = valid.optional("perm_{}_{}".format(short, sub_perm.name))
+        if new_perm:
+            result |= int(new_perm)
+    if result == 0:
+        valid.expect(result or "perm_{}_none".format(short) in valid,
+                     "{} type permissions are missing".format(short), field="tracker_{}_access".format(short))
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| 80 column limit
+    return result
+
+@tracker.route("/<owner>/<path:name>/configure", methods=["POST"])
+@loginrequired
+def tracker_configure_POST(owner, name):
+    tracker, access = get_tracker(owner, name)
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| Do you need to verify here that `access` grants the logged-in user
| permission to edit permissions? I think with this code any logged-in
| user could edit any tracker.
+    if not tracker:
+        abort(404)
+
+    valid = Validation(request)
+    perm_anon = parse_html_perms('anon', valid)
+    perm_user = parse_html_perms('user', valid)
+    perm_submit = parse_html_perms('submit', valid)
+    perm_commit = parse_html_perms('commit', valid)
+
+    desc = valid.optional("tracker_desc", default=tracker.description)
+    valid.expect(not desc or len(desc) < 4096,
+            "Must be less than 4096 characters",
+            field="tracker_desc")
+    if not valid.ok:
+        return render_template("tracker-configure.html",
+                               tracker=tracker,
+                               access_type_list=TicketAccess,
+                               **valid.kwargs), 400
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| Do not align this with the first arg. Prefer:
|
| +        return render_template("tracker-configure.html",
| +            tracker=tracker, access_type_list=TicketAccess,
| +            **valid.kwargs), 400
+
+    tracker.default_anonymous_perms = perm_anon
+    tracker.default_user_perms = perm_user
+    tracker.default_submitter_perms = perm_submit
+    tracker.default_committer_perms = perm_commit
+    tracker.description = desc
+    db.session.commit()
+
+    return redirect(url_for(".tracker_configure_GET",
+                    owner=owner, name=name))
+
+
 @tracker.route("/<owner>/<path:name>/configure")
 @loginrequired
 def tracker_configure_GET(owner, name):
-    pass
+    tracker, access = get_tracker(owner, name)
+    if not tracker:
+        abort(404)
+    return render_template("tracker-configure.html",
+                           tracker=tracker,
+                           access_type_list=TicketAccess)
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| Same alignment comment here

 @tracker.route("/<owner>/<path:name>/submit", methods=["POST"])
 @loginrequired
diff --git a/todosrht/templates/tracker-configure.html b/todosrht/templates/tracker-configure.html
new file mode 100644
index 0000000..dcbd7a9
--- /dev/null
+++ b/todosrht/templates/tracker-configure.html
@@ -0,0 +1,77 @@
+{% extends "todo.html" %}
+
+{% macro perm_checkbox(type, perms, name) %}
+  {% if type %}
+    <input class="form-check-input" type="checkbox" name="perm_{{ name }}_{{ type.name }}"{{ ' checked="checked"' if type in perms }} value="{{type.value}}"> {{type.name}}
+  {% else %}
+    <input class="form-check-input" type="checkbox" name="perm_{{ name }}_{{ type.name }}"{{ ' checked="checked"' if perms == 0 }} value="{{type.value}}"> {{type.name}}
+  {% endif %}
+{% endmacro %}
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| 80 column limit. It might also be cleaner to use str.format rather than
| try to splice these strings together with jinja.
+
+{% block title %}
+<title>Configure tracker &mdash; {{ cfg("sr.ht", "site-name") }}</title>
+{% endblock %}
+{% block content %}
+<div class="container">
+  <div class="row">
+    <div class="col-md-8">
+      <h2>Configure {{ tracker.name or "Error -- No Tracker" }}</h2>
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| What's this error about? This doesn't make sense to me.
+      <form method="POST">
+        <div class="form-group {{valid.cls("tracker_name")}}">
+          <label for="tracker_name">Name</label>
+          <input type="text" name="tracker_name" id="tracker_name" class="form-control" value="{{ tracker.name or "" }}" aria-describedby="tracker_name-help" disabled="disabled" />
+          {{ valid.summary("tracker_name") }}
+          <p id="tracker_name-help" class="form-text text-muted">Changing tracker name not yet supported.</p>
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| Don't make implicit promises about the future. Take a look at
| meta.sr.ht's profile edit page and replicate what I put in to tell users
| they can't change their username.
|
| Also, 80 col limit.
+        </div>
+        <div class="form-group {{valid.cls("tracker_desc")}}">
+          <label for="tracker_desc">Description</label>
+          <textarea name="tracker_desc" id="tracker_desc" class="form-control" value="{{ tracker_desc or "" }}" rows="5" aria-describedby="tracker_desc-help">{{tracker.desc or ""}}</textarea>
+          <p id="tracker_desc-help" class="form-text text-muted">Markdown supported</p>
+          {{ valid.summary("tracker_desc") }}
+        </div>
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| 80 cols
+        <div class="form-group {{valid.cls("tracker_any_access")}}">
+          <h3>Permissions</h3>
+          <h4>Default Anonymous Permissions</h4>
+          {% for a in access_type_list %}
+          <div class="form-check form-check-inline">
+            <label class="form-check-label">
+              {{ perm_checkbox(a, tracker.default_anonymous_perms, "anon") }}
+            </label>
+          </div>
+          {% endfor %}
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| I think this for loop can be wrapped up in another macro to de-dupe with
| the other user classes
+          {{ valid.summary("tracker_anon_access") }}
+          <h4>Default User Permissions</h4>
+          {% for a in access_type_list %}
+          <div class="form-check form-check-inline">
+            <label class="form-check-label">
+              {{ perm_checkbox(a, tracker.default_user_perms, "user") }}
+            </label>
+          </div>
+          {% endfor %}
+          {{ valid.summary("tracker_user_access") }}
+          <h4>Default Submitter Permissions</h4>
+          {% for a in access_type_list %}
+          <div class="form-check form-check-inline">
+            <label class="form-check-label">
+              {{ perm_checkbox(a, tracker.default_submitter_perms, "submit") }}
+            </label>
+          </div>
+          {% endfor %}
+          {{ valid.summary("tracker_submit_access") }}
+          <h4>Default Committer Permissions</h4>
+          {% for a in access_type_list %}
+          <div class="form-check form-check-inline">
+            <label class="form-check-label">
+              {{ perm_checkbox(a, tracker.default_committer_perms, "commit") }}
+            </label>
+          </div>
+          {% endfor %}
+          {{ valid.summary("tracker_commit_access") }}
+        </div>
+        {{ valid.summary() }}
+        <button type="submit" class="btn btn-default" name="save">Save</button>
+      </form>
+    </div>
+  </div>
+</div>
+{% endblock %}
diff --git a/todosrht/templates/tracker.html b/todosrht/templates/tracker.html
index a06ec3e..1eccaae 100644
--- a/todosrht/templates/tracker.html
+++ b/todosrht/templates/tracker.html
@@ -10,9 +10,8 @@
 <div class="container-fluid">
   <div class="row">
     <div class="col-md-12">
-      <h2>
-        {{ format_tracker_name(tracker) }}
-      </h2>
+      <h2>{{ format_tracker_name(tracker) }}</h2>
+      <a class="text-muted" href="/~{{tracker.owner.username}}/{{tracker.name}}/configure">Configure ~{{tracker.owner.username}}/{{ tracker.name }}</a>
[inline thread by Drew DeVault <sir@example.com> at Mon, 11 Jun 2018 14:10:17 -0400]
| 80 cols
     </div>
   </div>
   <div class="row">
--
2.17.0
