Skip to content

feat: comprehensive moderator system with role hierarchy, suspensions, appeals, and audit logging#17

Open
Syme-6005 wants to merge 41 commits into
mainfrom
development
Open

feat: comprehensive moderator system with role hierarchy, suspensions, appeals, and audit logging#17
Syme-6005 wants to merge 41 commits into
mainfrom
development

Conversation

@Syme-6005
Copy link
Copy Markdown
Collaborator

@Syme-6005 Syme-6005 commented May 16, 2026

Summary

Complete moderator system implementation with role-based access control, suspension management with auto-restore, appeals workflow, comprehensive audit logging, and enhanced moderation UX with search, filtering, and action templates.

Core Features Implemented

User Role & Status System

  • Added role column to users table (user, moderator, super_moderator)
  • Added status column to users table (active, suspended, banned)
  • Added suspended_until column for time-based suspension auto-restore
  • Login endpoint auto-restores expired suspensions
  • Role-based access control across all moderator endpoints

Super Moderator Role Hierarchy

  • Only super_moderators can change user roles
  • Regular moderators cannot ban/suspend other moderators
  • Privilege escalation prevented via permission checks on all actions
  • is_super_moderator() and updated is_moderator_row() helper functions

Suspension System

  • Time-based suspensions with pre-defined durations: 1, 7, 30, 60 days
  • Auto-restore logic when suspension expires (checked at login)
  • Permanent bans distinguished from temporary suspensions
  • Session revocation when user is suspended/banned
  • Custom reason support per suspension action

Audit Logging System

  • mod_actions table tracks all moderator activities
  • Logs include: suspend, ban, restore, role change with moderator/target user IDs
  • Endpoint: GET /api/mod/audit-log?limit=100&offset=0 with pagination
  • Dashboard displays audit trail with moderator username, target username, action, reason, and timestamp
  • All moderator actions automatically logged with reason and ISO timestamp

Appeal System

  • appeals table tracks suspension/ban appeals with status (pending/approved/rejected)
  • Users submit appeals: POST /api/appeals with reason
  • Moderators review appeals: GET /api/mod/appeals?status=pending
  • Moderators approve/reject: POST /api/mod/appeals/{id} with decision and response
  • Auto-restore users when appeals approved
  • Appeal decision logged to audit trail
  • Appeal UI in moderation dashboard with review modal

Search & Filtering

  • Real-time user search by email with live filtering
  • Status filters: active, suspended, banned, moderators only
  • Report search by keyword across: reason, details, reporter email, reported user email
  • "No matching X" message when filters yield no results

Moderator Dashboard Enhancements

  • Metric cards showing total users, active, suspended, banned users
  • Metric cards showing total messages, total reports
  • Pending appeals metric card with red badge notification
  • Recent reports list with search capability
  • User accounts list with search/filter
  • Audit log section showing latest moderator actions
  • Appeal queue with review interface

Action Templates & Custom Reasons

  • Pre-defined reason templates for all moderation actions:
    • Spam or repetitive content
    • Harassment or bullying
    • Inappropriate content
    • Violation of community guidelines
    • Suspicious activity
  • Template selection auto-fills reason field
  • Custom reason input available for all actions
  • Reason templates work for suspend, ban, restore, and appeals review

Security Enhancements

  • CSRF double-submit token protection on all moderation endpoints
  • All user input properly escaped with escapeHtml() to prevent XSS
  • Moderator privilege checks on role modification
  • Session revocation on account suspension/ban
  • Password verification for sensitive operations

Bug Fixes

Issue #16: Report as spam validation error ✅

  • Reduced report reason min_length from 5 to 1 character
  • Allows "spam" (4 chars) and short preset reasons
  • Resolves validation error when using report reason templates

XSS Prevention

  • All DOM manipulation uses createElement() and textContent
  • No innerHTML usage - safe DOM updates
  • User-generated content properly escaped

CSRF Protection

  • All POST endpoints require valid CSRF token
  • Proper token validation on moderator actions
  • Session management prevents unauthorized access

Database Schema

Modified Tables

  • users: Added role, status, suspended_until columns

New Tables

  • mod_actions(id, mod_id, target_id, action, reason, created_at) with indexes on mod_id, target_id, created_at
  • appeals(id, user_id, status, reason, response, created_at, reviewed_at, reviewed_by) with indexes on user_id, status

