Crls/deny publish action for staff#69
Open
ccantillo wants to merge 9 commits intoopen-release/teak.nelpfrom
Open
Crls/deny publish action for staff#69ccantillo wants to merge 9 commits intoopen-release/teak.nelpfrom
ccantillo wants to merge 9 commits intoopen-release/teak.nelpfrom
Conversation
johanseto
requested changes
Jan 2, 2026
| ) | ||
| else: | ||
| log.info(f"Publish ALLOWED for user: {request.user.username}, roles={user_course_roles}, global_staff={is_global_staff}") | ||
| except Exception as e: |
| log.info(f"request.json exists: {hasattr(request, 'json')}, request.json value: {getattr(request, 'json', None)}") | ||
|
|
||
| # Check if user is trying to publish and if they have permission | ||
| if request.method in ("POST", "PUT", "PATCH"): |
| user_course_roles = list(CourseAccessRole.objects.filter( | ||
| user=request.user, | ||
| course_id=usage_key.course_key, | ||
| role__in=['instructor', 'staff'] |
Collaborator
There was a problem hiding this comment.
Suggested change
| role__in=['instructor', 'staff'] | |
| role__in=['instructor', 'staff'], |
| log.warning(f"Publish DENIED for staff-only user: {request.user.username} (global_staff={is_global_staff})") | ||
| return JsonResponse( | ||
| { | ||
| "error": _("Only instructors can publish content. Staff members do not have publish permissions.") |
| # Check if user is trying to publish and if they have permission | ||
| if request.method in ("POST", "PUT", "PATCH"): | ||
| try: | ||
| publish_action = request.json.get("publish") if hasattr(request, 'json') and request.json else None |
Collaborator
There was a problem hiding this comment.
Suggested change
| publish_action = request.json.get("publish") if hasattr(request, 'json') and request.json else None | |
| publish_action = request.json.get("publish") if hasattr(request, "json") and request.json else None |
single or double quotes
johanseto
reviewed
Jan 2, 2026
| from .course_index import CourseIndexSerializer | ||
| from .course_rerun import CourseRerunSerializer | ||
| from .course_team import CourseTeamSerializer | ||
| from .course_user_role import CourseUserRoleSerializer |
Collaborator
There was a problem hiding this comment.
CourseUserRoleSerializer Do you need it?
Collaborator
Author
There was a problem hiding this comment.
Yes, needed. It's used by CourseUserRoleView to serialize the response data.
johanseto
reviewed
Jan 2, 2026
| from .course_rerun import CourseRerunView | ||
| from .course_waffle_flags import CourseWaffleFlagsView | ||
| from .course_team import CourseTeamView | ||
| from .course_user_role import CourseUserRoleView |
Collaborator
There was a problem hiding this comment.
Do you use it? CourseUserRoleView
Collaborator
Author
There was a problem hiding this comment.
Yes, it's used. Registered in urls.py at the route course_user_role/{COURSE_ID_PATTERN}, making it an active API endpoint accessible at /api/contentstore/v1/course_user_role/{course_id}
Co-authored-by: Johan Seto Kaiba <51926076+johanseto@users.noreply.github.com>
Co-authored-by: Johan Seto Kaiba <51926076+johanseto@users.noreply.github.com>
Co-authored-by: Johan Seto Kaiba <51926076+johanseto@users.noreply.github.com>
9f9744c to
96a324e
Compare
andrey-canon
reviewed
Jan 5, 2026
| user_course_roles = list(CourseAccessRole.objects.filter( | ||
| user=request.user, | ||
| course_id=usage_key.course_key, | ||
| role__in=["instructor", "staff"] |
Collaborator
There was a problem hiding this comment.
Suggested change
| role__in=["instructor", "staff"] | |
| role__in=getattr(settings, "VALID_PUBLISH_ROLES", ["instructor", "staff"]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This change enforces course-level role restrictions for content publishing in Studio, preventing users with only the "staff" role from publishing content, regardless of their GlobalStaff status.
Impact: Course Authors (Staff role specifically)
Previously, GlobalStaff users could bypass course-level permissions. Now, if a user is assigned the "staff" role (not "instructor") in a course, they cannot publish content even if they have GlobalStaff privileges. This ensures course-level role assignments take precedence over global permissions.
User Roles Affected:
Files Modified:
cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py- Updatedhandle_xblock()permission logicSupporting information
Related to course permission management and role-based access control in Open edX Studio.
Testing instructions