From 43698fff0ad36d21117ccba62d2d51bf4e2a5357 Mon Sep 17 00:00:00 2001 From: stvn Date: Thu, 8 Apr 2021 15:02:18 -0700 Subject: [PATCH] refactor: Move get_course_by_id helper from LMS to core This helper is used by the LMS, CMS, _and_ `openedx.core`, so let's move it to `openedx.core` to reduce import complexity. The following files no longer import from LMS: - cms/djangoapps/contentstore/management/commands/edit_course_tabs.py - lms/djangoapps/ccx/migrations/0006_set_display_name_as_override.py - openedx/core/djangoapps/ccxcon/api.py - openedx/core/djangoapps/verified_track_content/models.py - openedx/features/course_experience/plugins.py Note: The LTI XBlock has a dependency on this import path (!?); a fix can be found here [1]. - [1] https://github.com/edx/xblock-lti-consumer/pull/154 --- .../management/commands/edit_course_tabs.py | 2 +- lms/djangoapps/bulk_email/views.py | 2 +- lms/djangoapps/ccx/api/v0/tests/test_views.py | 7 ++++--- lms/djangoapps/ccx/api/v0/views.py | 3 ++- .../0003_add_master_course_staff_in_ccx.py | 2 +- .../0005_change_ccx_coach_to_staff.py | 2 +- .../0006_set_display_name_as_override.py | 2 +- lms/djangoapps/ccx/tests/test_overrides.py | 2 +- lms/djangoapps/ccx/tests/test_views.py | 2 +- lms/djangoapps/ccx/utils.py | 2 +- lms/djangoapps/ccx/views.py | 2 +- .../management/commands/fix_ungraded_certs.py | 4 ++-- lms/djangoapps/certificates/views/webview.py | 2 +- lms/djangoapps/course_wiki/views.py | 2 +- lms/djangoapps/courseware/courses.py | 17 +---------------- lms/djangoapps/courseware/tests/test_courses.py | 2 +- lms/djangoapps/courseware/tests/test_tabs.py | 2 +- .../django_comment_client/base/views.py | 3 ++- .../discussion/django_comment_client/utils.py | 6 +++--- lms/djangoapps/experiments/views.py | 3 ++- .../grades/rest_api/v1/gradebook_views.py | 2 +- lms/djangoapps/instructor/views/api.py | 3 ++- .../instructor/views/instructor_dashboard.py | 3 ++- .../instructor_task/tasks_helper/grades.py | 2 +- .../tasks_helper/module_state.py | 3 ++- openedx/core/djangoapps/ccxcon/api.py | 2 +- .../core/djangoapps/course_groups/cohorts.py | 7 ++++--- openedx/core/djangoapps/courseware_api/views.py | 3 ++- .../djangoapps/verified_track_content/models.py | 2 +- openedx/core/lib/courses.py | 17 +++++++++++++++++ openedx/features/course_experience/plugins.py | 2 +- 31 files changed, 63 insertions(+), 52 deletions(-) diff --git a/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py b/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py index 7f38b3d978..feb624ce49 100644 --- a/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py +++ b/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py @@ -13,7 +13,7 @@ from django.core.management.base import BaseCommand, CommandError from opaque_keys.edx.keys import CourseKey from cms.djangoapps.contentstore.views import tabs -from lms.djangoapps.courseware.courses import get_course_by_id +from openedx.core.lib.courses import get_course_by_id from .prompt import query_yes_no diff --git a/lms/djangoapps/bulk_email/views.py b/lms/djangoapps/bulk_email/views.py index a1cc7e9513..528baf97b5 100644 --- a/lms/djangoapps/bulk_email/views.py +++ b/lms/djangoapps/bulk_email/views.py @@ -12,8 +12,8 @@ from opaque_keys.edx.keys import CourseKey from common.djangoapps.edxmako.shortcuts import render_to_response from lms.djangoapps.bulk_email.models import Optout -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.discussion.notification_prefs.views import UsernameCipher, UsernameDecryptionException +from openedx.core.lib.courses import get_course_by_id log = logging.getLogger(__name__) diff --git a/lms/djangoapps/ccx/api/v0/tests/test_views.py b/lms/djangoapps/ccx/api/v0/tests/test_views.py index e0528eabe5..e36f20eba4 100644 --- a/lms/djangoapps/ccx/api/v0/tests/test_views.py +++ b/lms/djangoapps/ccx/api/v0/tests/test_views.py @@ -32,6 +32,7 @@ from lms.djangoapps.ccx.utils import ccx_course as ccx_course_cm from lms.djangoapps.courseware import courses from lms.djangoapps.instructor.access import allow_access, list_with_level from lms.djangoapps.instructor.enrollment import enroll_email, get_email_params +from openedx.core.lib.courses import get_course_by_id USER_PASSWORD = 'test' @@ -422,7 +423,7 @@ class CcxListTest(CcxRestApiTest): self.mstore.update_item(self.course, self.coach.id) # case with deprecated master_course_id - with mock.patch('lms.djangoapps.courseware.courses.get_course_by_id', autospec=True) as mocked: + with mock.patch('lms.djangoapps.ccx.api.v0.views.get_course_by_id', autospec=True) as mocked: mocked.return_value.id.deprecated = True resp = self.client.post(self.list_url, data, format='json', HTTP_AUTHORIZATION=self.auth) @@ -594,7 +595,7 @@ class CcxListTest(CcxRestApiTest): coach_role_on_master_course = CourseCcxCoachRole(self.master_course_key) assert coach_role_on_master_course.has_user(self.coach) # check that the coach has been enrolled in the ccx - ccx_course_object = courses.get_course_by_id(course_key) + ccx_course_object = get_course_by_id(course_key) assert CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=self.coach).exists() # check that an email has been sent to the coach assert len(outbox) == 1 @@ -1053,7 +1054,7 @@ class CcxDetailTest(CcxRestApiTest): coach_role_on_master_course = CourseCcxCoachRole(self.master_course_key) assert coach_role_on_master_course.has_user(new_coach) # check that the coach has been enrolled in the ccx - ccx_course_object = courses.get_course_by_id(self.ccx_key) + ccx_course_object = get_course_by_id(self.ccx_key) assert CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=new_coach).exists() # check that an email has been sent to the coach assert len(outbox) == 1 diff --git a/lms/djangoapps/ccx/api/v0/views.py b/lms/djangoapps/ccx/api/v0/views.py index c698c645c0..19477ae4e7 100644 --- a/lms/djangoapps/ccx/api/v0/views.py +++ b/lms/djangoapps/ccx/api/v0/views.py @@ -28,6 +28,7 @@ from lms.djangoapps.courseware import courses from lms.djangoapps.instructor.enrollment import enroll_email, get_email_params from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.lib.api import authentication, permissions +from openedx.core.lib.courses import get_course_by_id from xmodule.modulestore.django import SignalHandler from .paginators import CCXAPIPagination @@ -70,7 +71,7 @@ def get_valid_course(course_id, is_ccx=False, advanced_course_check=False): if not is_ccx: try: - course_object = courses.get_course_by_id(course_key) + course_object = get_course_by_id(course_key) except Http404: log.info('Master Course with ID "%s" not found', course_id) return None, None, 'course_id_does_not_exist', status.HTTP_404_NOT_FOUND diff --git a/lms/djangoapps/ccx/migrations/0003_add_master_course_staff_in_ccx.py b/lms/djangoapps/ccx/migrations/0003_add_master_course_staff_in_ccx.py index 18f555b887..5a2d7e42ec 100644 --- a/lms/djangoapps/ccx/migrations/0003_add_master_course_staff_in_ccx.py +++ b/lms/djangoapps/ccx/migrations/0003_add_master_course_staff_in_ccx.py @@ -5,8 +5,8 @@ from ccx_keys.locator import CCXLocator from django.db import migrations from django.http import Http404 -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.ccx.utils import add_master_course_staff_to_ccx, remove_master_course_staff_from_ccx +from openedx.core.lib.courses import get_course_by_id log = logging.getLogger("edx.ccx") diff --git a/lms/djangoapps/ccx/migrations/0005_change_ccx_coach_to_staff.py b/lms/djangoapps/ccx/migrations/0005_change_ccx_coach_to_staff.py index a7b5e57695..f808192308 100644 --- a/lms/djangoapps/ccx/migrations/0005_change_ccx_coach_to_staff.py +++ b/lms/djangoapps/ccx/migrations/0005_change_ccx_coach_to_staff.py @@ -6,8 +6,8 @@ from django.contrib.auth.models import User from django.db import migrations from django.http import Http404 -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.instructor.access import allow_access, revoke_access +from openedx.core.lib.courses import get_course_by_id log = logging.getLogger("edx.ccx") diff --git a/lms/djangoapps/ccx/migrations/0006_set_display_name_as_override.py b/lms/djangoapps/ccx/migrations/0006_set_display_name_as_override.py index 2dbc3b2b02..f37c9dc321 100644 --- a/lms/djangoapps/ccx/migrations/0006_set_display_name_as_override.py +++ b/lms/djangoapps/ccx/migrations/0006_set_display_name_as_override.py @@ -6,7 +6,7 @@ import logging from django.db import migrations from django.http import Http404 -from lms.djangoapps.courseware.courses import get_course_by_id +from openedx.core.lib.courses import get_course_by_id log = logging.getLogger(__name__) diff --git a/lms/djangoapps/ccx/tests/test_overrides.py b/lms/djangoapps/ccx/tests/test_overrides.py index 3545be00e6..be60dc40d4 100644 --- a/lms/djangoapps/ccx/tests/test_overrides.py +++ b/lms/djangoapps/ccx/tests/test_overrides.py @@ -15,10 +15,10 @@ from common.djangoapps.student.tests.factories import AdminFactory from lms.djangoapps.ccx.models import CustomCourseForEdX from lms.djangoapps.ccx.overrides import override_field_for_ccx from lms.djangoapps.ccx.tests.utils import flatten, iter_blocks -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.courseware.field_overrides import OverrideFieldData from lms.djangoapps.courseware.tests.test_field_overrides import inject_field_overrides from lms.djangoapps.courseware.testutils import FieldOverrideTestMixin +from openedx.core.lib.courses import get_course_by_id from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory diff --git a/lms/djangoapps/ccx/tests/test_views.py b/lms/djangoapps/ccx/tests/test_views.py index c5086d736a..23d6345702 100644 --- a/lms/djangoapps/ccx/tests/test_views.py +++ b/lms/djangoapps/ccx/tests/test_views.py @@ -31,7 +31,6 @@ from lms.djangoapps.ccx.tests.factories import CcxFactory from lms.djangoapps.ccx.tests.utils import CcxTestCase, flatten from lms.djangoapps.ccx.utils import ccx_course, is_email from lms.djangoapps.ccx.views import get_date -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.courseware.tabs import get_course_tab_list from lms.djangoapps.courseware.tests.factories import StudentModuleFactory from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase @@ -42,6 +41,7 @@ from lms.djangoapps.instructor.access import allow_access, list_with_level from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.django_comment_common.models import FORUM_ROLE_ADMINISTRATOR from openedx.core.djangoapps.django_comment_common.utils import are_permissions_roles_seeded +from openedx.core.lib.courses import get_course_by_id from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ( diff --git a/lms/djangoapps/ccx/utils.py b/lms/djangoapps/ccx/utils.py index 08f307c1fd..68f2d8326a 100644 --- a/lms/djangoapps/ccx/utils.py +++ b/lms/djangoapps/ccx/utils.py @@ -22,12 +22,12 @@ from common.djangoapps.student.roles import CourseCcxCoachRole, CourseInstructor from lms.djangoapps.ccx.custom_exception import CCXUserValidationException from lms.djangoapps.ccx.models import CustomCourseForEdX from lms.djangoapps.ccx.overrides import get_override_for_ccx -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.instructor.access import allow_access, list_with_level, revoke_access from lms.djangoapps.instructor.enrollment import enroll_email, get_email_params, unenroll_email from lms.djangoapps.instructor.views.api import _split_input_list from lms.djangoapps.instructor.views.tools import get_student_from_identifier from openedx.core.djangoapps.content.course_overviews.models import CourseOverview +from openedx.core.lib.courses import get_course_by_id log = logging.getLogger("edx.ccx") diff --git a/lms/djangoapps/ccx/views.py b/lms/djangoapps/ccx/views.py index 99a3fc2a18..c628b30062 100644 --- a/lms/djangoapps/ccx/views.py +++ b/lms/djangoapps/ccx/views.py @@ -49,13 +49,13 @@ from lms.djangoapps.ccx.utils import ( get_enrollment_action_and_identifiers, parse_date ) -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.courseware.field_overrides import disable_overrides from lms.djangoapps.grades.api import CourseGradeFactory from lms.djangoapps.instructor.enrollment import enroll_email, get_email_params from lms.djangoapps.instructor.views.gradebook_api import get_grade_book_page from openedx.core.djangoapps.django_comment_common.models import FORUM_ROLE_ADMINISTRATOR, assign_role from openedx.core.djangoapps.django_comment_common.utils import seed_permissions_roles +from openedx.core.lib.courses import get_course_by_id from xmodule.modulestore.django import SignalHandler log = logging.getLogger(__name__) diff --git a/lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py b/lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py index 341be951c5..3a30894400 100644 --- a/lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py +++ b/lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py @@ -9,8 +9,8 @@ from django.core.management.base import BaseCommand from lms.djangoapps.certificates.api import can_generate_certificate_task from lms.djangoapps.certificates.models import GeneratedCertificate -from lms.djangoapps.courseware import courses from lms.djangoapps.grades.api import CourseGradeFactory +from openedx.core.lib.courses import get_course_by_id log = logging.getLogger(__name__) @@ -50,7 +50,7 @@ class Command(BaseCommand): ungraded = GeneratedCertificate.objects.filter( course_id__exact=course_id ).filter(grade__exact='') - course = courses.get_course_by_id(course_id) + course = get_course_by_id(course_id) for cert in ungraded: if can_generate_certificate_task(cert.user, course_id): log.info(f'{course_id} is using V2 certificates. Certificate will not be regraded for user ' diff --git a/lms/djangoapps/certificates/views/webview.py b/lms/djangoapps/certificates/views/webview.py index 037a932124..bf16ee968c 100644 --- a/lms/djangoapps/certificates/views/webview.py +++ b/lms/djangoapps/certificates/views/webview.py @@ -42,12 +42,12 @@ from lms.djangoapps.certificates.models import ( ) from lms.djangoapps.certificates.permissions import PREVIEW_CERTIFICATES from lms.djangoapps.certificates.utils import emit_certificate_event, get_certificate_url -from lms.djangoapps.courseware.courses import get_course_by_id from openedx.core.djangoapps.catalog.utils import get_course_run_details from openedx.core.djangoapps.certificates.api import certificates_viewable_for_course, display_date_for_certificate from openedx.core.djangoapps.lang_pref.api import get_closest_released_language from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.lib.courses import course_image_url +from openedx.core.lib.courses import get_course_by_id log = logging.getLogger(__name__) _ = translation.ugettext diff --git a/lms/djangoapps/course_wiki/views.py b/lms/djangoapps/course_wiki/views.py index 0236b1a932..2affa2ce13 100644 --- a/lms/djangoapps/course_wiki/views.py +++ b/lms/djangoapps/course_wiki/views.py @@ -14,9 +14,9 @@ from wiki.core.exceptions import NoRootURL from wiki.models import Article, URLPath from lms.djangoapps.course_wiki.utils import course_wiki_slug -from lms.djangoapps.courseware.courses import get_course_by_id from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangolib.markup import Text +from openedx.core.lib.courses import get_course_by_id from openedx.features.enterprise_support.api import data_sharing_consent_required log = logging.getLogger(__name__) diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index 9f9bfefbdc..6dbc9d77d7 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -55,6 +55,7 @@ from openedx.core.djangoapps.content.course_overviews.models import CourseOvervi from openedx.core.djangoapps.enrollments.api import get_course_enrollment_details from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.lib.api.view_utils import LazySequence +from openedx.core.lib.courses import get_course_by_id from openedx.features.course_duration_limits.access import AuditExpiredError from openedx.features.course_experience import RELATIVE_DATES_FLAG from openedx.features.course_experience.utils import is_block_structure_complete_for_assignments @@ -91,22 +92,6 @@ def get_course(course_id, depth=0): return course -def get_course_by_id(course_key, depth=0): - """ - Given a course id, return the corresponding course descriptor. - - If such a course does not exist, raises a 404. - - depth: The number of levels of children for the modulestore to cache. None means infinite depth - """ - with modulestore().bulk_operations(course_key): - course = modulestore().get_course(course_key, depth=depth) - if course: - return course - else: - raise Http404("Course not found: {}.".format(str(course_key))) - - def get_course_with_access(user, action, course_key, depth=0, check_if_enrolled=False, check_survey_complete=True, check_if_authenticated=False): # lint-amnesty, pylint: disable=line-too-long """ Given a course_key, look up the corresponding course descriptor, diff --git a/lms/djangoapps/courseware/tests/test_courses.py b/lms/djangoapps/courseware/tests/test_courses.py index 9cb46095d1..e5647b59c1 100644 --- a/lms/djangoapps/courseware/tests/test_courses.py +++ b/lms/djangoapps/courseware/tests/test_courses.py @@ -25,7 +25,6 @@ from lms.djangoapps.courseware.courses import ( get_cms_course_link, get_course_about_section, get_course_assignments, - get_course_by_id, get_course_chapter_ids, get_course_info_section, get_course_overview_with_access, @@ -38,6 +37,7 @@ from lms.djangoapps.courseware.module_render import get_module_for_descriptor from lms.djangoapps.courseware.courseware_access_exception import CoursewareAccessException from openedx.core.djangolib.testing.utils import get_mock_request from openedx.core.lib.courses import course_image_url +from openedx.core.lib.courses import get_course_by_id from common.djangoapps.student.tests.factories import UserFactory from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import _get_modulestore_branch_setting, modulestore diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py index 7e76b6bfa5..58490fdd39 100644 --- a/lms/djangoapps/courseware/tests/test_tabs.py +++ b/lms/djangoapps/courseware/tests/test_tabs.py @@ -11,7 +11,6 @@ from django.urls import reverse from milestones.tests.utils import MilestonesTestCaseMixin from edx_toggles.toggles.testutils import override_waffle_flag -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.courseware.tabs import ( CourseInfoTab, CoursewareTab, @@ -25,6 +24,7 @@ from lms.djangoapps.courseware.tests.factories import InstructorFactory, StaffFa from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase from lms.djangoapps.courseware.views.views import StaticCourseTabView, get_static_tab_fragment from openedx.core.djangolib.testing.utils import get_mock_request +from openedx.core.lib.courses import get_course_by_id from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.tests.factories import UserFactory diff --git a/lms/djangoapps/discussion/django_comment_client/base/views.py b/lms/djangoapps/discussion/django_comment_client/base/views.py index 3293dd6a4d..9422238f8e 100644 --- a/lms/djangoapps/discussion/django_comment_client/base/views.py +++ b/lms/djangoapps/discussion/django_comment_client/base/views.py @@ -21,7 +21,7 @@ import lms.djangoapps.discussion.django_comment_client.settings as cc_settings import openedx.core.djangoapps.django_comment_common.comment_client as cc from common.djangoapps.util.file import store_uploaded_file from lms.djangoapps.courseware.access import has_access -from lms.djangoapps.courseware.courses import get_course_by_id, get_course_overview_with_access, get_course_with_access +from lms.djangoapps.courseware.courses import get_course_overview_with_access, get_course_with_access from lms.djangoapps.courseware.exceptions import CourseAccessRedirect from lms.djangoapps.discussion.django_comment_client.permissions import ( check_permissions_by_view, @@ -55,6 +55,7 @@ from openedx.core.djangoapps.django_comment_common.signals import ( thread_voted ) from openedx.core.djangoapps.django_comment_common.utils import ThreadContext +from openedx.core.lib.courses import get_course_by_id log = logging.getLogger(__name__) diff --git a/lms/djangoapps/discussion/django_comment_client/utils.py b/lms/djangoapps/discussion/django_comment_client/utils.py index 6d8fae21c6..2047bdd05b 100644 --- a/lms/djangoapps/discussion/django_comment_client/utils.py +++ b/lms/djangoapps/discussion/django_comment_client/utils.py @@ -17,7 +17,6 @@ from pytz import UTC from common.djangoapps.student.models import get_user_by_username_or_email from common.djangoapps.student.roles import GlobalStaff -from lms.djangoapps.courseware import courses from lms.djangoapps.courseware.access import has_access from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY from lms.djangoapps.discussion.django_comment_client.permissions import ( @@ -36,6 +35,7 @@ from openedx.core.djangoapps.django_comment_common.models import ( ) from openedx.core.djangoapps.django_comment_common.utils import get_course_discussion_settings from openedx.core.lib.cache_utils import request_cached +from openedx.core.lib.courses import get_course_by_id from xmodule.modulestore.django import modulestore from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID from xmodule.partitions.partitions_service import PartitionService @@ -924,7 +924,7 @@ def is_commentable_divided(course_key, commentable_id, course_discussion_setting if not course_discussion_settings: course_discussion_settings = get_course_discussion_settings(course_key) - course = courses.get_course_by_id(course_key) + course = get_course_by_id(course_key) if not course_discussion_division_enabled(course_discussion_settings) or get_team(commentable_id): # this is the easy case :) @@ -1034,7 +1034,7 @@ def get_group_names_by_id(course_discussion_settings): division_scheme = _get_course_division_scheme(course_discussion_settings) course_key = course_discussion_settings.course_id if division_scheme == CourseDiscussionSettings.COHORT: - return get_cohort_names(courses.get_course_by_id(course_key)) + return get_cohort_names(get_course_by_id(course_key)) elif division_scheme == CourseDiscussionSettings.ENROLLMENT_TRACK: # We negate the group_ids from dynamic partitions so that they will not conflict # with cohort IDs (which are an auto-incrementing integer field, starting at 1). diff --git a/lms/djangoapps/experiments/views.py b/lms/djangoapps/experiments/views.py index 6382fccd7d..2577eacee3 100644 --- a/lms/djangoapps/experiments/views.py +++ b/lms/djangoapps/experiments/views.py @@ -22,6 +22,7 @@ from lms.djangoapps.experiments.models import ExperimentData, ExperimentKeyValue from lms.djangoapps.experiments.permissions import IsStaffOrOwner, IsStaffOrReadOnly, IsStaffOrReadOnlyForSelf from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context from openedx.core.djangoapps.cors_csrf.authentication import SessionAuthenticationCrossDomainCsrf +from openedx.core.lib.courses import get_course_by_id User = get_user_model() # pylint: disable=invalid-name @@ -107,7 +108,7 @@ class UserMetaDataView(APIView): # lint-amnesty, pylint: disable=missing-class- return JsonResponse({'message': message}, status=404) try: - course = courses.get_course_by_id(CourseKey.from_string(course_id)) + course = get_course_by_id(CourseKey.from_string(course_id)) except Http404: message = "Provided course is not found" return JsonResponse({'message': message}, status=404) diff --git a/lms/djangoapps/grades/rest_api/v1/gradebook_views.py b/lms/djangoapps/grades/rest_api/v1/gradebook_views.py index 5d466b6078..de00adc7b0 100644 --- a/lms/djangoapps/grades/rest_api/v1/gradebook_views.py +++ b/lms/djangoapps/grades/rest_api/v1/gradebook_views.py @@ -31,7 +31,6 @@ from common.djangoapps.track.event_transaction_utils import ( ) from common.djangoapps.util.date_utils import to_timestamp from lms.djangoapps.course_blocks.api import get_course_blocks -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.grades.api import CourseGradeFactory, clear_prefetched_course_and_subsection_grades from lms.djangoapps.grades.api import constants as grades_constants from lms.djangoapps.grades.api import context as grades_context @@ -66,6 +65,7 @@ from openedx.core.lib.api.view_utils import ( view_auth_classes ) from openedx.core.lib.cache_utils import request_cached +from openedx.core.lib.courses import get_course_by_id from xmodule.modulestore.django import modulestore from xmodule.util.misc import get_default_short_labeler diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 959f8cce3c..45d5b4b0af 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -74,7 +74,7 @@ from lms.djangoapps.certificates.models import ( CertificateStatuses ) from lms.djangoapps.courseware.access import has_access -from lms.djangoapps.courseware.courses import get_course_by_id, get_course_with_access +from lms.djangoapps.courseware.courses import get_course_with_access from lms.djangoapps.courseware.models import StudentModule from lms.djangoapps.discussion.django_comment_client.utils import ( get_course_discussion_settings, @@ -114,6 +114,7 @@ from openedx.core.djangoapps.user_api.preferences.api import get_user_preference from openedx.core.djangolib.markup import HTML, Text from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin +from openedx.core.lib.courses import get_course_by_id from xmodule.modulestore.django import modulestore from .. import permissions diff --git a/lms/djangoapps/instructor/views/instructor_dashboard.py b/lms/djangoapps/instructor/views/instructor_dashboard.py index 1832dbcc2b..87772c6b60 100644 --- a/lms/djangoapps/instructor/views/instructor_dashboard.py +++ b/lms/djangoapps/instructor/views/instructor_dashboard.py @@ -48,7 +48,7 @@ from lms.djangoapps.certificates.models import ( GeneratedCertificate ) from lms.djangoapps.courseware.access import has_access -from lms.djangoapps.courseware.courses import get_course_by_id, get_studio_url +from lms.djangoapps.courseware.courses import get_studio_url from lms.djangoapps.courseware.module_render import get_module_by_usage_id from lms.djangoapps.discussion.django_comment_client.utils import available_division_schemes, has_forum_access from lms.djangoapps.grades.api import is_writable_gradebook_enabled @@ -57,6 +57,7 @@ from openedx.core.djangoapps.django_comment_common.models import FORUM_ROLE_ADMI from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.verified_track_content.models import VerifiedTrackCohortedCourse from openedx.core.djangolib.markup import HTML, Text +from openedx.core.lib.courses import get_course_by_id from openedx.core.lib.url_utils import quote_slashes from openedx.core.lib.xblock_utils import wrap_xblock from xmodule.html_module import HtmlBlock diff --git a/lms/djangoapps/instructor_task/tasks_helper/grades.py b/lms/djangoapps/instructor_task/tasks_helper/grades.py index 2f75a32bd8..59e7e2972c 100644 --- a/lms/djangoapps/instructor_task/tasks_helper/grades.py +++ b/lms/djangoapps/instructor_task/tasks_helper/grades.py @@ -21,7 +21,6 @@ from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.roles import BulkRoleCache from lms.djangoapps.certificates.models import CertificateWhitelist, GeneratedCertificate, certificate_info_for_user from lms.djangoapps.course_blocks.api import get_course_blocks -from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient from lms.djangoapps.grades.api import CourseGradeFactory from lms.djangoapps.grades.api import context as grades_context @@ -39,6 +38,7 @@ from openedx.core.djangoapps.content.block_structure.api import get_course_in_ca from openedx.core.djangoapps.course_groups.cohorts import bulk_cache_cohorts, get_cohort, is_course_cohorted from openedx.core.djangoapps.user_api.course_tag.api import BulkCourseTags from openedx.core.lib.cache_utils import get_cache +from openedx.core.lib.courses import get_course_by_id from xmodule.modulestore.django import modulestore from xmodule.partitions.partitions_service import PartitionService from xmodule.split_test_module import get_split_user_partitions diff --git a/lms/djangoapps/instructor_task/tasks_helper/module_state.py b/lms/djangoapps/instructor_task/tasks_helper/module_state.py index 6cad0408bf..35d4213947 100644 --- a/lms/djangoapps/instructor_task/tasks_helper/module_state.py +++ b/lms/djangoapps/instructor_task/tasks_helper/module_state.py @@ -17,11 +17,12 @@ from common.djangoapps.student.models import get_user_by_username_or_email from common.djangoapps.track.event_transaction_utils import create_new_event_transaction_id, set_event_transaction_type from common.djangoapps.track.views import task_track from common.djangoapps.util.db import outer_atomic -from lms.djangoapps.courseware.courses import get_course_by_id, get_problems_in_section +from lms.djangoapps.courseware.courses import get_problems_in_section from lms.djangoapps.courseware.model_data import DjangoKeyValueStore, FieldDataCache from lms.djangoapps.courseware.models import StudentModule from lms.djangoapps.courseware.module_render import get_module_for_descriptor_internal from lms.djangoapps.grades.api import events as grades_events +from openedx.core.lib.courses import get_course_by_id from xmodule.modulestore.django import modulestore from ..exceptions import UpdateProblemModuleStateError diff --git a/openedx/core/djangoapps/ccxcon/api.py b/openedx/core/djangoapps/ccxcon/api.py index 7be3b56751..26ba5cd05c 100644 --- a/openedx/core/djangoapps/ccxcon/api.py +++ b/openedx/core/djangoapps/ccxcon/api.py @@ -13,8 +13,8 @@ from oauthlib.oauth2 import BackendApplicationClient from requests_oauthlib import OAuth2Session from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED -from lms.djangoapps.courseware.courses import get_course_by_id from openedx.core.djangoapps.models.course_details import CourseDetails +from openedx.core.lib.courses import get_course_by_id from common.djangoapps.student.models import anonymous_id_for_user from common.djangoapps.student.roles import CourseInstructorRole diff --git a/openedx/core/djangoapps/course_groups/cohorts.py b/openedx/core/djangoapps/course_groups/cohorts.py index 87b6ce343d..2ce99d046a 100644 --- a/openedx/core/djangoapps/course_groups/cohorts.py +++ b/openedx/core/djangoapps/course_groups/cohorts.py @@ -20,6 +20,7 @@ from eventtracking import tracker from lms.djangoapps.courseware import courses from openedx.core.lib.cache_utils import request_cached +from openedx.core.lib.courses import get_course_by_id from common.djangoapps.student.models import get_user_by_username_or_email from .models import ( @@ -387,7 +388,7 @@ def add_cohort(course_key, name, assignment_type): raise ValueError(_("You cannot create two cohorts with the same name")) try: - course = courses.get_course_by_id(course_key) + course = get_course_by_id(course_key) except Http404: raise ValueError("Invalid course_key") # lint-amnesty, pylint: disable=raise-missing-from @@ -593,7 +594,7 @@ def _get_course_cohort_settings(course_key): try: course_cohort_settings = CourseCohortsSettings.objects.get(course_id=course_key) except CourseCohortsSettings.DoesNotExist: - course = courses.get_course_by_id(course_key) + course = get_course_by_id(course_key) course_cohort_settings = migrate_cohort_settings(course) return course_cohort_settings @@ -608,7 +609,7 @@ def get_legacy_discussion_settings(course_key): # lint-amnesty, pylint: disable 'always_cohort_inline_discussions': course_cohort_settings.always_cohort_inline_discussions } except CourseCohortsSettings.DoesNotExist: - course = courses.get_course_by_id(course_key) + course = get_course_by_id(course_key) return _get_cohort_settings_from_modulestore(course) diff --git a/openedx/core/djangoapps/courseware_api/views.py b/openedx/core/djangoapps/courseware_api/views.py index 9d946cd6ac..a707de14c9 100644 --- a/openedx/core/djangoapps/courseware_api/views.py +++ b/openedx/core/djangoapps/courseware_api/views.py @@ -29,7 +29,7 @@ from lms.djangoapps.courseware.access_response import ( CoursewareMicrofrontendDisabledAccessError, ) from lms.djangoapps.courseware.context_processor import user_timezone_locale_prefs -from lms.djangoapps.courseware.courses import check_course_access, get_course_by_id +from lms.djangoapps.courseware.courses import check_course_access from lms.djangoapps.courseware.masquerade import setup_masquerade from lms.djangoapps.courseware.module_render import get_module_by_usage_id from lms.djangoapps.courseware.tabs import get_course_tab_list @@ -39,6 +39,7 @@ from lms.djangoapps.grades.api import CourseGradeFactory from lms.djangoapps.verify_student.services import IDVerificationService from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin +from openedx.core.lib.courses import get_course_by_id from openedx.core.djangoapps.programs.utils import ProgramProgressMeter from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG from openedx.features.content_type_gating.models import ContentTypeGatingConfig diff --git a/openedx/core/djangoapps/verified_track_content/models.py b/openedx/core/djangoapps/verified_track_content/models.py index 1cf6bfad77..670416ef0c 100644 --- a/openedx/core/djangoapps/verified_track_content/models.py +++ b/openedx/core/djangoapps/verified_track_content/models.py @@ -14,7 +14,6 @@ from django.utils.translation import ugettext_lazy from edx_django_utils.cache import RequestCache from opaque_keys.edx.django.models import CourseKeyField -from lms.djangoapps.courseware.courses import get_course_by_id from openedx.core.djangoapps.course_groups.cohorts import ( CourseCohort, get_course_cohorts, @@ -23,6 +22,7 @@ from openedx.core.djangoapps.course_groups.cohorts import ( ) from openedx.core.djangoapps.verified_track_content.tasks import sync_cohort_with_mode from openedx.core.lib.cache_utils import request_cached +from openedx.core.lib.courses import get_course_by_id from common.djangoapps.student.models import CourseEnrollment log = logging.getLogger(__name__) diff --git a/openedx/core/lib/courses.py b/openedx/core/lib/courses.py index 5c04774060..f81bff03c6 100644 --- a/openedx/core/lib/courses.py +++ b/openedx/core/lib/courses.py @@ -4,6 +4,7 @@ Common utility functions related to courses. from django import forms from django.conf import settings +from django.http import Http404 from opaque_keys import InvalidKeyError from opaque_keys.edx.locator import CourseKey @@ -82,3 +83,19 @@ def clean_course_id(model_form, is_required=True): raise forms.ValidationError(msg) return course_key + + +def get_course_by_id(course_key, depth=0): + """ + Given a course id, return the corresponding course descriptor. + + If such a course does not exist, raises a 404. + + depth: The number of levels of children for the modulestore to cache. None means infinite depth + """ + with modulestore().bulk_operations(course_key): + course = modulestore().get_course(course_key, depth=depth) + if course: + return course + else: + raise Http404("Course not found: {}.".format(str(course_key))) diff --git a/openedx/features/course_experience/plugins.py b/openedx/features/course_experience/plugins.py index cb44171d35..516f6b7c0d 100644 --- a/openedx/features/course_experience/plugins.py +++ b/openedx/features/course_experience/plugins.py @@ -8,8 +8,8 @@ This includes any locally defined CourseTools. from django.urls import reverse from django.utils.translation import ugettext as _ -from lms.djangoapps.courseware.courses import get_course_by_id from common.djangoapps.student.models import CourseEnrollment +from openedx.core.lib.courses import get_course_by_id from . import DISABLE_UNIFIED_COURSE_TAB_FLAG from .course_tools import CourseTool