Skip to content

Commit 209ff50

Browse files
efortishBryanttV
authored andcommitted
revert: Cannot rerun courses - authz role assignment expects rerun to already exist (#38973)
(cherry picked from commit 07f0986) (cherry picked from commit 6aeb002)
1 parent 0b0289b commit 209ff50

4 files changed

Lines changed: 18 additions & 102 deletions

File tree

‎cms/djangoapps/contentstore/tasks.py‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
from cms.djangoapps.contentstore.toggles import enable_course_optimizer_check_prev_run_links
5757
from cms.djangoapps.contentstore.utils import (
5858
IMPORTABLE_FILE_TYPES,
59-
add_instructor,
6059
contains_course_reference,
6160
create_course_info_usage_key,
6261
create_or_update_xblock_upstream_link,
@@ -189,14 +188,7 @@ def rerun_course(source_course_key_string, destination_course_key_string, user_i
189188
update_unit_discussion_state_from_discussion_blocks(destination_course_key, user_id)
190189

191190
# set initial permissions for the user to access the course.
192-
# NOTE: add_instructor is called here (after clone_course) because when
193-
# authz.enable_course_authoring is enabled, it cannot be called pre-task
194-
# (CourseOverview doesn't exist yet). This is a temporary workaround until
195-
# openedx/openedx-authz#352 is implemented. Once resolved, add_instructor
196-
# can move back to the pre-task call site unconditionally.
197-
user = User.objects.get(id=user_id)
198-
add_instructor(destination_course_key, user, user)
199-
initialize_permissions(destination_course_key, user)
191+
initialize_permissions(destination_course_key, User.objects.get(id=user_id))
200192

201193
# update state: Succeeded
202194
CourseRerunState.objects.succeeded(course_key=destination_course_key)

‎cms/djangoapps/contentstore/tests/test_clone_course.py‎

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@
1414
from common.djangoapps.course_action_state.managers import CourseRerunUIStateManager
1515
from common.djangoapps.course_action_state.models import CourseRerunState
1616
from common.djangoapps.student.auth import has_course_author_access
17-
from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole
18-
from xmodule.contentstore.content import StaticContent # pylint: disable=wrong-import-order
19-
from xmodule.contentstore.django import contentstore # pylint: disable=wrong-import-order
20-
from xmodule.modulestore import EdxJSONEncoder, ModuleStoreEnum # pylint: disable=wrong-import-order
21-
from xmodule.modulestore.tests.factories import CourseFactory # pylint: disable=wrong-import-order
17+
from xmodule.contentstore.content import StaticContent # lint-amnesty, pylint: disable=wrong-import-order
18+
from xmodule.contentstore.django import contentstore # lint-amnesty, pylint: disable=wrong-import-order
19+
from xmodule.modulestore import EdxJSONEncoder, ModuleStoreEnum # lint-amnesty, pylint: disable=wrong-import-order
20+
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
2221

2322
TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT
2423

@@ -142,49 +141,3 @@ def test_rerun_course(self):
142141
course_key=split_course4_id,
143142
state=CourseRerunUIStateManager.State.FAILED
144143
)
145-
146-
147-
def test_rerun_course_grants_instructor_access(self):
148-
"""
149-
Test that the rerun_course task grants instructor and staff access
150-
to the user after cloning. This verifies add_instructor is called
151-
inside the task (needed when authz.enable_course_authoring is enabled
152-
and add_instructor cannot be called pre-task).
153-
154-
TODO: This test covers a temporary workaround until openedx/openedx-authz#352
155-
is implemented. Once authz supports pre-assigning roles without a CourseOverview,
156-
add_instructor can move back to the pre-task call site and this test can be
157-
simplified.
158-
"""
159-
org = 'edX'
160-
course_number = 'CS101'
161-
course_run = '2025_Q1'
162-
display_name = 'rerun_instructor_test'
163-
fields = {'display_name': display_name}
164-
165-
# Create a source course
166-
source_course = CourseFactory.create(
167-
org=org,
168-
number=course_number,
169-
run=course_run,
170-
display_name=display_name,
171-
default_store=ModuleStoreEnum.Type.split,
172-
)
173-
174-
dest_course_id = CourseLocator(org=org, course=course_number, run="instructor_rerun")
175-
CourseRerunState.objects.initiated(
176-
source_course.id, dest_course_id, self.user, fields['display_name']
177-
)
178-
179-
result = rerun_course.delay(
180-
str(source_course.id),
181-
str(dest_course_id),
182-
self.user.id,
183-
json.dumps(fields, cls=EdxJSONEncoder),
184-
)
185-
assert result.get() == "succeeded"
186-
187-
# Verify the user has instructor and staff access on the new course
188-
assert has_course_author_access(self.user, dest_course_id)
189-
assert CourseInstructorRole(dest_course_id).has_user(self.user)
190-
assert CourseStaffRole(dest_course_id).has_user(self.user)

‎cms/djangoapps/contentstore/tests/test_course_create_rerun.py‎

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -426,18 +426,10 @@ class TestCourseRerunAuthz(
426426
"""
427427
Tests for course rerun behavior when authz.enable_course_authoring is enabled.
428428
429-
Verifies that:
430-
- Rerun succeeds without calling add_instructor pre-task (which would fail
431-
because CourseOverview doesn't exist yet).
432-
- add_instructor is called in the task after clone_course, when CourseOverview
433-
can be resolved.
434-
- The initiating user can see in-process rerun status via created_user check.
435-
436-
TODO: These tests cover a temporary workaround needed while (1) the authz system
437-
doesn't support pre-assigning roles without a CourseOverview, and (2) we support
438-
both authz and legacy systems simultaneously. Once openedx/openedx-authz#352 is
439-
implemented, this class can be simplified — the conditional skip of add_instructor
440-
and the created_user visibility fallback will no longer be needed.
429+
Verifies that rerun succeeds and grants proper access even though add_instructor
430+
is called for the destination course key before its CourseOverview exists
431+
(openedx-authz#352 makes role assignment succeed ahead of the object, backfilling
432+
the link once clone_course creates it).
441433
"""
442434

443435
def setUp(self):
@@ -467,8 +459,8 @@ def setUp(self):
467459
def test_rerun_succeeds_with_authz_enabled(self):
468460
"""
469461
Test that course rerun completes successfully when authz.enable_course_authoring
470-
is enabled. Previously this would fail with CourseOverview.DoesNotExist because
471-
add_instructor was called before the course was cloned.
462+
is enabled, granting the initiating user instructor/staff access on the
463+
destination course before it's cloned.
472464
"""
473465
response = self.staff_client.ajax_post(self.url, {
474466
'source_course_key': str(self.source_course_key),
@@ -516,8 +508,7 @@ def test_rerun_does_not_create_legacy_roles_with_authz_enabled(self):
516508
def test_rerun_grants_authz_permissions_after_clone(self):
517509
"""
518510
Test that after a successful rerun with authz enabled, the user has proper
519-
permissions via the authz layer (add_instructor is called in the task after
520-
clone_course completes and CourseOverview is available).
511+
permissions via the authz layer on the newly created destination course.
521512
"""
522513
response = self.staff_client.ajax_post(self.url, {
523514
'source_course_key': str(self.source_course_key),
@@ -537,8 +528,8 @@ def test_rerun_grants_authz_permissions_after_clone(self):
537528
def test_in_process_rerun_visible_to_initiating_user(self):
538529
"""
539530
Test that the user who initiated the rerun can see the in-process status
540-
via the created_user check in get_in_process_course_actions, even when
541-
authz permissions haven't been fully established yet.
531+
in get_in_process_course_actions, via the instructor/staff access already
532+
granted on the destination course.
542533
"""
543534
dest_course_key = CourseLocator(org='testorg', course='101', run='in_progress_rerun')
544535
CourseRerunState.objects.initiated(

‎cms/djangoapps/contentstore/views/course.py‎

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -429,19 +429,8 @@ def get_in_process_course_actions(request):
429429
exclude_args={'state': CourseRerunUIStateManager.State.SUCCEEDED},
430430
should_display=True,
431431
)
432-
if (
433-
# The user who initiated the rerun can always see its status.
434-
# This is needed because when the authz flag is enabled, permission
435-
# checks require a CourseOverview which doesn't exist until the
436-
# rerun task clones the course.
437-
# TODO: This created_user fallback is a temporary workaround until
438-
# openedx/openedx-authz#352 is implemented. Once authz supports
439-
# pre-assigning roles without a CourseOverview, this check can be removed
440-
# and the standard permission check will suffice.
441-
course.created_user == request.user
442-
or user_has_course_permission(
443-
request.user, COURSES_VIEW_COURSE.identifier, course.course_key, LegacyAuthoringPermission.READ
444-
)
432+
if user_has_course_permission(
433+
request.user, COURSES_VIEW_COURSE.identifier, course.course_key, LegacyAuthoringPermission.READ
445434
)
446435
]
447436

@@ -1345,17 +1334,8 @@ def rerun_course(user, source_course_key, org, number, run, fields, background=T
13451334
raise PermissionDenied()
13461335

13471336
# Make sure user has instructor and staff access to the destination course
1348-
# so the user can see the updated status for that course.
1349-
# When authz is enabled, we skip this because the authz layer requires a
1350-
# CourseOverview (which doesn't exist until the course is cloned in the task).
1351-
# In that case, visibility of the rerun status is granted by checking
1352-
# created_user on CourseRerunState instead.
1353-
# TODO: This conditional is a temporary workaround until openedx/openedx-authz#352
1354-
# is implemented (pre-assigning roles without a CourseOverview). Once resolved,
1355-
# add_instructor can be called unconditionally here and the created_user fallback
1356-
# in get_in_process_course_actions can be removed.
1357-
if not enable_authz_course_authoring(destination_course_key):
1358-
add_instructor(destination_course_key, user, user)
1337+
# so the user can see the updated status for that course
1338+
add_instructor(destination_course_key, user, user)
13591339

13601340
# Mark the action as initiated
13611341
CourseRerunState.objects.initiated(source_course_key, destination_course_key, user, fields['display_name'])

0 commit comments

Comments
 (0)