Skip to content

Commit d20b87b

Browse files
authored
Discussion service to enable permission and access provider (#37912)
* chore: discussion service to enable permission and access provider
1 parent 24468b6 commit d20b87b

File tree

15 files changed

+150
-46
lines changed

15 files changed

+150
-46
lines changed

cms/djangoapps/contentstore/views/preview.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from xblock.runtime import KvsFieldData
2020

2121
from openedx.core.djangoapps.video_config.services import VideoConfigService
22+
from openedx.core.djangoapps.discussions.services import DiscussionConfigService
2223
from xmodule.contentstore.django import contentstore
2324
from xmodule.exceptions import NotFoundError as XModuleNotFoundError
2425
from xmodule.modulestore.django import XBlockI18nService, modulestore
@@ -228,6 +229,7 @@ def _prepare_runtime_for_preview(request, block):
228229
"cache": CacheService(cache),
229230
'replace_urls': ReplaceURLService,
230231
'video_config': VideoConfigService(),
232+
'discussion_config_service': DiscussionConfigService(),
231233
}
232234

233235
block.runtime.get_block_for_descriptor = partial(_load_preview_block, request)

lms/djangoapps/courseware/block_render.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
from lms.djangoapps.teams.services import TeamsService
4545
from openedx.core.djangoapps.video_config.services import VideoConfigService
46+
from openedx.core.djangoapps.discussions.services import DiscussionConfigService
4647
from openedx.core.lib.xblock_services.call_to_action import CallToActionService
4748
from xmodule.contentstore.django import contentstore
4849
from xmodule.exceptions import NotFoundError as XModuleNotFoundError
@@ -637,6 +638,7 @@ def inner_get_block(block: XBlock) -> XBlock | None:
637638
'publish': EventPublishingService(user, course_id, track_function),
638639
'enrollments': EnrollmentsService(),
639640
'video_config': VideoConfigService(),
641+
'discussion_config_service': DiscussionConfigService(),
640642
}
641643

642644
runtime.get_block_for_descriptor = inner_get_block

lms/djangoapps/courseware/tests/test_discussion_xblock.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from lms.djangoapps.courseware.block_render import get_block_for_descriptor
2929
from lms.djangoapps.courseware.tests.helpers import XModuleRenderingTestBase
3030
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, Provider
31+
from openedx.core.djangoapps.discussions.services import DiscussionConfigService
3132
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
3233

3334

@@ -193,6 +194,14 @@ def test_student_perms_are_correct(self, permissions):
193194
'can_create_subcomment': permission_dict['create_sub_comment'],
194195
}
195196

197+
self.add_patcher(
198+
patch.multiple(
199+
DiscussionConfigService,
200+
is_discussion_visible=mock.Mock(return_value=True),
201+
is_discussion_enabled=mock.Mock(return_value=True)
202+
)
203+
)
204+
196205
self.block.has_permission = lambda perm: permission_dict[perm]
197206
with mock.patch('xmodule.discussion_block.render_to_string', return_value='') as mock_render:
198207
self.block.student_view()
@@ -223,13 +232,10 @@ def test_has_permission(self):
223232
Test for has_permission method.
224233
"""
225234
permission_canary = object()
226-
with mock.patch(
227-
'xmodule.discussion_block.has_permission',
228-
return_value=permission_canary,
229-
) as has_perm:
230-
actual_permission = self.block.has_permission("test_permission")
235+
self.block.has_permission = mock.Mock(return_value=permission_canary)
236+
actual_permission = self.block.has_permission("test_permission")
231237
assert actual_permission == permission_canary
232-
has_perm.assert_called_once_with(self.django_user_canary, 'test_permission', self.course_id)
238+
self.block.has_permission.assert_called_once_with("test_permission")
233239

234240
def test_studio_view(self):
235241
"""Test for studio view."""
@@ -252,6 +258,14 @@ def test_student_perms_are_correct(self, permissions):
252258
'create_sub_comment': permissions[2]
253259
}
254260

261+
self.add_patcher(
262+
patch.multiple(
263+
DiscussionConfigService,
264+
is_discussion_visible=mock.Mock(return_value=True),
265+
is_discussion_enabled=mock.Mock(return_value=True)
266+
)
267+
)
268+
255269
self.block.has_permission = lambda perm: permission_dict[perm]
256270
fragment = self.block.student_view()
257271
read_only = 'false' if permissions[0] else 'true'
@@ -296,7 +310,7 @@ def get_root(self, block):
296310
block = block.get_parent()
297311
return block
298312

299-
@override_settings(FEATURES=dict(settings.FEATURES, ENABLE_DISCUSSION_SERVICE='True'))
313+
@override_settings(ENABLE_DISCUSSION_SERVICE=True)
300314
def test_html_with_user(self):
301315
"""
302316
Test rendered DiscussionXBlock permissions.
@@ -317,7 +331,7 @@ def test_html_with_user(self):
317331
assert 'data-user-create-comment="false"' in html
318332
assert 'data-user-create-subcomment="false"' in html
319333

