diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index 143f01cde32a..99a628a148f1 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -53,7 +53,7 @@ from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.edxmako.services import MakoService from common.djangoapps.student import auth -from common.djangoapps.student.auth import STUDIO_EDIT_ROLES, has_studio_read_access, has_studio_write_access +from common.djangoapps.student.auth import STUDIO_EDIT_ROLES, has_studio_write_access from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole, GlobalStaff from common.djangoapps.track import contexts @@ -71,6 +71,7 @@ from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService from openedx.core import toggles as core_toggles from openedx.core.djangoapps.content.course_overviews.models import CourseOverview +from openedx.core.djangoapps.content.services import StudioPermissionsService from openedx.core.djangoapps.content_libraries.api import get_container from openedx.core.djangoapps.content_tagging.toggles import is_tagging_feature_disabled from openedx.core.djangoapps.credit.api import get_credit_requirements, is_credit_course @@ -2243,27 +2244,6 @@ def get_group_configurations_context(course, store): return context -class StudioPermissionsService: - """ - Service that can provide information about a user's permissions. - - Deprecated. To be replaced by a more general authorization service. - - Only used by LegacyLibraryContentBlock (and library_tools.py). - """ - - def __init__(self, user): - self._user = user - - def can_read(self, course_key): - """ Does the user have read access to the given course/library? """ - return has_studio_read_access(self._user, course_key) - - def can_write(self, course_key): - """ Does the user have read access to the given course/library? """ - return has_studio_write_access(self._user, course_key) - - def track_course_update_event(course_key, user, course_update_content=None): """ Track course update event diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index 85b073b2734d..18cf525cb7db 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -29,6 +29,7 @@ from common.djangoapps.student.models import anonymous_id_for_user from common.djangoapps.xblock_django.user_service import DjangoXBlockUserService from lms.djangoapps.lms_xblock.field_data import LmsFieldData +from openedx.core.djangoapps.content.services import StudioPermissionsService from openedx.core.djangoapps.discussions.services import DiscussionConfigService from openedx.core.djangoapps.video_config.services import VideoConfigService from openedx.core.lib.cache_utils import CacheService @@ -44,7 +45,7 @@ from xmodule.util.sandboxing import SandboxService from xmodule.x_module import AUTHOR_VIEW, PREVIEW_VIEWS, STUDENT_VIEW, XModuleMixin -from ..utils import StudioPermissionsService, get_visibility_partition_info +from ..utils import get_visibility_partition_info from .access import get_user_role from .session_kv_store import SessionKeyValueStore diff --git a/openedx/core/djangoapps/content/services.py b/openedx/core/djangoapps/content/services.py new file mode 100644 index 000000000000..fd11413e2660 --- /dev/null +++ b/openedx/core/djangoapps/content/services.py @@ -0,0 +1,38 @@ +""" +Services for learning content +""" +from __future__ import annotations + +from content_libraries.api import has_permission_for_library_key, permissions +from opaque_keys.edx.locator import LibraryLocatorV2 + +from common.djangoapps.student.auth import has_studio_read_access, has_studio_write_access + + +class StudioPermissionsService: + """ + Service that can provide information about a user's permissions. + """ + + def __init__(self, user): + self._user = user + + def can_read(self, context_key): + """ Does the user have read access to the given course/library? """ + if isinstance(context_key, LibraryLocatorV2): + return has_permission_for_library_key( + context_key, + self._user, + permissions.CAN_VIEW_THIS_CONTENT_LIBRARY, + ) + return has_studio_read_access(self._user, context_key) + + def can_write(self, context_key): + """ Does the user have read access to the given course/library? """ + if isinstance(context_key, LibraryLocatorV2): + return has_permission_for_library_key( + context_key, + self._user, + permissions.CAN_EDIT_THIS_CONTENT_LIBRARY, + ) + return has_studio_write_access(self._user, context_key) diff --git a/openedx/core/djangoapps/content_libraries/api/libraries.py b/openedx/core/djangoapps/content_libraries/api/libraries.py index f8573eadd473..6800b890cde3 100644 --- a/openedx/core/djangoapps/content_libraries/api/libraries.py +++ b/openedx/core/djangoapps/content_libraries/api/libraries.py @@ -94,6 +94,7 @@ "get_libraries_for_user", "get_metadata", "require_permission_for_library_key", + "has_permission_for_library_key", "get_library", "create_library", "get_library_team", @@ -363,6 +364,30 @@ def require_permission_for_library_key( return library_obj +def has_permission_for_library_key( + library_key: LibraryLocatorV2, user: UserType, permission: str | authz_api.data.PermissionData +) -> bool: + """ + Like require_permission_for_library_key, checks if the user has the specified permission + for a library. Unlike require_permission_for_library_key, returns a boolean rather than the + library model or raising an exception. + + Args: + library_key: The library key identifying the content library + user: The user whose permissions are being checked + permission: Either a permission string from content_libraries.permissions + or a PermissionData instance from the authz API + + Returns: + bool: True if the user has the requested permission, False otherwise. + """ + try: + require_permission_for_library_key(library_key, user, permission) + return True + except (PermissionError, ContentLibrary.DoesNotExist): + return False + + def get_library(library_key: LibraryLocatorV2) -> ContentLibraryMetadata: """ Get the library with the specified key. Does not check permissions. diff --git a/openedx/core/djangoapps/xblock/runtime/runtime.py b/openedx/core/djangoapps/xblock/runtime/runtime.py index f3544a6102d8..dd4b8a644fb8 100644 --- a/openedx/core/djangoapps/xblock/runtime/runtime.py +++ b/openedx/core/djangoapps/xblock/runtime/runtime.py @@ -355,6 +355,9 @@ def service(self, block: XBlock, service_name: str): return DiscussionConfigService() elif service_name == 'xqueue': return XQueueService(block) + elif service_name == 'studio_user_permissions': + from openedx.core.djangoapps.content.services import StudioPermissionsService + return StudioPermissionsService(self.user) # Otherwise, fall back to the base implementation which loads services # defined in the constructor: