Skip to content
Snippets Groups Projects
Commit 599d6637 authored by Kyle McCormick's avatar Kyle McCormick Committed by Kyle McCormick
Browse files

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
parent 492ce7f2
Branches
Tags
No related merge requests found
......@@ -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
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment