Add option to backfill org data as inactive
Add an `--inactive` option to the `bulk_add_orgs_and_org_courses` management command, which causes the backfill to set `active=False` on all rows created in the Organization and OrganizationCourse tables. This will lower the potential data integrity risk to production systems such as courses.edx.org. Upgrade edx-organizations to 6.6.0 TNL-7774
This commit is contained in:
committed by
Kyle McCormick
parent
492ce7f217
commit
599d663779
@@ -107,6 +107,11 @@ class Command(BaseCommand):
|
||||
action='store_true',
|
||||
help="Show backfill, but do not apply changes to database."
|
||||
)
|
||||
parser.add_argument(
|
||||
'--inactive',
|
||||
action='store_true',
|
||||
help="Backfill data as inactive and do not re-activate any existing data."
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"""
|
||||
@@ -135,7 +140,12 @@ class Command(BaseCommand):
|
||||
if not confirm_changes(options, orgs, org_courseid_pairs):
|
||||
print("No changes applied.")
|
||||
return
|
||||
bulk_add_data(orgs, org_courseid_pairs, dry_run=False)
|
||||
bulk_add_data(
|
||||
orgs,
|
||||
org_courseid_pairs,
|
||||
dry_run=False,
|
||||
activate=(not options.get('inactive')),
|
||||
)
|
||||
|
||||
|
||||
def confirm_changes(options, orgs, org_courseid_pairs):
|
||||
@@ -158,7 +168,12 @@ def confirm_changes(options, orgs, org_courseid_pairs):
|
||||
raise CommandError("Only one of 'apply' and 'dry' may be specified")
|
||||
if options.get('apply'):
|
||||
return True
|
||||
bulk_add_data(orgs, org_courseid_pairs, dry_run=True)
|
||||
bulk_add_data(
|
||||
orgs,
|
||||
org_courseid_pairs,
|
||||
dry_run=True,
|
||||
activate=(not options.get('inactive')),
|
||||
)
|
||||
if options.get('dry'):
|
||||
return False
|
||||
answer = ""
|
||||
@@ -167,7 +182,7 @@ def confirm_changes(options, orgs, org_courseid_pairs):
|
||||
return answer.lower().startswith('y')
|
||||
|
||||
|
||||
def bulk_add_data(orgs, org_courseid_pairs, dry_run):
|
||||
def bulk_add_data(orgs, org_courseid_pairs, dry_run, activate):
|
||||
"""
|
||||
Bulk-add the organizations and organization-course linkages.
|
||||
|
||||
@@ -182,6 +197,9 @@ def bulk_add_data(orgs, org_courseid_pairs, dry_run):
|
||||
org_courseid_pairs (list[tuple[dict, str]]):
|
||||
list of (org data dictionary, course key string) links to bulk-add.
|
||||
dry_run: Whether or not this run should be "dry" (ie, don't apply changes).
|
||||
activate: Whether newly-added organizations and organization-course linkages
|
||||
should be activated, and whether existing-but-inactive
|
||||
organizations/linkages should be reactivated.
|
||||
"""
|
||||
adding_phrase = "Dry-run of bulk-adding" if dry_run else "Bulk-adding"
|
||||
created_phrase = "Will create" if dry_run else "Created"
|
||||
@@ -190,7 +208,7 @@ def bulk_add_data(orgs, org_courseid_pairs, dry_run):
|
||||
print("------------------------------------------------------")
|
||||
print(f"{adding_phrase} organizations...")
|
||||
orgs_created, orgs_reactivated = organizations_api.bulk_add_organizations(
|
||||
orgs, dry_run=dry_run
|
||||
orgs, dry_run=dry_run, activate=activate
|
||||
)
|
||||
print(f"{created_phrase} {len(orgs_created)} organizations:")
|
||||
for org_short_name in sorted(orgs_created):
|
||||
@@ -202,7 +220,7 @@ def bulk_add_data(orgs, org_courseid_pairs, dry_run):
|
||||
print("------------------------------------------------------")
|
||||
print(f"{adding_phrase} organization-course linkages...")
|
||||
linkages_created, linkages_reactivated = organizations_api.bulk_add_organization_courses(
|
||||
org_courseid_pairs, dry_run=dry_run
|
||||
org_courseid_pairs, dry_run=dry_run, activate=activate
|
||||
)
|
||||
print(f"{created_phrase} {len(linkages_created)} organization-course linkages:")
|
||||
for org_short_name, course_id in sorted(linkages_created):
|
||||
|
||||
@@ -117,26 +117,43 @@ class BackfillOrgsAndOrgCoursesTest(SharedModuleStoreTestCase):
|
||||
"command_line_args": [],
|
||||
"user_inputs": ["n"],
|
||||
"should_apply_changes": False,
|
||||
"should_data_be_activated": True,
|
||||
},
|
||||
{
|
||||
"command_line_args": [],
|
||||
"user_inputs": ["x", "N"],
|
||||
"should_apply_changes": False,
|
||||
"should_data_be_activated": True,
|
||||
},
|
||||
{
|
||||
"command_line_args": [],
|
||||
"user_inputs": ["", "", "YeS"],
|
||||
"should_apply_changes": True,
|
||||
"should_data_be_activated": True,
|
||||
},
|
||||
{
|
||||
"command_line_args": ["--inactive"],
|
||||
"user_inputs": ["y"],
|
||||
"should_apply_changes": True,
|
||||
"should_data_be_activated": False,
|
||||
},
|
||||
{
|
||||
"command_line_args": ["--dry"],
|
||||
"user_inputs": [],
|
||||
"should_apply_changes": False,
|
||||
"should_data_be_activated": True,
|
||||
},
|
||||
{
|
||||
"command_line_args": ["--dry", "--inactive"],
|
||||
"user_inputs": [],
|
||||
"should_apply_changes": False,
|
||||
"should_data_be_activated": False,
|
||||
},
|
||||
{
|
||||
"command_line_args": ["--apply"],
|
||||
"user_inputs": [],
|
||||
"should_apply_changes": True,
|
||||
"should_data_be_activated": True,
|
||||
},
|
||||
)
|
||||
@ddt.unpack
|
||||
@@ -161,6 +178,7 @@ class BackfillOrgsAndOrgCoursesTest(SharedModuleStoreTestCase):
|
||||
command_line_args,
|
||||
user_inputs,
|
||||
should_apply_changes,
|
||||
should_data_be_activated,
|
||||
):
|
||||
"""
|
||||
Test that the command-line arguments and user input processing works as
|
||||
@@ -184,31 +202,38 @@ class BackfillOrgsAndOrgCoursesTest(SharedModuleStoreTestCase):
|
||||
# then we expect one DRY bulk-add run *and* one REAL bulk-add run.
|
||||
assert mock_add_orgs.call_count == 2
|
||||
assert mock_add_org_courses.call_count == 2
|
||||
assert mock_add_orgs.call_args_list[0].kwargs == {"dry_run": True}
|
||||
assert mock_add_org_courses.call_args_list[0].kwargs == {"dry_run": True}
|
||||
assert mock_add_orgs.call_args_list[1].kwargs == {"dry_run": False}
|
||||
assert mock_add_org_courses.call_args_list[1].kwargs == {"dry_run": False}
|
||||
assert mock_add_orgs.call_args_list[0].kwargs["dry_run"] is True
|
||||
assert mock_add_org_courses.call_args_list[0].kwargs["dry_run"] is True
|
||||
assert mock_add_orgs.call_args_list[1].kwargs["dry_run"] is False
|
||||
assert mock_add_org_courses.call_args_list[1].kwargs["dry_run"] is False
|
||||
elif should_apply_changes:
|
||||
# If DID apply changes but the user WASN'T prompted,
|
||||
# then we expect just one REAL bulk-add run.
|
||||
assert mock_add_orgs.call_count == 1
|
||||
assert mock_add_org_courses.call_count == 1
|
||||
assert mock_add_orgs.call_args.kwargs == {"dry_run": False}
|
||||
assert mock_add_org_courses.call_args.kwargs == {"dry_run": False}
|
||||
assert mock_add_orgs.call_args.kwargs["dry_run"] is False
|
||||
assert mock_add_org_courses.call_args.kwargs["dry_run"] is False
|
||||
elif user_inputs:
|
||||
# If we DIDN'T apply changes but the user WAS prompted
|
||||
# then we expect just one DRY bulk-add run.
|
||||
assert mock_add_orgs.call_count == 1
|
||||
assert mock_add_org_courses.call_count == 1
|
||||
assert mock_add_orgs.call_args.kwargs == {"dry_run": True}
|
||||
assert mock_add_org_courses.call_args.kwargs == {"dry_run": True}
|
||||
assert mock_add_orgs.call_args.kwargs["dry_run"] is True
|
||||
assert mock_add_org_courses.call_args.kwargs["dry_run"] is True
|
||||
else:
|
||||
# Similarly, if we DIDN'T apply changes and the user WASN'T prompted
|
||||
# then we expect just one DRY bulk-add run.
|
||||
assert mock_add_orgs.call_count == 1
|
||||
assert mock_add_org_courses.call_count == 1
|
||||
assert mock_add_orgs.call_args.kwargs == {"dry_run": True}
|
||||
assert mock_add_org_courses.call_args.kwargs == {"dry_run": True}
|
||||
assert mock_add_orgs.call_args.kwargs["dry_run"] is True
|
||||
assert mock_add_org_courses.call_args.kwargs["dry_run"] is True
|
||||
|
||||
# Assert that the value of of the "active" kwarg is correct for all
|
||||
# calls both bulk-add functions, whether or not they were dry runs.
|
||||
for call in mock_add_orgs:
|
||||
assert call.kwargs["activate"] == should_data_be_activated
|
||||
for call in mock_add_org_courses:
|
||||
assert call.kwargs["activate"] == should_data_be_activated
|
||||
|
||||
def test_conflicting_arguments(self):
|
||||
"""
|
||||
|
||||
@@ -103,7 +103,7 @@ edx-event-routing-backends==2.0.0 # via -r requirements/edx/base.in
|
||||
edx-i18n-tools==0.5.3 # via ora2
|
||||
edx-milestones==0.3.0 # via -r requirements/edx/base.in
|
||||
edx-opaque-keys[django]==2.1.1 # via -r requirements/edx/paver.txt, edx-bulk-grades, edx-ccx-keys, edx-completion, edx-drf-extensions, edx-enterprise, edx-milestones, edx-organizations, edx-proctoring, edx-user-state-client, edx-when, lti-consumer-xblock, xmodule
|
||||
edx-organizations==6.5.0 # via -r requirements/edx/base.in
|
||||
edx-organizations==6.6.0 # via -r requirements/edx/base.in
|
||||
edx-proctoring-proctortrack==1.0.5 # via -r requirements/edx/base.in
|
||||
edx-proctoring==2.5.5 # via -r requirements/edx/base.in, edx-proctoring-proctortrack
|
||||
edx-rbac==1.3.3 # via edx-enterprise
|
||||
|
||||
@@ -115,7 +115,7 @@ edx-i18n-tools==0.5.3 # via -r requirements/edx/testing.txt, ora2
|
||||
edx-lint==1.6 # via -r requirements/edx/testing.txt
|
||||
edx-milestones==0.3.0 # via -r requirements/edx/testing.txt
|
||||
edx-opaque-keys[django]==2.1.1 # via -r requirements/edx/testing.txt, edx-bulk-grades, edx-ccx-keys, edx-completion, edx-drf-extensions, edx-enterprise, edx-milestones, edx-organizations, edx-proctoring, edx-user-state-client, edx-when, lti-consumer-xblock, xmodule
|
||||
edx-organizations==6.5.0 # via -r requirements/edx/testing.txt
|
||||
edx-organizations==6.6.0 # via -r requirements/edx/testing.txt
|
||||
edx-proctoring-proctortrack==1.0.5 # via -r requirements/edx/testing.txt
|
||||
edx-proctoring==2.5.5 # via -r requirements/edx/testing.txt, edx-proctoring-proctortrack
|
||||
edx-rbac==1.3.3 # via -r requirements/edx/testing.txt, edx-enterprise
|
||||
|
||||
@@ -112,7 +112,7 @@ edx-i18n-tools==0.5.3 # via -r requirements/edx/base.txt, -r requirements/ed
|
||||
edx-lint==1.6 # via -r requirements/edx/testing.in
|
||||
edx-milestones==0.3.0 # via -r requirements/edx/base.txt
|
||||
edx-opaque-keys[django]==2.1.1 # via -r requirements/edx/base.txt, edx-bulk-grades, edx-ccx-keys, edx-completion, edx-drf-extensions, edx-enterprise, edx-milestones, edx-organizations, edx-proctoring, edx-user-state-client, edx-when, lti-consumer-xblock, xmodule
|
||||
edx-organizations==6.5.0 # via -r requirements/edx/base.txt
|
||||
edx-organizations==6.6.0 # via -r requirements/edx/base.txt
|
||||
edx-proctoring-proctortrack==1.0.5 # via -r requirements/edx/base.txt
|
||||
edx-proctoring==2.5.5 # via -r requirements/edx/base.txt, edx-proctoring-proctortrack
|
||||
edx-rbac==1.3.3 # via -r requirements/edx/base.txt, edx-enterprise
|
||||
|
||||
Reference in New Issue
Block a user