WIP: feat(defaults/withRules): add permission rule wrapper #108

Draft
djalim wants to merge 4 commits from feature/permission-system into develop
Collaborator

Adds a developer-friendly permission system in defaults/withRules.ts.

How it works

withRules() wraps a route handler and grants access if any of the provided rules passes (OR logic). Returns 403 otherwise.

  export const handler: Handlers<null, AuthenticatedState> = {    
    GET: withRules(["note_read", "own_note"])(async (_req, ctx) => { ... }),                       
    PUT: withRules(["note_write", "own_teaching_note"])(async (req, ctx) => { ... }),              
  };                                                                                               

Rules available

DB-based — checks the user's role against role_permissions:
student_read, student_write, note_read, note_write, module_read, module_write, user_read,
user_write, role_write

Contextual — checks ownership at request time:

  • own_student / own_note — CAS uid matches the student (uid = prenom[0] + numEtud)
  • own_teaching_note — the logged-in user teaches the module in the URL (enseignements table)

Access model

  ┌────────────┬──────────────────────────────────────┐                                            
  │    Role    │               Rule(s)                │           
  ├────────────┼──────────────────────────────────────┤                                            
  │ Admin      │ all DB permissions                   │           
  ├────────────┼──────────────────────────────────────┤
  │ Secrétaire │ note_read, note_write, student_write │
  ├────────────┼──────────────────────────────────────┤                                            
  │ Élève      │ own_note                             │
  ├────────────┼──────────────────────────────────────┤                                            
  │ Prof       │ own_teaching_note                    │           
  └────────────┴──────────────────────────────────────┘

A CAS user not found in users nor students has no rights.

Closes #107

Adds a developer-friendly permission system in defaults/withRules.ts. How it works withRules() wraps a route handler and grants access if any of the provided rules passes (OR logic). Returns 403 otherwise. ```js export const handler: Handlers<null, AuthenticatedState> = { GET: withRules(["note_read", "own_note"])(async (_req, ctx) => { ... }), PUT: withRules(["note_write", "own_teaching_note"])(async (req, ctx) => { ... }), }; ```` Rules available DB-based — checks the user's role against role_permissions: student_read, student_write, note_read, note_write, module_read, module_write, user_read, user_write, role_write Contextual — checks ownership at request time: - own_student / own_note — CAS uid matches the student (uid = prenom[0] + numEtud) - own_teaching_note — the logged-in user teaches the module in the URL (enseignements table) Access model ``` ┌────────────┬──────────────────────────────────────┐ │ Role │ Rule(s) │ ├────────────┼──────────────────────────────────────┤ │ Admin │ all DB permissions │ ├────────────┼──────────────────────────────────────┤ │ Secrétaire │ note_read, note_write, student_write │ ├────────────┼──────────────────────────────────────┤ │ Élève │ own_note │ ├────────────┼──────────────────────────────────────┤ │ Prof │ own_teaching_note │ └────────────┴──────────────────────────────────────┘ ``` A CAS user not found in users nor students has no rights. Closes #107
anys requested review from anys 2026-04-22 17:14:10 +00:00
Collaborator

If I get it, every time we implement an API, we need to precise the require rules ?
So like this :

export const handler = {
  POST: withRules(["student_write"])(async (req, ctx) => {
    async GET(request) {
    ...
    }
  }

Instead of this :

export const handler: Handlers<null, AuthenticatedState> = {
  // #48 GET /ajustements
  async GET(request) {
  ...
  }
}

Then, wouldn't it be a problem for routes like GET /notes/{numEtud}/{idModule} where every role has different constraint ?

If I get it, every time we implement an API, we need to precise the require rules ? So like this : ```ts export const handler = { POST: withRules(["student_write"])(async (req, ctx) => { async GET(request) { ... } } ``` Instead of this : ```ts export const handler: Handlers<null, AuthenticatedState> = { // #48 GET /ajustements async GET(request) { ... } } ``` Then, wouldn't it be a problem for routes like `GET /notes/{numEtud}/{idModule}` where every role has different constraint ?
djalim changed title from feat(defaults/withRules): add permission rule wrapper to DRAFT: feat(defaults/withRules): add permission rule wrapper 2026-04-23 12:10:26 +00:00
djalim changed title from DRAFT: feat(defaults/withRules): add permission rule wrapper to WIP: feat(defaults/withRules): add permission rule wrapper 2026-04-23 12:10:37 +00:00
djalim added 4 commits 2026-04-27 17:46:08 +00:00
refactor: add withRules wrapper to API routes

Use withRules to enforce permissions instead of manual checks.
Remove FORBIDDEN constant, simplify handlers, import withRules,
adjust GET/POST/PUT/DELETE handlers.
Centralizes auth logic.

refactor: replace manual auth checks with withRules wrapper for routes

refactor(student routes): replace manual employee checks with withRules wrapper
refactor(notes): improve error handling and formatting
Check Deno code / Check Deno code (pull_request) Successful in 5s
Tests / Unit tests (pull_request) Successful in 11s
Tests / Integration tests (pull_request) Failing after 1m18s
401160aa30
docs: update CLAUDE.md formatting
djalim force-pushed feature/permission-system from 1a25ae981a to 401160aa30 2026-04-27 17:46:08 +00:00 Compare
Some checks are pending
Check Deno code / Check Deno code (pull_request) Successful in 5s
Tests / Unit tests (pull_request) Successful in 11s
Tests / Integration tests (pull_request) Failing after 1m18s
This pull request has changes conflicting with the target branch.
  • routes/(apps)/admin/api/ue-modules/[idModule]/[idUE]/[idPromo].ts
  • routes/(apps)/admin/api/ues/[idUE].ts
  • routes/(apps)/notes/api/ajustements.ts
  • routes/(apps)/notes/api/notes/[numEtud]/[idModule].ts
  • routes/(apps)/notes/api/ue-modules.ts
  • routes/(apps)/notes/api/ues.ts
  • routes/(apps)/students/api/promotions.ts
  • routes/(apps)/students/api/promotions/[idPromo].ts
  • routes/(apps)/students/api/students.ts
  • routes/(apps)/students/api/students/[numEtud].ts
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feature/permission-system:feature/permission-system
git checkout feature/permission-system
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/PolyMPR#108