diff --git a/services/arbiter-3.0/src/routes/admin/appeals.js b/services/arbiter-3.0/src/routes/admin/appeals.js new file mode 100644 index 0000000..c48b82a --- /dev/null +++ b/services/arbiter-3.0/src/routes/admin/appeals.js @@ -0,0 +1,88 @@ +const express = require('express'); +const router = express.Router(); +const db = require('../../database'); + +// Shell route +router.get('/', (req, res) => { + res.render('admin/appeals/index', { title: 'Trinity Appeals' }); +}); + +// HTMX polling endpoint +router.get('/list', async (req, res) => { + try { + const { rows: appeals } = await db.query(` + SELECT id, discord_username, email, circumstances, requested_outcome, + status, trinity_notes, actioned_by, actioned_at, created_at + FROM trinity_appeals + ORDER BY + CASE status + WHEN 'pending' THEN 1 + WHEN 'needs_info' THEN 2 + WHEN 'approved' THEN 3 + WHEN 'denied' THEN 4 + END, + created_at DESC + LIMIT 100; + `); + + const counts = { + pending: appeals.filter(a => a.status === 'pending').length, + needs_info: appeals.filter(a => a.status === 'needs_info').length, + approved: appeals.filter(a => a.status === 'approved').length, + denied: appeals.filter(a => a.status === 'denied').length, + total: appeals.length + }; + + res.render('admin/appeals/_list', { appeals, counts, layout: false }); + } catch (error) { + console.error('Appeals list error:', error); + res.status(500).send("
| ID | +Submitted | +Submitter | +Appeal | +Status | +Actions | +
|---|---|---|---|---|---|
| No appeals yet. The wall holds. | |||||
| #<%= a.id %> | +<%= new Date(a.created_at).toLocaleString() %> | +
+ <%= a.discord_username %>
+ <%= a.email %>
+ |
+
+
+
+ View details+
+
+ Circumstances:
+ <%= a.circumstances %> Requested outcome:
+ <% if (a.trinity_notes) { %>
+ <%= a.requested_outcome %>
+ Trinity notes:
+
+ <% } %>
+ <%= a.trinity_notes %> + <% if (a.actioned_by) { %> +— <%= a.actioned_by %>, <%= new Date(a.actioned_at).toLocaleString() %> + <% } %> + |
+ + <% var badge = { pending:'bg-yellow-100 text-yellow-800', needs_info:'bg-blue-100 text-blue-800', approved:'bg-green-100 text-green-800', denied:'bg-red-100 text-red-800' }[a.status]; %> + <%= a.status %> + | +
+ <% if (a.status === 'pending' || a.status === 'needs_info') { %>
+
+
+
+ <% } else { %>
+ resolved
+ <% } %>
+
+
+
+
+
+ |
+
Review ban appeals submitted via the public form
+Loading appeals...
+