Skip to content

Commit fb491c3

Browse files
committed
feat: Implement courses roles and permissions mappings, including legacy compat permissions
1 parent dc99738 commit fb491c3

8 files changed

Lines changed: 470 additions & 27 deletions

File tree

CHANGELOG.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ Unreleased
1717
Added
1818
=====
1919

20+
0.22.0 - 2026-02-19
21+
********************
22+
2023
* ADR on the AuthZ for Course Authoring implementation plan.
2124
* ADR on the AuthZ for Course Authoring Feature Flag Implementation Details.
22-
25+
* Defined courses roles and permissions mappings, including legacy compatible permissions.
2326

2427
0.21.0 - 2026-02-12
2528
********************

openedx_authz/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
import os
66

7-
__version__ = "0.21.0"
7+
__version__ = "0.22.0"
88

99
ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__))

openedx_authz/constants/permissions.py

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,177 @@
5858

5959
COURSES_NAMESPACE = "courses"
6060

61-
MANAGE_ADVANCED_SETTINGS = PermissionData(
61+
COURSES_VIEW_COURSE = PermissionData(
62+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.view_course"),
63+
effect="allow",
64+
)
65+
66+
COURSES_CREATE_COURSE = PermissionData(
67+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.create_course"),
68+
effect="allow",
69+
)
70+
71+
COURSES_EDIT_COURSE_CONTENT = PermissionData(
72+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.edit_course_content"),
73+
effect="allow",
74+
)
75+
76+
COURSES_PUBLISH_COURSE_CONTENT = PermissionData(
77+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.publish_course_content"),
78+
effect="allow",
79+
)
80+
81+
COURSES_MANAGE_LIBRARY_UPDATES = PermissionData(
82+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.manage_library_updates"),
83+
effect="allow",
84+
)
85+
86+
COURSES_VIEW_COURSE_UPDATES = PermissionData(
87+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.view_course_updates"),
88+
effect="allow",
89+
)
90+
91+
COURSES_MANAGE_COURSE_UPDATES = PermissionData(
92+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.manage_course_updates"),
93+
effect="allow",
94+
)
95+
96+
COURSES_VIEW_PAGES_AND_RESOURCES = PermissionData(
97+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.view_pages_and_resources"),
98+
effect="allow",
99+
)
100+
101+
COURSES_MANAGE_PAGES_AND_RESOURCES = PermissionData(
102+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.manage_pages_and_resources"),
103+
effect="allow",
104+
)
105+
106+
COURSES_VIEW_FILES = PermissionData(
107+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.view_files"),
108+
effect="allow",
109+
)
110+
111+
COURSES_CREATE_FILES = PermissionData(
112+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.create_files"),
113+
effect="allow",
114+
)
115+
116+
COURSES_DELETE_FILES = PermissionData(
117+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.delete_files"),
118+
effect="allow",
119+
)
120+
121+
COURSES_EDIT_FILES = PermissionData(
122+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.edit_files"),
123+
effect="allow",
124+
)
125+
126+
COURSES_VIEW_SCHEDULE_AND_DETAILS = PermissionData(
127+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.view_schedule_and_details"),
128+
effect="allow",
129+
)
130+
131+
COURSES_EDIT_SCHEDULE = PermissionData(
132+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.edit_schedule"),
133+
effect="allow",
134+
)
135+
136+
COURSES_EDIT_DETAILS = PermissionData(
137+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.edit_details"),
138+
effect="allow",
139+
)
140+
141+
COURSES_VIEW_GRADING_SETTINGS = PermissionData(
142+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.view_grading_settings"),
143+
effect="allow",
144+
)
145+
146+
COURSES_EDIT_GRADING_SETTINGS = PermissionData(
147+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.edit_grading_settings"),
148+
effect="allow",
149+
)
150+
151+
COURSES_VIEW_COURSE_TEAM = PermissionData(
152+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.view_course_team"),
153+
effect="allow",
154+
)
155+
156+
COURSES_MANAGE_COURSE_TEAM = PermissionData(
157+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.manage_course_team"),
158+
effect="allow",
159+
)
160+
161+
COURSES_MANAGE_GROUP_CONFIGURATIONS = PermissionData(
162+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.manage_group_configurations"),
163+
effect="allow",
164+
)
165+
166+
COURSES_MANAGE_ADVANCED_SETTINGS = PermissionData(
62167
action=ActionData(external_key=f"{COURSES_NAMESPACE}.manage_advanced_settings"),
63168
effect="allow",
64169
)
170+
171+
COURSES_MANAGE_CERTIFICATES = PermissionData(
172+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.manage_certificates"),
173+
effect="allow",
174+
)
175+
176+
COURSES_IMPORT_COURSE = PermissionData(
177+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.import_course"),
178+
effect="allow",
179+
)
180+
181+
COURSES_EXPORT_COURSE = PermissionData(
182+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.export_course"),
183+
effect="allow",
184+
)
185+
186+
COURSES_EXPORT_TAGS = PermissionData(
187+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.export_tags"),
188+
effect="allow",
189+
)
190+
191+
COURSES_VIEW_CHECKLISTS = PermissionData(
192+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.view_checklists"),
193+
effect="allow",
194+
)
195+
196+
COURSES_MANAGE_TAGS = PermissionData(
197+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.manage_tags"),
198+
effect="allow",
199+
)
200+
201+
COURSES_MANAGE_TAXONOMIES = PermissionData(
202+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.manage_taxonomies"),
203+
effect="allow",
204+
)
205+
206+
# Legacy Course permissions
207+
# These permissions allow backwards compatibility with legacy code that depends on the old roles system
208+
# These relate to legacy roles, if a openedx-authz role has one of these permissions,
209+
# it will have the same permissions as the equivalent legacy roles on code that has not been updated to the new system.
210+
211+
COURSES_LEGACY_INSTRUCTOR_ROLE_PERMISSIONS = PermissionData(
212+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.legacy_instructor_role_permissions"),
213+
effect="allow",
214+
)
215+
216+
COURSES_LEGACY_STAFF_ROLE_PERMISSIONS = PermissionData(
217+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.legacy_staff_role_permissions"),
218+
effect="allow",
219+
)
220+
221+
COURSES_LEGACY_LIMITED_STAFF_ROLE_PERMISSIONS = PermissionData(
222+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.legacy_limited_staff_role_permissions"),
223+
effect="allow",
224+
)
225+
226+
COURSES_LEGACY_DATA_RESEARCHER_PERMISSIONS = PermissionData(
227+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.legacy_data_researcher_permissions"),
228+
effect="allow",
229+
)
230+
231+
COURSES_LEGACY_BETA_TESTER_PERMISSIONS = PermissionData(
232+
action=ActionData(external_key=f"{COURSES_NAMESPACE}.legacy_beta_tester_permissions"),
233+
effect="allow",
234+
)

openedx_authz/constants/roles.py

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,133 @@
6060

6161
# Course Roles and Permissions
6262

63+
COURSE_AUDITOR_PERMISSIONS = [
64+
permissions.COURSES_VIEW_COURSE,
65+
permissions.COURSES_VIEW_COURSE_UPDATES,
66+
permissions.COURSES_VIEW_PAGES_AND_RESOURCES,
67+
permissions.COURSES_VIEW_FILES,
68+
permissions.COURSES_VIEW_GRADING_SETTINGS,
69+
permissions.COURSES_VIEW_CHECKLISTS,
70+
permissions.COURSES_VIEW_COURSE_TEAM,
71+
permissions.COURSES_VIEW_SCHEDULE_AND_DETAILS,
72+
]
73+
74+
COURSE_AUDITOR = RoleData(external_key="course_auditor", permissions=COURSE_AUDITOR_PERMISSIONS)
75+
76+
COURSE_EDITOR_PERMISSIONS = [
77+
permissions.COURSES_VIEW_COURSE,
78+
permissions.COURSES_VIEW_COURSE_UPDATES,
79+
permissions.COURSES_VIEW_PAGES_AND_RESOURCES,
80+
permissions.COURSES_VIEW_FILES,
81+
permissions.COURSES_VIEW_GRADING_SETTINGS,
82+
permissions.COURSES_VIEW_CHECKLISTS,
83+
permissions.COURSES_VIEW_COURSE_TEAM,
84+
permissions.COURSES_VIEW_SCHEDULE_AND_DETAILS,
85+
permissions.COURSES_EDIT_COURSE_CONTENT,
86+
permissions.COURSES_MANAGE_LIBRARY_UPDATES,
87+
permissions.COURSES_MANAGE_COURSE_UPDATES,
88+
permissions.COURSES_MANAGE_PAGES_AND_RESOURCES,
89+
permissions.COURSES_CREATE_FILES,
90+
permissions.COURSES_EDIT_FILES,
91+
permissions.COURSES_EDIT_GRADING_SETTINGS,
92+
permissions.COURSES_MANAGE_GROUP_CONFIGURATIONS,
93+
permissions.COURSES_EDIT_DETAILS,
94+
permissions.COURSES_MANAGE_TAGS,
95+
]
96+
97+
COURSE_EDITOR = RoleData(external_key="course_editor", permissions=COURSE_EDITOR_PERMISSIONS)
98+
99+
COURSE_ADMIN_PERMISSIONS = [
100+
permissions.COURSES_LEGACY_INSTRUCTOR_ROLE_PERMISSIONS,
101+
permissions.COURSES_VIEW_COURSE,
102+
permissions.COURSES_VIEW_COURSE_UPDATES,
103+
permissions.COURSES_VIEW_PAGES_AND_RESOURCES,
104+
permissions.COURSES_VIEW_FILES,
105+
permissions.COURSES_VIEW_GRADING_SETTINGS,
106+
permissions.COURSES_VIEW_CHECKLISTS,
107+
permissions.COURSES_VIEW_COURSE_TEAM,
108+
permissions.COURSES_VIEW_SCHEDULE_AND_DETAILS,
109+
permissions.COURSES_EDIT_COURSE_CONTENT,
110+
permissions.COURSES_MANAGE_LIBRARY_UPDATES,
111+
permissions.COURSES_MANAGE_COURSE_UPDATES,
112+
permissions.COURSES_MANAGE_PAGES_AND_RESOURCES,
113+
permissions.COURSES_CREATE_FILES,
114+
permissions.COURSES_EDIT_FILES,
115+
permissions.COURSES_EDIT_GRADING_SETTINGS,
116+
permissions.COURSES_MANAGE_GROUP_CONFIGURATIONS,
117+
permissions.COURSES_EDIT_DETAILS,
118+
permissions.COURSES_MANAGE_TAGS,
119+
permissions.COURSES_PUBLISH_COURSE_CONTENT,
120+
permissions.COURSES_DELETE_FILES,
121+
permissions.COURSES_EDIT_SCHEDULE,
122+
permissions.COURSES_MANAGE_ADVANCED_SETTINGS,
123+
permissions.COURSES_MANAGE_CERTIFICATES,
124+
permissions.COURSES_IMPORT_COURSE,
125+
permissions.COURSES_EXPORT_COURSE,
126+
permissions.COURSES_EXPORT_TAGS,
127+
permissions.COURSES_MANAGE_COURSE_TEAM,
128+
permissions.COURSES_MANAGE_TAXONOMIES,
129+
]
130+
131+
COURSE_ADMIN = RoleData(external_key="course_admin", permissions=COURSE_ADMIN_PERMISSIONS)
63132

64133
COURSE_STAFF_PERMISSIONS = [
65-
permissions.MANAGE_ADVANCED_SETTINGS,
134+
permissions.COURSES_LEGACY_STAFF_ROLE_PERMISSIONS,
135+
permissions.COURSES_VIEW_COURSE,
136+
permissions.COURSES_VIEW_COURSE_UPDATES,
137+
permissions.COURSES_VIEW_PAGES_AND_RESOURCES,
138+
permissions.COURSES_VIEW_FILES,
139+
permissions.COURSES_VIEW_GRADING_SETTINGS,
140+
permissions.COURSES_VIEW_CHECKLISTS,
141+
permissions.COURSES_VIEW_COURSE_TEAM,
142+
permissions.COURSES_VIEW_SCHEDULE_AND_DETAILS,
143+
permissions.COURSES_EDIT_COURSE_CONTENT,
144+
permissions.COURSES_MANAGE_LIBRARY_UPDATES,
145+
permissions.COURSES_MANAGE_COURSE_UPDATES,
146+
permissions.COURSES_MANAGE_PAGES_AND_RESOURCES,
147+
permissions.COURSES_CREATE_FILES,
148+
permissions.COURSES_EDIT_FILES,
149+
permissions.COURSES_EDIT_GRADING_SETTINGS,
150+
permissions.COURSES_MANAGE_GROUP_CONFIGURATIONS,
151+
permissions.COURSES_EDIT_DETAILS,
152+
permissions.COURSES_MANAGE_TAGS,
153+
permissions.COURSES_PUBLISH_COURSE_CONTENT,
154+
permissions.COURSES_DELETE_FILES,
155+
permissions.COURSES_EDIT_SCHEDULE,
156+
permissions.COURSES_MANAGE_ADVANCED_SETTINGS,
157+
permissions.COURSES_MANAGE_CERTIFICATES,
158+
permissions.COURSES_IMPORT_COURSE,
159+
permissions.COURSES_EXPORT_COURSE,
160+
permissions.COURSES_EXPORT_TAGS,
66161
]
67162

68163
COURSE_STAFF = RoleData(external_key="course_staff", permissions=COURSE_STAFF_PERMISSIONS)
164+
165+
COURSE_LIMITED_STAFF_PERMISSIONS = [
166+
permissions.COURSES_LEGACY_LIMITED_STAFF_ROLE_PERMISSIONS,
167+
]
168+
169+
COURSE_LIMITED_STAFF = RoleData(external_key="course_limited_staff", permissions=COURSE_LIMITED_STAFF_PERMISSIONS)
170+
171+
COURSE_DATA_RESEARCHER_PERMISSIONS = [
172+
permissions.COURSES_LEGACY_DATA_RESEARCHER_PERMISSIONS,
173+
]
174+
175+
COURSE_DATA_RESEARCHER = RoleData(external_key="course_data_researcher", permissions=COURSE_DATA_RESEARCHER_PERMISSIONS)
176+
177+
COURSE_BETA_TESTER_PERMISSIONS = [
178+
permissions.COURSES_LEGACY_BETA_TESTER_PERMISSIONS,
179+
]
180+
181+
COURSE_BETA_TESTER = RoleData(external_key="course_beta_tester", permissions=COURSE_BETA_TESTER_PERMISSIONS)
182+
183+
# Map of legacy course role names to their equivalent new roles
184+
# This mapping must be unique in both directions, since it may be used as a reverse lookup (value → key).
185+
# If multiple keys share the same value, it will lead to collisions.
186+
LEGACY_COURSE_ROLE_EQUIVALENCES = {
187+
"instructor": COURSE_ADMIN.external_key,
188+
"staff": COURSE_STAFF.external_key,
189+
"limited_staff": COURSE_LIMITED_STAFF.external_key,
190+
"data_researcher": COURSE_DATA_RESEARCHER.external_key,
191+
"beta_testers": COURSE_BETA_TESTER.external_key,
192+
}

0 commit comments

Comments
 (0)