Backend Endpoints

Moderation Endpoints:

  • GET /api/mod/stats - Moderation statistics
  • GET /api/mod/reports - List reports with filtering
  • GET /api/mod/users - List users for moderation
  • POST /api/mod/users/{user_id}/status - Suspend/ban/restore user
  • POST /api/mod/users/{user_id}/role - Change user role (super_moderator only)
  • GET /api/mod/audit-log - View moderation action history
  • GET /api/mod/appeals - View pending appeals
  • POST /api/mod/appeals/{appeal_id} - Review and decide on appeal

User Endpoints:

  • POST /api/appeals - Submit suspension/ban appeal
  • GET /api/auth/me - Returns user status and role

Frontend Components

Moderation Dashboard:

  • Metric cards with statistics and notification badges
  • Recent reports list with search
  • User accounts with search/filter by email and status
  • Appeals queue with modal review interface
  • Audit log showing all moderator actions

Modals:

  • Suspension dialog with duration selector and reason templates
  • Action dialog for ban/restore with reason templates
  • Appeal submission modal for restricted users
  • Appeal review modal for moderators with decision options

UX Features:

  • Real-time filtering with live search results
  • Notification badges (red) for pending work items
  • Reason template auto-fill on selection
  • Confirmation dialogs for sensitive actions
  • Toast notifications for action feedback

