Skip to content

feat: add MODERATOR role for delegated moderation#74

Merged
Egor051 merged 3 commits into
mainfrom
claude/add-moderator-role-4NC6H
May 21, 2026
Merged

feat: add MODERATOR role for delegated moderation#74
Egor051 merged 3 commits into
mainfrom
claude/add-moderator-role-4NC6H

Conversation

@Egor051
Copy link
Copy Markdown
Owner

@Egor051 Egor051 commented May 20, 2026

Summary

  • Adds a new MODERATOR role between APPROVED_USER and SUPERADMIN, solving the problem of having no intermediate delegation option
  • Moderators can approve/reject access requests and block/unblock regular users
  • Moderators cannot assign roles, delete others' keys, view the audit log, or send announcements
  • SUPERADMINs can assign/revoke the moderator role via a new button in the user card

Changes

Model layer

  • models/enums.py: UserRole.MODERATOR = "MODERATOR"
  • db/schema.sql: users.role CHECK constraint updated for fresh installs
  • db/database.py: migration v17 recreates users table with expanded CHECK constraint; _validate_enum_values updated

Service layer

  • services/users.py: new require_moderator_or_admin(); require_approved_or_admin now accepts MODERATOR (so moderators can use their own VPN keys); block/unblock/approve/reject/list methods now accept MODERATOR; block_user prevents a moderator from blocking another moderator
  • services/access_approval.py: approve, reject, list_pending, get_request now accept MODERATOR

Bot layer

  • bot/guards.py: exports require_moderator_or_admin
  • bot/keyboards/admin.py: moderator_panel_keyboard() (requests + users only); user_actions_keyboard gains actor_role param — hides admin-only actions for moderators, shows "Назначить/Снять модератора" toggle for superadmins
  • bot/handlers/admin.py: /moderator command and admin:moderator_panel callback; admin:setmoderator:{id} toggle handler (SUPERADMIN only via set_role); block/unblock/request handlers updated to accept moderators and pass actor_role to keyboards

Test plan

  • Assign MODERATOR role: as SUPERADMIN, open user card → "Назначить модератором" button appears for APPROVED_USER; click it
  • As MODERATOR: /moderator shows panel with only "Заявки на доступ" and "Пользователи"
  • As MODERATOR: approve/reject a pending access request works and sends user notification
  • As MODERATOR: block a regular user (APPROVED_USER/PENDING_USER) works; unblock works
  • As MODERATOR: attempt to block another MODERATOR → error "Модератор не может заблокировать другого модератора"
  • As MODERATOR: /admin → AccessDenied; audit log callback → AccessDenied; announce callback → AccessDenied
  • As MODERATOR: own VPN keys work (regular user features unaffected)
  • Revoke moderator role: as SUPERADMIN, open MODERATOR user card → "Снять роль модератора" → user becomes APPROVED_USER
  • Fresh DB: python init_db.py bootstraps with MODERATOR in CHECK constraint
  • Existing DB: app startup runs migration v17, schema_version becomes 17

https://claude.ai/code/session_01LVGnWPcQ82ZnFS1D2JcULd


Generated by Claude Code

Introduces an intermediate MODERATOR role between APPROVED_USER and
SUPERADMIN. Moderators can approve/reject access requests and
block/unblock regular users, but cannot assign roles, manage others'
keys, view the audit log, or send announcements.

- models/enums.py: add UserRole.MODERATOR
- db/schema.sql: add MODERATOR to users.role CHECK constraint
- db/database.py: migration v17 recreates users table with new CHECK
  constraint; _validate_enum_values updated accordingly
- services/users.py: new require_moderator_or_admin(), require_approved_or_admin
  now accepts MODERATOR; block/unblock/approve/reject/list methods
  downgraded from require_superadmin to require_moderator_or_admin;
  block_user prevents moderator from blocking another moderator
- services/access_approval.py: approve/reject/list_pending/get_request
  accept moderators
- bot/guards.py: expose require_moderator_or_admin guard
- bot/keyboards/admin.py: moderator_panel_keyboard(); user_actions_keyboard
  accepts actor_role param — hides admin-only buttons for moderators,
  shows assign/revoke moderator buttons for superadmins
- bot/handlers/admin.py: /moderator command and panel callback; setmoderator
  toggle handler; updated block/unblock/request handlers to use
  require_moderator_or_admin and pass actor_role to keyboards

https://claude.ai/code/session_01LVGnWPcQ82ZnFS1D2JcULd
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

claude added 2 commits May 21, 2026 00:46
… _migrate_v17

SQLite silently ignores PRAGMA foreign_keys changes inside an open
transaction. Previous migrations accumulate writes in an implicit
transaction, causing DROP TABLE users to fail with FK constraint errors.
Fix by flushing with await self.commit() first, then operating on the
raw connection with explicit commit/rollback.

https://claude.ai/code/session_01LVGnWPcQ82ZnFS1D2JcULd
Block and unblock handler stubs used require_superadmin which no longer
matches the handlers that now call require_moderator_or_admin.

https://claude.ai/code/session_01LVGnWPcQ82ZnFS1D2JcULd
@Egor051 Egor051 merged commit 1eef289 into main May 21, 2026
4 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