Skip to content

feat(moderation): implement moderator management interface with automatic logging#379

Merged
C4ptainCrunch merged 14 commits into
DocHub-ULB:mainfrom
mnietona:feat/moderation-dashboard
Apr 27, 2026
Merged

feat(moderation): implement moderator management interface with automatic logging#379
C4ptainCrunch merged 14 commits into
DocHub-ULB:mainfrom
mnietona:feat/moderation-dashboard

Conversation

@mnietona

@mnietona mnietona commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

UPDATE (April 13, 2026): Addressed Review Feedback

Based on the latest code review, I have significantly refactored the moderation system to improve security, accountability, and code quality:

  • Security & UX Hardening:
    • Replaced raw request.POST handling with a robust Django Form (ProcessRepresentativeRequestForm).
    • Mandatory Rejection Reason: Refusing a request now strictly requires a minimum of 10 characters.
    • Added targeted Bootstrap UI feedback for errors (e.g., short reasons) to avoid silent failures.
  • Cleaner Architecture:
    • Split the monolithic management view into 3 distinct, single-responsibility views: moderators_list, moderator_add, and moderator_remove.
    • Restricted Permissions: Only System Admins (is_staff) can now remove a moderator. Simple moderators can only view the list and add new members.
    • Standardized naming conventions (e.g., process_representative_request) and switched all code comments to English.
  • Public Accountability (Transparency Logs):
    • Created a Public Transparency Ledger at /moderation/logs/ (accessible to all logged-in users via the footer).
    • Implemented full pagination (50 items/page) using Django's Paginator for long-term scalability.
    • OOP Refactoring: The ModerationLog model now uses @property methods (action_text, action_color, target_text) to act as a "translator". This ensures clean UI rendering and robust fallbacks for legacy logs.

Context

This PR is the first step of the moderation system overhaul. It focuses on creating a dedicated interface to manage moderator permissions directly from the site, moving away from the Django admin for daily operations.

Key Features

  • Moderation Hub: Created a landing page at /moderation/ to centralize all tools.
  • Public Activity Ledger: New paginated view for community accountability.
  • Semantic Tracking: Refactored logging to record human-readable actions (e.g., "Accepted request") instead of raw database field changes.
  • Security & Logic:
    • Access restricted to is_staff or is_moderator.
    • Staff Protection: Moderators cannot remove rights from "Staff/Admin" members.
    • Removal Restriction: Only Admins can demote moderators.

Screenshots (New)

1. Moderation Hub (Landing Page)
CleanShot 2026-04-13 at 21 25 35

2. Moderator Management UI
CleanShot 2026-04-13 at 21 25 44

3. Public Transparency Logs (Paginated)
CleanShot 2026-04-13 at 21 25 07

4. Targeted Error Feedback
CleanShot 2026-04-13 at 21 33 50


Manual Testing

  • New: Verified that a rejection fails if the reason is < 10 characters.
  • New: Confirmed that a simple Moderator cannot see or trigger the "Remove" action.
  • New: Verified the public logs page correctly handles pagination and displays legacy logs via fallbacks.
  • Verified that non-authorized users cannot access the Moderation Hub.
  • Tested adding a user via NetID: correctly sets is_moderator=True and creates a semantic log.
  • Checked that logs in the Django admin are human-readable and filtered from technical noise.

@mnietona

mnietona commented Apr 2, 2026

Copy link
Copy Markdown
Contributor Author

To give you more visibility on the next steps:
I'm planning to continue working on this moderation logic by:

  1. Integrating the Request System: Implementing the Accept/Reject logic for RepresentativeRequest (which is already partially in the codebase) so we can onboard new moderators directly from the site.
  2. Dashboard Logs: In a follow-up PR, I'll bring the ModerationLog activity directly onto the dashboard. This will allow moderators to monitor recent changes without needing Django Admin access.
  3. Bulk Upload Management: I'll also add a view to process the bulk upload links submitted via the form I recently fixed in fix: resolve bulk upload Turbo error with PRG pattern #377.

I'll start with the Request System integration on this branch unless you prefer I wait for this first part to be merged!

@mnietona

mnietona commented Apr 2, 2026

Copy link
Copy Markdown
Contributor Author

Important

This update is now obsolete. All the features and logic described below have been refactored and integrated into the main PR description above.

Click to see archived update details (April 2nd)### Update: Request Processing & Rejection Feedback

Following up on the moderation hub, I've just pushed the logic to handle incoming RepresentativeRequest directly from the dashboard.

What's new in this commit:

  • Dashboard Integration: Moderators can now accept or reject pending requests directly from the /moderation/ dashboard with a single click.
  • Optional Rejection Reason: When rejecting a request, moderators can now provide an optional reason.
  • Enhanced UX for Students: If a student's request is rejected, they will see a styled, framework-agnostic banner on the request page displaying the moderator's reason, prompting them to fix their info and apply again.
  • Flawless Audit Trail (Logs): Updated ModerationLog.track() to explicitly record when a request's processed status changes to True, and to log the rejection_reason. We now have full traceability on who rejected a request and why.

Screenshots

1. Dashboard with Accept/Reject & Rejection Input
CleanShot 2026-04-02 at 12 37 08

2. Student View: Custom Rejection Banner
CleanShot 2026-04-02 at 12 30 20

3. Admin Logs: Full Traceability on Rejections
CleanShot 2026-04-02 at 12 30 06

@mnietona

mnietona commented Apr 4, 2026

Copy link
Copy Markdown
Contributor Author

Hey! While waiting for the review on this PR, I kept the momentum going and prepared the next logical step: Semantic Activity Logs & UI.

To keep things clean and easy to review, I didn't add the new commits here. Instead, I stacked them in a separate PR on my fork. You can preview the upcoming code and the new clean architecture (both frontend and Django admin) right here: Semantic Activity Logs & UI

Let me know if you have any feedback on this current PR so we can merge it, and then I'll officially open the logs PR against the main repo!

Comment thread moderation/views.py Outdated
Comment thread moderation/views.py Outdated
Comment thread moderation/views.py Outdated
Comment thread moderation/views.py Outdated
Comment thread moderation/views.py Outdated
@C4ptainCrunch

Copy link
Copy Markdown
Contributor

Hello again :) Thank you for all the work and energy !

As usual, on the substance:

  • I would really prefer that the moderation log is public (to logged users) to enforce accountability: people are much less likely to deface or engage in moderation wars if their name is attached to it. Example on lobste.rs and the why
  • (optional, could be in a follow-up PR) Could we have something like the lobste.rs invite tree (see the why too ) for moderators ? (also to enforce accountability)
  • I think only admins should be able to remove a moderator
  • Could you keep the bulk documents management for a future PR, i would like to avoid this becoming too big
  • I have a few remarks on the code itself, i wrote them directly in the diff

And on the form: when you are working on a PR, could you keep it as a draft and whenever you add commits, update the description at the top ? Otherwise, i'll end up A) reviewing the code multiple times B) having to update my mental model of your PR on each comment

@C4ptainCrunch

Copy link
Copy Markdown
Contributor

I had a look at the UI by running your branch on my laptop. It looks good !
However, i see 2 bugs:

  • /moderation/representative-request is still available even when you are already a moderator. It should show a small message in the vibe of "your are already a moderator"
  • If user A, asks for moderation rights, then user B grants the rights with the other form (see screenshot), the requests stays open
image

Comment thread moderation/templates/moderation/representative_request.html
Comment thread moderation/forms.py
Comment thread moderation/urls.py Outdated
Comment thread moderation/urls.py Outdated
Comment thread moderation/views.py Outdated
Comment thread moderation/views.py Outdated
Comment thread moderation/views.py
Comment thread moderation/models.py
Comment thread moderation/admin.py
Comment thread moderation/views.py Outdated
Comment thread moderation/views.py Outdated
Comment thread moderation/views.py Outdated
Comment thread moderation/views.py Outdated
Comment thread moderation/models.py Outdated
Comment thread moderation/views.py
Comment thread moderation/models.py Outdated
Comment thread moderation/views.py Outdated
Comment thread moderation/templates/moderation/home.html Outdated
@mnietona

Copy link
Copy Markdown
Contributor Author

Thanks for the review! I've taken all your feedback into account, tested the changes, and fixed the bugs.

Here is the new proper 403 Error page:
CleanShot 2026-04-21 at 22 09 52

And here is the updated UI for the rejection reason (fixed the icon!):
CleanShot 2026-04-22 at 19 06 56

Let me know if it's good to merge!

Comment thread moderation/templates/moderation/moderators_management.html Outdated
@C4ptainCrunch

Copy link
Copy Markdown
Contributor

Awesome, thank you for all the fixes and the back and forth !
I'm going to merge this right now and deploy in a few days :)

@C4ptainCrunch C4ptainCrunch merged commit 07ee27e into DocHub-ULB:main Apr 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants