[BD-14] Migrate all environments to use database-backed organizations (#25153)
* Install `organizations` app into LMS and Studio non-optionally. * Add toggle `ORGANIZATIONS_AUTOCREATE` to Studio. * Remove the `FEATURES["ORGANIZATIONS_APP"]` toggle. * Use the new `organizations.api.ensure_organization` function to either validate or get-or-create organizations, depending on the value of `ORGANIZATIONS_AUTOCREATE`, when creating course runs and V2 content libraries. We'll soon use it for V1 content libraries as well. * Remove the `util.organizations_helpers` wrapper layer that had to exist because `organizations` was an optional app. * Add `.get_library_keys()` method to the Split modulestore. * Add Studio management command for backfilling organizations tables (`backfill_orgs_and_org_courses`). For full details, see https://github.com/edx/edx-organizations/blob/master/docs/decisions/0001-phase-in-db-backed-organizations-to-all.rst TNL-7646
This commit is contained in:
@@ -7,15 +7,20 @@ import datetime
|
||||
|
||||
import ddt
|
||||
import six
|
||||
from django.test import override_settings
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls import reverse
|
||||
from mock import patch
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from organizations.api import (
|
||||
add_organization,
|
||||
get_organization_by_short_name,
|
||||
get_course_organizations
|
||||
)
|
||||
from organizations.exceptions import InvalidOrganizationException
|
||||
|
||||
from cms.djangoapps.contentstore.tests.utils import AjaxEnabledTestClient, parse_json
|
||||
from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from common.djangoapps.util.organizations_helpers import add_organization, get_course_organizations
|
||||
from xmodule.course_module import CourseFields
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
@@ -66,7 +71,6 @@ class TestCourseListing(ModuleStoreTestCase):
|
||||
self.client.logout()
|
||||
ModuleStoreTestCase.tearDown(self)
|
||||
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
|
||||
def test_rerun(self):
|
||||
"""
|
||||
Just testing the functionality the view handler adds over the tasks tested in test_clone_course
|
||||
@@ -114,13 +118,15 @@ class TestCourseListing(ModuleStoreTestCase):
|
||||
course = self.store.get_course(new_course_key)
|
||||
self.assertTrue(course.cert_html_view_enabled)
|
||||
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': False})
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_course_creation_without_org_app_enabled(self, store):
|
||||
def test_course_creation_for_unknown_organization_relaxed(self, store):
|
||||
"""
|
||||
Tests course creation workflow should not create course to org
|
||||
link if organizations_app is not enabled.
|
||||
Tests that when ORGANIZATIONS_AUTOCREATE is True,
|
||||
creating a course-run with an unknown org slug will create an organization
|
||||
and organization-course linkage in the system.
|
||||
"""
|
||||
with self.assertRaises(InvalidOrganizationException):
|
||||
get_organization_by_short_name("orgX")
|
||||
with modulestore().default_store(store):
|
||||
response = self.client.ajax_post(self.course_create_rerun_url, {
|
||||
'org': 'orgX',
|
||||
@@ -129,17 +135,19 @@ class TestCourseListing(ModuleStoreTestCase):
|
||||
'run': '2015_T2'
|
||||
})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIsNotNone(get_organization_by_short_name("orgX"))
|
||||
data = parse_json(response)
|
||||
new_course_key = CourseKey.from_string(data['course_key'])
|
||||
course_orgs = get_course_organizations(new_course_key)
|
||||
self.assertEqual(course_orgs, [])
|
||||
self.assertEqual(len(course_orgs), 1)
|
||||
self.assertEqual(course_orgs[0]['short_name'], 'orgX')
|
||||
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_course_creation_with_org_not_in_system(self, store):
|
||||
@override_settings(ORGANIZATIONS_AUTOCREATE=False)
|
||||
def test_course_creation_for_unknown_organization_strict(self, store):
|
||||
"""
|
||||
Tests course creation workflow when course organization does not exist
|
||||
in system.
|
||||
Tests that when ORGANIZATIONS_AUTOCREATE is False,
|
||||
creating a course-run with an unknown org slug will raise a validation error.
|
||||
"""
|
||||
with modulestore().default_store(store):
|
||||
response = self.client.ajax_post(self.course_create_rerun_url, {
|
||||
@@ -149,12 +157,13 @@ class TestCourseListing(ModuleStoreTestCase):
|
||||
'run': '2015_T2'
|
||||
})
|
||||
self.assertEqual(response.status_code, 400)
|
||||
with self.assertRaises(InvalidOrganizationException):
|
||||
get_organization_by_short_name("orgX")
|
||||
data = parse_json(response)
|
||||
self.assertIn(u'Organization you selected does not exist in the system', data['error'])
|
||||
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_course_creation_with_org_in_system(self, store):
|
||||
@ddt.data(True, False)
|
||||
def test_course_creation_for_known_organization(self, organizations_autocreate):
|
||||
"""
|
||||
Tests course creation workflow when course organization exist in system.
|
||||
"""
|
||||
@@ -163,7 +172,7 @@ class TestCourseListing(ModuleStoreTestCase):
|
||||
'short_name': 'orgX',
|
||||
'description': 'Testing Organization Description',
|
||||
})
|
||||
with modulestore().default_store(store):
|
||||
with override_settings(ORGANIZATIONS_AUTOCREATE=organizations_autocreate):
|
||||
response = self.client.ajax_post(self.course_create_rerun_url, {
|
||||
'org': 'orgX',
|
||||
'number': 'CS101',
|
||||
|
||||
@@ -127,7 +127,7 @@ class RerunCourseTaskTestCase(CourseTestCase):
|
||||
old_course_id = str(old_course_key)
|
||||
new_course_id = str(new_course_key)
|
||||
|
||||
organization = OrganizationFactory()
|
||||
organization = OrganizationFactory(short_name=old_course_key.org)
|
||||
OrganizationCourse.objects.create(course_id=old_course_id, organization=organization)
|
||||
|
||||
restricted_course = RestrictedCourse.objects.create(course_key=self.course.id)
|
||||
|
||||
Reference in New Issue
Block a user