320-
@override_settings(FEATURES=dict(settings.FEATURES, ENABLE_DISCUSSION_SERVICE='True'))
334+
@override_settings(ENABLE_DISCUSSION_SERVICE=True)
321335
def test_discussion_render_successfully_with_orphan_parent(self):
322336
"""
323337
Test that discussion xblock render successfully
@@ -421,7 +435,7 @@ class TestXBlockQueryLoad(SharedModuleStoreTestCase):
421435
Test the number of queries executed when rendering the XBlock.
422436
"""
423437

424-
@override_settings(FEATURES=dict(settings.FEATURES, ENABLE_DISCUSSION_SERVICE='True'))
438+
@override_settings(ENABLE_DISCUSSION_SERVICE=True)
425439
def test_permissions_query_load(self):
426440
"""
427441
Tests that the permissions queries are cached when rendering numerous discussion XBlocks.

lms/djangoapps/discussion/django_comment_client/base/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import lms.djangoapps.discussion.django_comment_client.settings as cc_settings
2727
import openedx.core.djangoapps.django_comment_common.comment_client as cc
28+
from openedx.core.djangoapps.django_comment_common.models import has_permission
2829
from common.djangoapps.student.roles import GlobalStaff
2930
from common.djangoapps.track import contexts
3031
from common.djangoapps.util.file import store_uploaded_file
@@ -33,8 +34,7 @@
3334
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
3435
from lms.djangoapps.discussion.django_comment_client.permissions import (
3536
check_permissions_by_view,
36-
get_team,
37-
has_permission
37+
get_team
3838
)
3939
from lms.djangoapps.discussion.django_comment_client.utils import (
4040
JsonError,

lms/djangoapps/discussion/django_comment_client/permissions.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,11 @@
1212
from openedx.core.djangoapps.django_comment_common.comment_client import Thread
1313
from openedx.core.djangoapps.django_comment_common.models import (
1414
CourseDiscussionSettings,
15-
all_permissions_for_user_in_course
15+
has_permission
1616
)
1717
from openedx.core.lib.cache_utils import request_cached
1818

1919

20-
def has_permission(user, permission, course_id=None): # lint-amnesty, pylint: disable=missing-function-docstring
21-
assert isinstance(course_id, (type(None), CourseKey))
22-
request_cache_dict = DEFAULT_REQUEST_CACHE.data
23-
cache_key = "django_comment_client.permissions.has_permission.all_permissions.{}.{}".format(
24-
user.id, course_id
25-
)
26-
if cache_key in request_cache_dict:
27-
all_permissions = request_cache_dict[cache_key]
28-
else:
29-
all_permissions = all_permissions_for_user_in_course(user, course_id)
30-
request_cache_dict[cache_key] = all_permissions
31-
32-
return permission in all_permissions
33-
34-
3520
CONDITIONS = ['is_open', 'is_author', 'is_question_author', 'is_team_member_if_applicable']
3621

3722

lms/djangoapps/discussion/django_comment_client/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY
2525
from lms.djangoapps.discussion.django_comment_client.permissions import (
2626
check_permissions_by_view,
27-
get_team,
28-
has_permission
27+
get_team
2928
)
3029
from lms.djangoapps.discussion.django_comment_client.settings import MAX_COMMENT_DEPTH
30+
from openedx.core.djangoapps.django_comment_common.models import has_permission
3131
from openedx.core.djangoapps.course_groups.cohorts import get_cohort_id
3232
from openedx.core.djangoapps.discussions.utils import (
3333
get_accessible_discussion_xblocks,

lms/djangoapps/discussion/templates/discussion/discussion_profile_page.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from django.template.defaultfilters import escapejs
1212
from django.urls import reverse
1313

14-
from lms.djangoapps.discussion.django_comment_client.permissions import has_permission
14+
from openedx.core.djangoapps.django_comment_common.models import has_permission
1515
from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_string
1616
%>
1717

lms/djangoapps/discussion/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import lms.djangoapps.discussion.django_comment_client.utils as utils
3030
import openedx.core.djangoapps.django_comment_common.comment_client as cc
31+
from openedx.core.djangoapps.django_comment_common.models import has_permission
3132
from common.djangoapps.student.models import CourseEnrollment
3233
from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole, GlobalStaff
3334
from common.djangoapps.util.json_request import JsonResponse, expect_json
@@ -37,7 +38,6 @@
3738
from lms.djangoapps.discussion.config.settings import is_forum_daily_digest_enabled
3839
from lms.djangoapps.discussion.django_comment_client.base.views import track_thread_viewed_event
3940
from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY
40-
from lms.djangoapps.discussion.django_comment_client.permissions import has_permission
4141
from lms.djangoapps.discussion.django_comment_client.utils import (
4242
add_courseware_context,
4343
course_discussion_division_enabled,

mypy.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ files =
1515
# openedx/core/djangoapps/content/search,
1616
openedx/core/djangoapps/content_staging,
1717
openedx/core/djangoapps/content_libraries,
18+
openedx/core/djangoapps/discussions/services.py,
1819
openedx/core/djangoapps/programs/rest_api,
1920
openedx/core/djangoapps/xblock,
2021
openedx/core/lib/derived.py,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Discussion Configuration Service for XBlock runtime.
3+
4+
This service provides discussion-related configuration and feature flags
5+
that are specific to the edx-platform implementation
6+
for the extracted discussion block in xblocks-contrib repository.
7+
"""
8+
9+
from django.conf import settings
10+
from django.contrib.auth.models import User # pylint: disable=imported-auth-user
11+
from opaque_keys.edx.keys import CourseKey
12+
from openedx.core.djangoapps.django_comment_common.models import has_permission
13+
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, Provider
14+
15+
16+
class DiscussionConfigService:
17+
"""
18+
Service for providing discussion-related configuration and feature flags.
19+
"""
20+
21+
def has_permission(self, user: User, permission: str, course_id: CourseKey | None = None) -> bool:
22+
"""
23+
Return whether the user has the given discussion permission for a given course.
24+
"""
25+
return has_permission(user, permission, course_id)
26+
27+
def is_discussion_visible(self, course_key: CourseKey) -> bool:
28+
"""
29+
Discussion Xblock does not support new OPEN_EDX provider
30+
"""
31+
provider = DiscussionsConfiguration.get(course_key)
32+
return provider.provider_type == Provider.LEGACY
33+
34+
def is_discussion_enabled(self) -> bool:
35+
"""
36+
Return True if discussions are enabled; else False
37+
"""
38+
return settings.ENABLE_DISCUSSION_SERVICE

0 commit comments

Comments
 (0)