Skip to content

Refactor steward permissions from per-action rows to role+scope model#564

Open
JoaquinBN wants to merge 1 commit intodevfrom
JoaquinBN/steward-perms-audit
Open

Refactor steward permissions from per-action rows to role+scope model#564
JoaquinBN wants to merge 1 commit intodevfrom
JoaquinBN/steward-perms-audit

Conversation

@JoaquinBN
Copy link
Copy Markdown
Collaborator

Summary

Replaces StewardPermission (one row per steward × contribution type × action, 672 rows for 4 stewards) with StewardAssignment, a role + scope model. Two roles: full_review (accept/reject/request_more_info/propose) and propose (propose only). Scope is a category, a contribution type, or global. Multiple assignments per steward are additive. The data migration collapses existing permissions per steward (global → category → per-type, then propose-only with the same collapsing), dropping partial action combinations with a print summary; verified against live data with zero mismatches (672 grants → 40 assignments). Frontend response shapes for /stewards/ and /my-permissions/ are preserved so no Svelte changes are required.

Test plan

  • python manage.py migrate on a DB copy; confirm StewardPermission table is dropped and StewardAssignment row count matches the collapse summary
  • Log in as a full-review steward; accept / reject / request-more-info / propose on a submission
  • Log in as a propose-only steward; expect 403 on accept, 200 on propose
  • Add a new StewardAssignment in Django admin with both scope_category and scope_type set; confirm form validation blocks it
  • /stewards/ list shows expected role label and permitted_categories
  • /my-permissions/ returns {ct_id: [actions]} covering every permitted type

Replace StewardPermission (one row per steward × contribution type × action)
with StewardAssignment, a role + scope model. Two roles: full_review
(accept, reject, request_more_info, propose) and propose (propose only).
Scope is one of a category, a contribution type, or global (both null).
Multiple assignments per steward are additive.

Data migration collapses existing permissions per steward: global full set
first, then category-level, then per-type, then propose-only with the same
collapsing. Partial action combinations are dropped with a summary print
for manual review. The old StewardPermission model is deleted in a follow
up migration.

Frontend response shapes are preserved so no Svelte changes are required:
/stewards/ still returns role + permitted_categories, /my-permissions/
still returns { ct_id: [actions] }. Django admin gains a StewardAssignment
inline with a dual-scope guard matching the DB CheckConstraint.

## Implementation Notes
- backend/stewards/models.py: Remove StewardPermission; add StewardAssignment with CheckConstraint (scopes mutually exclusive) and UniqueConstraint on (steward, role, scope_category, scope_type).
- backend/stewards/migrations/0010_stewardassignment.py: New model.
- backend/stewards/migrations/0011_migrate_permissions_to_assignments.py: Data migration collapsing StewardPermission rows into StewardAssignment rows.
- backend/stewards/migrations/0012_delete_stewardpermission.py: Drop old model.
- backend/contributions/permissions.py: Rewrite steward_has_permission and steward_permitted_type_ids to query StewardAssignment; full_review implies propose, encoded in code.
- backend/contributions/views.py: Rewrite /my-permissions/; short-circuits when steward has a global full_review assignment.
- backend/stewards/views.py: Rewrite /stewards/ list; role label derived from assignments, permitted_categories built via scope_category or scope_type.category_id.
- backend/stewards/admin.py: Replace StewardPermissionInline/Admin with StewardAssignmentInline/Admin; form clean() enforces single scope.
- backend/contributions/management/commands/review_submissions.py: AI steward creation uses a single global full_review StewardAssignment.
- backend/contributions/tests/test_steward_permissions.py, test_calibration_data.py: Update setUp to create StewardAssignment.
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.

1 participant