chore: added waffle for allowing only verified users to create post (#37051)
This commit is contained in:
committed by
GitHub
parent
e1a801a700
commit
01beca4ebb
@@ -35,7 +35,7 @@ from common.djangoapps.student.roles import (
|
||||
from lms.djangoapps.course_api.blocks.api import get_blocks
|
||||
from lms.djangoapps.courseware.courses import get_course_with_access
|
||||
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
|
||||
from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE
|
||||
from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE, ONLY_VERIFIED_USERS_CAN_POST
|
||||
from lms.djangoapps.discussion.views import is_privileged_user
|
||||
from openedx.core.djangoapps.discussions.models import (
|
||||
DiscussionsConfiguration,
|
||||
@@ -385,7 +385,7 @@ def get_course(request, course_key, check_tab=True):
|
||||
'site_key': settings.RECAPTCHA_SITE_KEY,
|
||||
},
|
||||
"is_email_verified": request.user.is_active,
|
||||
"only_verified_users_can_post": False,
|
||||
"only_verified_users_can_post": ONLY_VERIFIED_USERS_CAN_POST.is_enabled(course_key),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ from pytz import UTC
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient, APITestCase
|
||||
|
||||
from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE
|
||||
from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE, ONLY_VERIFIED_USERS_CAN_POST
|
||||
from lms.djangoapps.discussion.rest_api.utils import get_usernames_from_search_string
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
@@ -1064,6 +1064,7 @@ class CourseTopicsViewV3Test(DiscussionAPIViewTestMixin, CommentsServiceMockMixi
|
||||
assert vertical_keys == expected_non_courseware_keys
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@httpretty.activate
|
||||
@disable_signal(api, 'thread_created')
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
|
||||
@@ -1139,6 +1140,41 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
|
||||
response_data = json.loads(response.content.decode('utf-8'))
|
||||
assert response_data == expected_response_data
|
||||
|
||||
@ddt.data(
|
||||
(False, False, status.HTTP_200_OK),
|
||||
(False, True, status.HTTP_400_BAD_REQUEST),
|
||||
(True, False, status.HTTP_200_OK),
|
||||
(True, True, status.HTTP_200_OK),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_creation_for_non_verified_user(self, email_verified, only_verified_user_can_post, response_status):
|
||||
"""
|
||||
Tests posts cannot be created if ONLY_VERIFIED_USERS_CAN_POST is enabled and user email is unverified.
|
||||
"""
|
||||
with override_waffle_flag(ONLY_VERIFIED_USERS_CAN_POST, only_verified_user_can_post):
|
||||
self.user.is_active = email_verified
|
||||
self.user.save()
|
||||
self.register_get_user_response(self.user)
|
||||
cs_thread = make_minimal_cs_thread({
|
||||
"id": "test_thread",
|
||||
"username": self.user.username,
|
||||
"read": True,
|
||||
})
|
||||
self.register_post_thread_response(cs_thread)
|
||||
request_data = {
|
||||
"course_id": str(self.course.id),
|
||||
"topic_id": "test_topic",
|
||||
"type": "discussion",
|
||||
"title": "Test Title",
|
||||
"raw_body": "# Test \n This is a very long body but will not be truncated for the preview.",
|
||||
}
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
json.dumps(request_data),
|
||||
content_type="application/json"
|
||||
)
|
||||
assert response.status_code == response_status
|
||||
|
||||
|
||||
@httpretty.activate
|
||||
@disable_signal(api, 'thread_deleted')
|
||||
@@ -2019,6 +2055,7 @@ class CommentViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@httpretty.activate
|
||||
@disable_signal(api, 'comment_created')
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
|
||||
@@ -2134,6 +2171,69 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase):
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
@ddt.data(
|
||||
(False, False, status.HTTP_200_OK),
|
||||
(False, True, status.HTTP_400_BAD_REQUEST),
|
||||
(True, False, status.HTTP_200_OK),
|
||||
(True, True, status.HTTP_200_OK),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_creation_for_non_verified_user(self, email_verified, only_verified_user_can_post, response_status):
|
||||
"""
|
||||
Tests comments/replies cannot be created if ONLY_VERIFIED_USERS_CAN_POST is enabled and
|
||||
user email is unverified.
|
||||
"""
|
||||
with override_waffle_flag(ONLY_VERIFIED_USERS_CAN_POST, only_verified_user_can_post):
|
||||
self.user.is_active = email_verified
|
||||
self.user.save()
|
||||
self.register_get_user_response(self.user)
|
||||
self.register_thread()
|
||||
self.register_comment()
|
||||
request_data = {
|
||||
"thread_id": "test_thread",
|
||||
"raw_body": "Test body",
|
||||
}
|
||||
expected_response_data = {
|
||||
"id": "test_comment",
|
||||
"thread_id": "test_thread",
|
||||
"parent_id": None,
|
||||
"author": self.user.username,
|
||||
"author_label": None,
|
||||
"created_at": "1970-01-01T00:00:00Z",
|
||||
"updated_at": "1970-01-01T00:00:00Z",
|
||||
"raw_body": "Test body",
|
||||
"rendered_body": "<p>Test body</p>",
|
||||
"endorsed": False,
|
||||
"endorsed_by": None,
|
||||
"endorsed_by_label": None,
|
||||
"endorsed_at": None,
|
||||
"abuse_flagged": False,
|
||||
"abuse_flagged_any_user": None,
|
||||
"voted": False,
|
||||
"vote_count": 0,
|
||||
"children": [],
|
||||
"editable_fields": ["abuse_flagged", "anonymous", "raw_body"],
|
||||
"child_count": 0,
|
||||
"can_delete": True,
|
||||
"anonymous": False,
|
||||
"anonymous_to_peers": False,
|
||||
"last_edit": None,
|
||||
"edit_by_label": None,
|
||||
"profile_image": {
|
||||
"has_image": False,
|
||||
"image_url_full": "http://testserver/static/default_500.png",
|
||||
"image_url_large": "http://testserver/static/default_120.png",
|
||||
"image_url_medium": "http://testserver/static/default_50.png",
|
||||
"image_url_small": "http://testserver/static/default_30.png",
|
||||
},
|
||||
}
|
||||
response = self.client.post(
|
||||
self.url,
|
||||
json.dumps(request_data),
|
||||
content_type="application/json"
|
||||
)
|
||||
assert response.status_code == response_status
|
||||
|
||||
|
||||
@httpretty.activate
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
|
||||
|
||||
@@ -29,6 +29,7 @@ from lms.djangoapps.course_api.blocks.api import get_blocks
|
||||
from lms.djangoapps.course_goals.models import UserActivity
|
||||
from lms.djangoapps.discussion.rest_api.permissions import IsAllowedToBulkDelete
|
||||
from lms.djangoapps.discussion.rest_api.tasks import delete_course_post_for_user
|
||||
from lms.djangoapps.discussion.toggles import ONLY_VERIFIED_USERS_CAN_POST
|
||||
from lms.djangoapps.discussion.django_comment_client import settings as cc_settings
|
||||
from lms.djangoapps.discussion.django_comment_client.utils import get_group_id_for_comments_service
|
||||
from lms.djangoapps.instructor.access import update_forum_role
|
||||
@@ -671,13 +672,19 @@ class ThreadViewSet(DeveloperErrorViewMixin, ViewSet):
|
||||
"""
|
||||
if not request.data.get("course_id"):
|
||||
raise ValidationError({"course_id": ["This field is required."]})
|
||||
if is_captcha_enabled(CourseKey.from_string(request.data.get("course_id"))):
|
||||
course_key_str = request.data.get("course_id")
|
||||
course_key = CourseKey.from_string(course_key_str)
|
||||
if is_captcha_enabled(course_key):
|
||||
captcha_token = request.data.get('captcha_token')
|
||||
if not captcha_token:
|
||||
raise ValidationError({'captcha_token': 'This field is required.'})
|
||||
|
||||
if not verify_recaptcha_token(captcha_token):
|
||||
return Response({'error': 'CAPTCHA verification failed.'}, status=400)
|
||||
|
||||
if ONLY_VERIFIED_USERS_CAN_POST.is_enabled(course_key) and not request.user.is_active:
|
||||
raise ValidationError({"detail": "Only verified users can post in discussions."})
|
||||
|
||||
data = request.data.copy()
|
||||
data.pop('captcha_token', None)
|
||||
return Response(create_thread(request, data))
|
||||
@@ -1037,14 +1044,20 @@ class CommentViewSet(DeveloperErrorViewMixin, ViewSet):
|
||||
"""
|
||||
if not request.data.get("thread_id"):
|
||||
raise ValidationError({"thread_id": ["This field is required."]})
|
||||
course_id = get_course_id_from_thread_id(request.data["thread_id"])
|
||||
if is_captcha_enabled(CourseKey.from_string(course_id)):
|
||||
course_key_str = get_course_id_from_thread_id(request.data["thread_id"])
|
||||
course_key = CourseKey.from_string(course_key_str)
|
||||
|
||||
if is_captcha_enabled(course_key):
|
||||
captcha_token = request.data.get('captcha_token')
|
||||
if not captcha_token:
|
||||
raise ValidationError({'captcha_token': 'This field is required.'})
|
||||
|
||||
if not verify_recaptcha_token(captcha_token):
|
||||
return Response({'error': 'CAPTCHA verification failed.'}, status=400)
|
||||
|
||||
if ONLY_VERIFIED_USERS_CAN_POST.is_enabled(course_key) and not request.user.is_active:
|
||||
raise ValidationError({"detail": "Only verified users can post in discussions."})
|
||||
|
||||
data = request.data.copy()
|
||||
data.pop('captcha_token', None)
|
||||
return Response(create_comment(request, data))
|
||||
|
||||
@@ -15,3 +15,15 @@ from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
|
||||
ENABLE_DISCUSSIONS_MFE = CourseWaffleFlag(
|
||||
f"{WAFFLE_FLAG_NAMESPACE}.enable_discussions_mfe", __name__
|
||||
)
|
||||
|
||||
|
||||
# .. toggle_name: discussions.only_verified_users_can_post
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
# .. toggle_default: False
|
||||
# .. toggle_description: Waffle flag to allow only verified users to post in discussions
|
||||
# .. toggle_use_cases: temporary, open_edx
|
||||
# .. toggle_creation_date: 2025-22-07
|
||||
# .. toggle_target_removal_date: 2026-04-01
|
||||
ONLY_VERIFIED_USERS_CAN_POST = CourseWaffleFlag(
|
||||
f"{WAFFLE_FLAG_NAMESPACE}.only_verified_users_can_post", __name__
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user