Skip to content

Commit 22f2300

Browse files
committed
temp: Restrict forum bulk-delete to global staff only
1 parent 3f44585 commit 22f2300

File tree

3 files changed

+24
-66
lines changed

3 files changed

+24
-66
lines changed

lms/djangoapps/discussion/rest_api/permissions.py

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from opaque_keys.edx.keys import CourseKey
77
from rest_framework import permissions
88

9-
from common.djangoapps.student.models import CourseAccessRole, CourseEnrollment
9+
from common.djangoapps.student.models import CourseEnrollment
1010
from common.djangoapps.student.roles import (
1111
CourseInstructorRole,
1212
CourseStaffRole,
@@ -19,7 +19,7 @@
1919
from openedx.core.djangoapps.django_comment_common.comment_client.comment import Comment
2020
from openedx.core.djangoapps.django_comment_common.comment_client.thread import Thread
2121
from openedx.core.djangoapps.django_comment_common.models import (
22-
Role, FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_COMMUNITY_TA, FORUM_ROLE_MODERATOR
22+
FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_COMMUNITY_TA, FORUM_ROLE_MODERATOR
2323
)
2424

2525

@@ -185,46 +185,3 @@ def has_permission(self, request, view):
185185
request.user.is_staff or
186186
is_user_staff and request.method == "GET"
187187
)
188-
189-
190-
def can_take_action_on_spam(user, course_id):
191-
"""
192-
Returns if the user has access to take action against forum spam posts
193-
Parameters:
194-
user: User object
195-
course_id: CourseKey or string of course_id
196-
"""
197-
if GlobalStaff().has_user(user):
198-
return True
199-
200-
if isinstance(course_id, str):
201-
course_id = CourseKey.from_string(course_id)
202-
org_id = course_id.org
203-
course_ids = CourseEnrollment.objects.filter(user=user).values_list('course_id', flat=True)
204-
course_ids = [c_id for c_id in course_ids if c_id.org == org_id]
205-
user_roles = set(
206-
Role.objects.filter(
207-
users=user,
208-
course_id__in=course_ids,
209-
).values_list('name', flat=True).distinct()
210-
)
211-
if bool(user_roles & {FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR}):
212-
return True
213-
214-
if CourseAccessRole.objects.filter(user=user, course_id__in=course_ids, role__in=["instructor", "staff"]).exists():
215-
return True
216-
return False
217-
218-
219-
class IsAllowedToBulkDelete(permissions.BasePermission):
220-
"""
221-
Permission that checks if the user is staff or an admin.
222-
"""
223-
224-
def has_permission(self, request, view):
225-
"""Returns true if the user can bulk delete posts"""
226-
if not request.user.is_authenticated:
227-
return False
228-
229-
course_id = view.kwargs.get("course_id")
230-
return can_take_action_on_spam(request.user, course_id)

lms/djangoapps/discussion/rest_api/tests/test_views_v2.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -917,10 +917,9 @@ def test_bulk_delete_denied_for_discussion_roles(self, role):
917917
thread_mock.count_documents.assert_not_called()
918918
comment_mock.count_documents.assert_not_called()
919919

920-
@ddt.data(FORUM_ROLE_MODERATOR, FORUM_ROLE_ADMINISTRATOR)
921-
def test_bulk_delete_allowed_for_discussion_roles(self, role):
920+
def test_bulk_delete_allowed_for_global_staff(self, role):
922921
"""
923-
Test bulk delete user posts passed with discussion roles.
922+
Test bulk delete user posts passed with global staff.
924923
"""
925924
self.mock_comment_and_thread_count(comment_count=1, thread_count=1)
926925
assign_role(self.course.id, self.user, role)

lms/djangoapps/discussion/rest_api/views.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
from lms.djangoapps.course_api.blocks.api import get_blocks
2929
from lms.djangoapps.course_goals.models import UserActivity
3030
from lms.djangoapps.discussion.rate_limit import is_content_creation_rate_limited
31-
from lms.djangoapps.discussion.rest_api.permissions import IsAllowedToBulkDelete
3231
from lms.djangoapps.discussion.rest_api.tasks import delete_course_post_for_user
3332
from lms.djangoapps.discussion.toggles import ONLY_VERIFIED_USERS_CAN_POST
3433
from lms.djangoapps.discussion.django_comment_client import settings as cc_settings
@@ -1549,31 +1548,34 @@ def post(self, request, course_id, rolename):
15491548

15501549
class BulkDeleteUserPosts(DeveloperErrorViewMixin, APIView):
15511550
"""
1552-
**Use Cases**
1553-
A privileged user that can delete all posts and comments made by a user.
1554-
It returns expected number of comments and threads that will be deleted
1555-
1556-
**Example Requests**:
1557-
POST /api/discussion/v1/bulk_delete_user_posts/{course_id}
1558-
Query Parameters:
1559-
username: The username of the user whose posts are to be deleted
1560-
course_id: Course id for which posts are to be removed
1561-
execute: If True, runs deletion task
1562-
course_or_org: If 'course', deletes posts in the course, if 'org', deletes posts in all courses of the org
1563-
1564-
**Example Response**:
1565-
Empty string
1551+
Bulk-delete posts for a forum user (generally in reponse to spam).
15661552
"""
15671553

15681554
authentication_classes = (
15691555
JwtAuthentication, BearerAuthentication, SessionAuthentication,
15701556
)
1571-
permission_classes = (permissions.IsAuthenticated, IsAllowedToBulkDelete)
1557+
permission_classes = (permissions.IsAuthenticated, permissions.IsAdminUser)
15721558

15731559
def post(self, request, course_id):
15741560
"""
1575-
Implements the delete user posts endpoint.
1576-
TODO: Add support for MySQLBackend as well
1561+
Delete all posts and comments made by a user across a course or a course's entire org.
1562+
It returns expected number of comments and threads that will be deleted.
1563+
This only works on legacy MongoDB-backed forums, not MySQL backed forums.
1564+
1565+
POST /api/discussion/v1/bulk_delete_user_posts/{course_id}
1566+
1567+
Query Parameters:
1568+
* username: The username of the user whose posts are to be deleted.
1569+
* course_or_org: See below.
1570+
* course_id: If course_or_org=="course", then a user's posts in this org will be removed.
1571+
If course_or_org=="org", then a user's posts will be removed across the
1572+
whole org containing this course.
1573+
* execute: If True, runs deletion task; if False, just return # of comments and threads
1574+
that would be deleted.
1575+
1576+
Notes: This API is a work-in-progress. We are experimentally releasing in Ulmo to superusers only.
1577+
In Verawood, we plan to allow course staff and forum moderators to bulk-delete posts for
1578+
contexts which they have access to. See https://github.com/openedx/edx-platform/issues/37402 for details.
15771579
"""
15781580
username = request.GET.get("username", None)
15791581
execute_task = request.GET.get("execute", "false").lower() == "true"

0 commit comments

Comments
 (0)