Testing Checklist

  • Super moderator can change user roles
  • Regular moderators cannot modify other moderators
  • Suspension tiers work correctly (1, 7, 30, 60 days)
  • Auto-restore when suspension expires at login
  • Audit log displays all moderator actions with correct info
  • Appeal submission, review, approval, and auto-restore works
  • Notification badges update correctly
  • Report search filters by keyword
  • User search/filter works by email and status
  • Action templates pre-fill reason field
  • Report reason validation fixed (issue Report as spam is broken #16)
  • CSRF protection active on all endpoints
  • No XSS vulnerabilities in DOM manipulation
  • Session revocation on suspension/ban

https://claude.ai/code/session_01Tq7iYMZVHmyeByUxiUj2iH

Summary by CodeRabbit

  • New Features
    • Added moderator dashboard displaying statistics, reports, and user accounts
    • Moderators can now suspend, ban, or restore user accounts
    • New "Moderation" tab accessible to moderators
    • Implemented account status system (active, suspended, banned)
    • Added warning about unencrypted report submission

Review Change Stack

@Syme-6005 Syme-6005 requested a review from dbwg2009 as a code owner May 16, 2026 09:06
@github-actions github-actions Bot added area: frontend app/, components/, styles area: backend labels May 16, 2026
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented May 16, 2026

Not up to standards ⛔

🔴 Issues 8 high

Alerts:
⚠ 8 issues (≤ 0 issues of at least minor severity)

Results:
8 new issues

Category Results
ErrorProne 7 high
Security 1 high

View in Codacy

🟢 Metrics 71 complexity · 0 duplication

Metric Results
Complexity 71
Duplication 0

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Adds role and status fields to users, enforces active and moderator checks in auth and API flows, adds moderator APIs and UI, deletes sessions on ban/suspend, and resets message decryption state when entering threads.

Changes

Moderator System and Message Handling Enhancements

Layer / File(s) Summary
Database Schema and Configuration
backend/main.py
Adds CIPHER_MODERATOR_EMAILS parsing into MODERATOR_EMAILS, START_TIME, extends users with role (default user) and status (default active), and updates migrations to add these columns when missing.
Authentication Flows with Role and Status
backend/main.py
current_user reads role/status and treats status == "banned" as unauthenticated; registration assigns role from MODERATOR_EMAILS and sets status=active; login checks status and rejects banned users (403); /api/auth/me includes role, status, and isModerator.
Authorization Dependencies
backend/main.py
Adds require_active_user (CSRF + blocks non-active accounts) and require_moderator (requires active account and moderator access) and defines ModUserActionIn.
Message and Group Endpoint Access Control
backend/main.py
Message endpoints (send, mark_read, delete) and group endpoints (join, leave, message_send, message_delete, messages_list) now use require_active_user instead of prior generic auth dependency.
Moderator Management API
backend/main.py
Adds moderator-only routes: /api/mod/stats, /api/mod/reports, /api/mod/users, /api/mod/users/{user_id}/status. Actions map to active/suspended/banned; sessions for suspended/banned users are deleted; moderators cannot modify other moderators.
Moderation UI Structure
static/index.html
Adds hidden Moderation tab and moderation view with metrics, recent reports, and user account controls; updates the report modal hint stating reports are passed to moderators unencrypted.
Frontend Moderation Controls and Routing
static/js/app.js
Adds updateModeratorTab() and loadModeration() (fetches stats/reports/users, renders lists, wires suspend/ban/restore actions with confirmation and POST), calls updateModeratorTab() after user load and at boot, and adds "moderation" to the route allowlist.
Message Thread Decryption State Management
static/js/app.js
Opening DM/group threads now passes resetDecryption = true to loadDmMessages/loadGroupMessages, which reset state.messagesDecrypted before decrypt/render when flagged.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AuthServer as /api/auth
  participant ModServer as /api/mod
  participant Database as SQLite

  rect rgba(100, 150, 200, 0.5)
    Client->>AuthServer: POST /register (email, password)
    AuthServer->>AuthServer: parse CIPHER_MODERATOR_EMAILS -> MODERATOR_EMAILS
    AuthServer->>Database: INSERT users (role, status=active)
    Database-->>AuthServer: OK
  end

  rect rgba(200, 150, 100, 0.5)
    Client->>AuthServer: POST /login (email, password)
    AuthServer->>Database: SELECT status FROM users WHERE email
    alt status == banned
      AuthServer-->>Client: 403 Forbidden
    else
      AuthServer-->>Client: JWT token
    end
  end

  rect rgba(150, 200, 100, 0.5)
    Client->>ModServer: POST /mod/users/{id}/status (action=ban)
    ModServer->>Database: UPDATE users SET status = banned
    ModServer->>Database: DELETE FROM sessions WHERE user_id = id
    Database-->>ModServer: OK
    ModServer-->>Client: updated user
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • dbwg2009/XorCrypt#13: Overlaps in static/js/app.js around thread entry and state.messagesDecrypted handling.

Suggested labels

enhancement, bug

Suggested reviewers

  • dbwg2009

Poem

🐰 I hopped in to add a moderator light,
Roles and statuses to guard the night.
Ban, suspend, restore with a button and cheer,
Threads decrypt fresh when a rabbit is near.
Moderation blooms — hop to it, my dear!

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The PR title promises comprehensive moderator system features (role hierarchy, suspensions, appeals, audit logging) not present in the actual changeset. Update the title to match the implemented changes: 'feat: add basic moderator system with role-based access control and status management' or similar.
Description check ⚠️ Warning The PR description is overly ambitious and describes many features (appeals system, audit logging, search/filtering, action templates, CSRF protection, role hierarchy) not implemented in this changeset. Rewrite the description to accurately reflect only the features implemented in this PR: role/status columns, moderator detection, basic mod endpoints, and frontend moderation tab.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch development

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@codacy-production codacy-production Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

The PR introduces a moderation system but contains critical security regressions and logic oversights that prevent it from being production-ready. Most notably, the introduction of new authentication dependencies has inadvertently removed CSRF protection from several sensitive backend endpoints, and the new moderation dashboard is vulnerable to Cross-Site Scripting (XSS) due to unsafe HTML rendering. Additionally, Codacy has flagged the PR as not up to standards, specifically noting high complexity in 'backend/main.py' which lacks any accompanying test coverage. These security flaws and the lack of automated validation for critical authorization paths must be addressed before merging.

About this PR

  • Systemic Security Issue: The replacement of 'auth_dep' with status-specific dependencies has systematically removed CSRF protection from multiple POST and DELETE endpoints. A global fix is required to ensure all protected routes maintain CSRF validation.
  • Missing Tests: The PR contains significant logic for account banning and access control but lacks new unit or integration tests to verify these critical security paths.
1 comment outside of the diff
backend/main.py

line 1127 🟡 MEDIUM RISK
Suspended users can still retrieve group messages. Use require_active_user to enforce the suspension.\n\nsuggestion\ndef group_messages_list(group_id: int, limit: int = 200, user = Depends(require_active_user)):\n

Test suggestions

  • Verify that a user listed in CIPHER_MODERATOR_EMAILS is assigned the 'moderator' role upon registration.\n- [x] Verify that a 'banned' user is immediately rejected by current_user even if they have an active session cookie.\n- [x] Verify that a 'suspended' user is blocked from sending messages by the require_active_user guard.\n- [x] Verify that the moderator dashboard tab is hidden for standard users and visible for moderators.\n- [ ] Verify CSRF protection on new moderator POST endpoints (e.g., /api/mod/users/{user_id}/status).\n- [x] Verify that message decryption state is reset when switching from one DM thread to another.\n- [ ] Add unit tests for the complex authorization logic in backend/main.py to address coverage gaps.
Low confidence findings
  • Consistency gap: While 'require_active_user' protects endpoints, suspended users can still appear authenticated in UI components that only use 'require_user'. Consider standardizing the check across all authentication-dependent UI elements.

TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback

Comment thread static/js/app.js Outdated
if (reports.length === 0) {
reportsList.innerHTML = `<div class="empty"><p>No recent reports.</p></div>`;
} else {
reportsList.innerHTML = reports.map(r => `
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 HIGH RISK

Avoid assigning dynamic HTML strings to innerHTML. This pattern is susceptible to Cross-Site Scripting (XSS) attacks. Properties like messageId and groupMessageId are concatenated without sanitization. For a safer implementation, use document.createElement and textContent.

Comment thread backend/main.py Outdated
return user


def require_active_user(user = Depends(require_user)):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 HIGH RISK

Security regression: by replacing 'auth_dep' with 'require_active_user', CSRF protection has been removed from multiple sensitive endpoints including message_send and group_join. This dependency must include a CSRF check.

Comment thread backend/main.py Outdated
return user


def require_moderator(user = Depends(require_user)):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 HIGH RISK

This dependency lacks CSRF protection, representing a security regression. Moderator actions are vulnerable to CSRF because this dependency does not perform CSRF token validation. It should incorporate 'require_csrf' or depend on 'auth_dep'.\n\nsuggestion\ndef require_moderator(user = Depends(auth_dep)):\n

Comment thread backend/main.py


@app.post("/api/mod/users/{user_id}/status")
def mod_user_status(user_id: int, body: ModUserActionIn, user = Depends(require_moderator)):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

Moderators can currently ban other moderators or admins. This endpoint should verify that the target user is not a moderator before applying a status change. Given the complexity of this file and lack of test coverage, this logic gap is high risk.\n\nTry running the following prompt in your coding agent:\n> In backend/main.py, update the mod_user_status function to check if the target user_id belongs to a moderator (by fetching their role and checking if their email is in MODERATOR_EMAILS) and raise an HTTPException(403) if a moderator attempts to modify another moderator's account.

Comment thread backend/main.py Outdated
if not target:
raise HTTPException(404, "User not found")
conn.execute("UPDATE users SET status = ? WHERE id = ?", (status, user_id))
if status == "banned":
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

Suggestion: Sessions should be revoked for suspended users as well to ensure they are immediately blocked from the system.\n\nsuggestion\n if status in ("banned", "suspended"):\n

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/main.py`:
- Around line 386-395: The guards must be chained so CSRF and active-account
checks run for mutating/moderator routes: change require_active_user to take its
user via Depends(require_csrf) instead of Depends(require_user), and change
require_moderator to take its user via Depends(require_active_user) (so
moderator checks automatically include CSRF + active status); update the
parameter defaults/signatures for require_active_user and require_moderator
accordingly and keep the same error behavior.

In `@static/js/app.js`:
- Around line 786-788: The toast uses a naive template `${action}ed` which
yields incorrect past-tense strings; update the success message after
api.post(`/api/mod/users/${userId}/status`, { action }) to use an explicit
mapping or switch on the action (e.g., map 'ban'->'banned',
'restore'->'restored') and pass the mapped past-tense label into toast instead
of `${action}ed`, then call loadModeration() as before.
- Around line 247-250: The boot path sets state.user directly but doesn't
refresh UI; ensure the moderator tab is synced whenever state.user is assigned
on startup by calling updateModeratorTab() from the boot() flow (the same way
loadUser() does) or by extracting the state.user assignment into a helper that
sets state.user and then calls updateModeratorTab(); update references in
boot(), loadUser(), and any existing-session logic so updateModeratorTab() runs
after state.user is populated.
- Around line 738-792: The loadModeration function and the per-user click
handler (the addEventListener on elements found via usersList.querySelectorAll)
call api.get and api.post without try/catch; wrap the API calls in try/catch
blocks (both the initial await api.get("/api/mod/stats"), the reports/users
fetches, and the await api.post(`/api/mod/users/${userId}/status`)) and on error
show a user-visible error (e.g., toast with the error message), avoid leaving
the UI half-rendered by ensuring fallback content is set for
reportsList/usersList and by re-enabling or leaving buttons intact; also catch
errors around the confirmDialog/api.post in the per-user handler so failures
don’t produce unhandled rejections and call loadModeration() only after a
successful post.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c4ab34c8-6c17-4fff-aae6-3ff608a5eea8

📥 Commits

Reviewing files that changed from the base of the PR and between fe21c4f and 49e3e02.

📒 Files selected for processing (3)
  • backend/main.py
  • static/index.html
  • static/js/app.js

Comment thread backend/main.py Outdated
Comment thread static/js/app.js
Comment thread static/js/app.js
Comment thread static/js/app.js Outdated
- Replace unsafe innerHTML assignments with safe DOM manipulation (createElement, appendChild, textContent)
- Fix moderation reports list rendering (line 748-785)
- Fix moderation users list rendering (line 787-843)
- Add try-catch error handling to loadModeration() function
- Add error handling to async user action event listeners
- Use textContent for user-controlled data instead of innerHTML templates

Fixes XSS issues reported in static/js/app.js related to reports and users lists
@dbwg2009
Copy link
Copy Markdown
Owner

@Syme-6005 will you fix the security issues or shall i?

@Syme-6005
Copy link
Copy Markdown
Collaborator Author

you please, im busy

- Replace unsafe innerHTML assignments with replaceChildren()
- Use textContent instead of innerHTML for error messages
- Eliminate unencoded HTML in error display
- Improve XSS vulnerability prevention
@Syme-6005
Copy link
Copy Markdown
Collaborator Author

nevermind i guess

@Syme-6005 Syme-6005 closed this May 16, 2026
@Syme-6005 Syme-6005 reopened this May 16, 2026
Syme-6005 added 2 commits May 16, 2026 17:08
…e checks, and session revocation

- Fix CSRF protection in require_active_user and require_moderator dependencies
- Add moderator privilege escalation prevention in mod_user_status
- Extend session revocation to suspended users (not just banned)
- Sync moderator tab visibility on boot() for existing sessions
- Fix toast message grammar for account actions (ban->banned, suspend->suspended, restore->restored)
- Prevent suspended users from accessing group messages by using require_active_user
@Syme-6005
Copy link
Copy Markdown
Collaborator Author

@dbwg2009 i cant fix it. ngl idk what the code space copilot is up to but its hallucinating and says it fixes the errors and then the smae errors come up. soooooo

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
backend/main.py (1)

1559-1564: ⚠️ Potential issue | 🟠 Major

Use the stored role when protecting moderator accounts.

This still only checks target["email"] against MODERATOR_EMAILS. Any account already persisted with role = "moderator" but no longer present in the env list is still treated as a moderator by is_moderator_row(), yet this endpoint will let another moderator change its status. Fetch role here and reuse the same moderator predicate before applying any status change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/main.py` around lines 1559 - 1564, The endpoint fetches only id/email
into target but then uses MODERATOR_EMAILS to protect moderators; change the
query to also select role (e.g., SELECT id, email, role FROM users), and replace
the email-based check with the existing moderator predicate (call
is_moderator_row(target) or the same logic that checks role/email) before
applying status changes; if the predicate is true and status != "active" raise
HTTPException(403, "Cannot modify moderator accounts") so persisted moderator
rows remain protected even if their email is not in MODERATOR_EMAILS.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/main.py`:
- Around line 355-356: The session validation currently only blocks "banned"
users so suspended accounts can re-authenticate; update the checks in the
session lookup (the if that inspects row["sess_exp"] and row["status"]) to also
treat "suspended" as invalid, and add the same status check to the login() flow
so authentication is refused for users with status == "suspended"; also ensure
require_user()/current_user() uses the user's status (not just session
existence) to deny access for suspended accounts and keep the same behavior
where suspension deletes sessions so re-login is impossible.

---

Duplicate comments:
In `@backend/main.py`:
- Around line 1559-1564: The endpoint fetches only id/email into target but then
uses MODERATOR_EMAILS to protect moderators; change the query to also select
role (e.g., SELECT id, email, role FROM users), and replace the email-based
check with the existing moderator predicate (call is_moderator_row(target) or
the same logic that checks role/email) before applying status changes; if the
predicate is true and status != "active" raise HTTPException(403, "Cannot modify
moderator accounts") so persisted moderator rows remain protected even if their
email is not in MODERATOR_EMAILS.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 19c01256-66dd-4285-9028-d69db4512977

📥 Commits

Reviewing files that changed from the base of the PR and between 6777f1d and 99cb067.

📒 Files selected for processing (2)
  • backend/main.py
  • static/js/app.js

Comment thread backend/main.py
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
static/js/app.js (1)

738-748: 💤 Low value

Consider parallelizing the three API calls for faster load.

The stats, reports, and users fetches are independent and could run concurrently. This would reduce total load time from ~3 sequential round-trips to ~1.

♻️ Suggested parallel fetch pattern
 async function loadModeration() {
   try {
-    const stats = await api.get("/api/mod/stats");
+    const [stats, reports, users] = await Promise.all([
+      api.get("/api/mod/stats"),
+      api.get("/api/mod/reports?limit=100"),
+      api.get("/api/mod/users?limit=200"),
+    ]);
+
     $("mod-total-users").textContent = stats.totalUsers;
     $("mod-active-users").textContent = stats.activeUsers;
     $("mod-suspended-users").textContent = stats.suspendedUsers;
     $("mod-banned-users").textContent = stats.bannedUsers;
     $("mod-total-messages").textContent = stats.totalMessages;
     $("mod-total-reports").textContent = stats.totalReports;

-    const reports = await api.get("/api/mod/reports?limit=100");
   const reportsList = $("mod-reports-list");
   // ... rest of reports rendering ...

-  const users = await api.get("/api/mod/users?limit=200");
   const usersList = $("mod-users-list");
   // ... rest of users rendering ...
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@static/js/app.js` around lines 738 - 748, The loadModeration function
currently awaits the three independent API calls sequentially; change it to
fetch stats, reports and users in parallel using Promise.all so the three
api.get calls (for "/api/mod/stats", "/api/mod/reports?limit=100", and the users
endpoint you use elsewhere, e.g., "/api/mod/users?limit=100") run concurrently,
then destructure the results into stats, reports and users variables and update
the DOM nodes ("mod-total-users", "mod-active-users", etc. and report/user
rendering code) from those results; keep the existing try/catch and error
handling around the Promise.all to preserve failure behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/main.py`:
- Around line 1559-1564: The current moderator-protection only fetches email and
checks MODERATOR_EMAILS, which is inconsistent with is_moderator_row (which also
checks role == "moderator"); update the SELECT to also fetch the role (e.g.,
"SELECT id, email, role FROM users WHERE id = ?") and then use the same helper
logic as is_moderator_row (or reproduce its condition) to decide whether to
block status changes — replace the email-only check with a call to
is_moderator_row(target) or equivalent (checking role == "moderator" OR email in
MODERATOR_EMAILS) in the handler that raises HTTPException(403).

---

Nitpick comments:
In `@static/js/app.js`:
- Around line 738-748: The loadModeration function currently awaits the three
independent API calls sequentially; change it to fetch stats, reports and users
in parallel using Promise.all so the three api.get calls (for "/api/mod/stats",
"/api/mod/reports?limit=100", and the users endpoint you use elsewhere, e.g.,
"/api/mod/users?limit=100") run concurrently, then destructure the results into
stats, reports and users variables and update the DOM nodes ("mod-total-users",
"mod-active-users", etc. and report/user rendering code) from those results;
keep the existing try/catch and error handling around the Promise.all to
preserve failure behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6e6b6945-6027-4a37-aeef-5f562142e489

📥 Commits

Reviewing files that changed from the base of the PR and between 99cb067 and 8168d92.

📒 Files selected for processing (2)
  • backend/main.py
  • static/js/app.js

Comment thread backend/main.py Outdated
@dbwg2009
Copy link
Copy Markdown
Owner

@Syme-6005 sorry, ive been bogged down. fixing now

- New super_moderator role with higher privileges than moderators
- Regular moderators cannot ban/suspend other moderators
- Suspension system with duration (1-365 days) and auto-restore on expiry
- Added suspended_until column with migration
- Fixed suspended user login blocking
- New /api/mod/users/{id}/role endpoint for role management
- Complete HTML injection audit: all user data properly escaped
- Improved role-based access controls throughout

Fixes privilege escalation where moderators could ban each other.
@github-actions github-actions Bot added the enhancement New feature or request label May 18, 2026
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 18, 2026
Copy link
Copy Markdown
Owner

dbwg2009 commented May 18, 2026

Moderator System Enhancements - TODO

  • Pass messages along to mods with a warning displayed to user
  • Add reason for being banned/suspended with remaining suspension time (if applicable) to login page, plus appeal button
  • Implement appeal portal for restricted users
  • Add mod actions display in reports section
  • Enable ban/suspend capability directly in reports section
  • Add ability to close/delete reports
  • Remove reason field from restore button action
  • Enable super mods to add/remove moderators in the UI
  • Fully redesign and flesh out mod dashboard
  • Fix exit mod button functionality
  • Improve visual design of mod mode and exit mod buttons ("cooler" styling)

Generated by Claude Code

@dbwg2009
Copy link
Copy Markdown
Owner

@Syme-6005 I've fixed a lot of errors and added some things. tested it and it works all ok. just need to complete the to-do list

@Syme-6005
Copy link
Copy Markdown
Collaborator Author

@Syme-6005 I've fixed a lot of errors and added some things. tested it and it works all ok. just need to complete the to-do list

ngl i made my own in the meantime https://xorcrypt-6005.web.app/

@dbwg2009
Copy link
Copy Markdown
Owner

@Syme-6005 I've fixed a lot of errors and added some things. tested it and it works all ok. just need to complete the to-do list

ngl i made my own in the meantime https://xorcrypt-6005.web.app/

@Syme-6005 looks good! I'm almost done with the mods features on this

claude added 3 commits May 19, 2026 20:57
…stead

Restore now has its own flow with a simple prompt for restoration reason, helping other mods understand the context without the formal dialog format of ban actions.
Add a dedicated restore dialog with three preset reasons:
- Appeal approved
- Manual review - no violation found
- Mistaken suspension

Reason is now required for restore actions to help other mods understand context.
- Add warning message explaining message will be decrypted and sent unencrypted to mods
- Show preview of message being reported in report dialog
- Add confirmation dialog before submitting report
- Decrypt message using user's key and send decrypted content with report
- Store message_content in reports table
- Display message content in mod reports view
- Add migration for message_content column
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 19, 2026
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented May 19, 2026

Not up to standards ⛔

🔴 Issues 10 high

Alerts:
⚠ 10 issues (≤ 0 issues of at least minor severity)

Results:
10 new issues

Category Results
ErrorProne 9 high
Security 1 high

View in Codacy

🟢 Metrics 82 complexity · 0 duplication

Metric Results
Complexity 82
Duplication 0

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

- Item 1: Message decryption for reports ✅
- Item 7: Restore dialog with preset reasons ✅

https://claude.ai/code/session_01Tq7iYMZVHmyeByUxiUj2iH
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 19, 2026
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 19, 2026
- Add AppealSubmitIn model with appeal_type, email confirmation, min 50 char reason
- Add appeal_type column migration and endpoint support
- Add GET /api/appeals/status endpoint for users to check appeal status
- Modify POST /api/appeals to validate email and accept appeal_type
- Update login endpoint to return restriction info (banned/suspended) instead of throwing errors
- Return timeRemaining for suspended accounts to display on suspension screen
- Support auto-restore on appeal approval

https://claude.ai/code/session_01Tq7iYMZVHmyeByUxiUj2iH
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 19, 2026
- Add suspension screen (replaces login when user is banned/suspended)
- Show suspension time remaining with readable format
- Add appeal form page with:
  - Appeal type dropdown (mistaken, violated by mistake, circumstances changed)
  - Email confirmation field
  - Reason textarea (min 50 char, max 2000)
  - Character count display
- Handle appeal submission and show success screen
- Route to /appeal from suspension screen
- Update login flow to detect restrictions and show suspension screen

https://claude.ai/code/session_01Tq7iYMZVHmyeByUxiUj2iH
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 19, 2026
The suspension and appeal views weren't being toggled by setView(),
causing blank screen when user is suspended. Now properly shows
suspension screen with appeal option.

https://claude.ai/code/session_01Tq7iYMZVHmyeByUxiUj2iH
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: backend area: docs Markdown, design docs, README area: frontend app/, components/, styles enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants