1717from django .views .decorators .csrf import ensure_csrf_cookie
1818from django .views .decorators .http import require_http_methods , require_POST
1919from opaque_keys .edx .keys import AssetKey , CourseKey
20+ from openedx .core .djangoapps .authz .constants import LegacyAuthoringPermission
21+ from openedx .core .djangoapps .authz .decorators import user_has_course_permission
2022from pymongo import ASCENDING , DESCENDING
2123
22- from common .djangoapps .student .auth import has_course_author_access
2324from common .djangoapps .util .date_utils import get_default_time_display
2425from common .djangoapps .util .json_request import JsonResponse
2526from openedx .core .djangoapps .contentserver .caching import del_cached_content
2627from openedx .core .djangoapps .site_configuration import helpers as configuration_helpers
2728from openedx .core .djangoapps .user_api .models import UserPreference
29+ from openedx_authz .constants .permissions import (
30+ COURSES_VIEW_FILES ,
31+ COURSES_CREATE_FILES ,
32+ COURSES_DELETE_FILES ,
33+ COURSES_EDIT_FILES ,
34+ )
2835from openedx_filters .content_authoring .filters import LMSPageURLRequested
36+ from openedx .core .toggles import enable_authz_course_authoring
2937from xmodule .contentstore .content import StaticContent # lint-amnesty, pylint: disable=wrong-import-order
3038from xmodule .contentstore .django import contentstore # lint-amnesty, pylint: disable=wrong-import-order
3139from xmodule .exceptions import NotFoundError # lint-amnesty, pylint: disable=wrong-import-order
@@ -73,8 +81,8 @@ def handle_assets(request, course_key_string=None, asset_key_string=None):
7381 json: delete an asset
7482 '''
7583 course_key = CourseKey .from_string (course_key_string )
76- if not has_course_author_access ( request . user , course_key ):
77- raise PermissionDenied ( )
84+ # Enforce file permissions.
85+ _authz_enforce_file_permissions ( request , course_key )
7886
7987 response_format = get_response_format (request )
8088 if request_response_format_is_json (request , response_format ):
@@ -91,12 +99,60 @@ def handle_assets(request, course_key_string=None, asset_key_string=None):
9199 return HttpResponseNotFound ()
92100
93101
102+ def _authz_enforce_file_permissions (request , course_key ):
103+ """
104+ Enforce permissions for file operations in asset handler.
105+ When the authz.enable_course_authoring flag is enabled for the specified course,
106+ This function enforces the appropriate file permission depending on request content.
107+ When the flag is disabled, it enforces the legacy has_studio_write_access permission.
108+ """
109+ # Enforce permission to view files.
110+ # This is the minimum permission needed for handling assets.
111+ if not user_has_course_permission (
112+ request .user ,
113+ COURSES_VIEW_FILES .identifier ,
114+ course_key ,
115+ LegacyAuthoringPermission .WRITE
116+ ):
117+ raise PermissionDenied ()
118+
119+ if enable_authz_course_authoring (course_key ):
120+ # Check create, edit and delete permissions for AuthZ-enabled courses.
121+ if request .method in ('PUT' , 'POST' ):
122+ permission = (
123+ COURSES_CREATE_FILES .identifier
124+ if 'file' in request .FILES
125+ else COURSES_EDIT_FILES .identifier
126+ )
127+
128+ if not user_has_course_permission (
129+ request .user ,
130+ permission ,
131+ course_key ,
132+ LegacyAuthoringPermission .WRITE
133+ ):
134+ raise PermissionDenied ()
135+
136+ if request .method == 'DELETE' and not user_has_course_permission (
137+ request .user ,
138+ COURSES_DELETE_FILES .identifier ,
139+ course_key ,
140+ LegacyAuthoringPermission .WRITE
141+ ):
142+ raise PermissionDenied ()
143+
144+
94145def get_asset_usage_path_json (request , course_key , asset_key_string ):
95146 """
96147 Get a list of units with ancestors that use given asset.
97148 """
98149 course_key = CourseKey .from_string (course_key )
99- if not has_course_author_access (request .user , course_key ):
150+ if not user_has_course_permission (
151+ request .user ,
152+ COURSES_VIEW_FILES .identifier ,
153+ course_key ,
154+ LegacyAuthoringPermission .WRITE
155+ ):
100156 raise PermissionDenied ()
101157 asset_location = AssetKey .from_string (asset_key_string ) if asset_key_string else None
102158 usage_locations = _get_asset_usage_path (course_key , [{'asset_key' : asset_location }])
0 commit comments