Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cms/djangoapps/contentstore/views/preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from xblock.runtime import KvsFieldData

from openedx.core.djangoapps.video_config.services import VideoConfigService
from openedx.core.djangoapps.discussions.services import DiscussionConfigService
from xmodule.contentstore.django import contentstore
from xmodule.exceptions import NotFoundError as XModuleNotFoundError
from xmodule.modulestore.django import XBlockI18nService, modulestore
Expand Down Expand Up @@ -217,6 +218,7 @@ def _prepare_runtime_for_preview(request, block):
"cache": CacheService(cache),
'replace_urls': ReplaceURLService,
'video_config': VideoConfigService(),
'discussion_config': DiscussionConfigService(),
}

block.runtime.get_block_for_descriptor = partial(_load_preview_block, request)
Expand Down
2 changes: 2 additions & 0 deletions lms/djangoapps/courseware/block_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

from lms.djangoapps.teams.services import TeamsService
from openedx.core.djangoapps.video_config.services import VideoConfigService
from openedx.core.djangoapps.discussions.services import DiscussionConfigService
from openedx.core.lib.xblock_services.call_to_action import CallToActionService
from xmodule.contentstore.django import contentstore
from xmodule.exceptions import NotFoundError as XModuleNotFoundError
Expand Down Expand Up @@ -637,6 +638,7 @@ def inner_get_block(block: XBlock) -> XBlock | None:
'publish': EventPublishingService(user, course_id, track_function),
'enrollments': EnrollmentsService(),
'video_config': VideoConfigService(),
'discussion_config': DiscussionConfigService(),
}

runtime.get_block_for_descriptor = inner_get_block
Expand Down
4 changes: 2 additions & 2 deletions lms/djangoapps/discussion/django_comment_client/base/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import lms.djangoapps.discussion.django_comment_client.settings as cc_settings
import openedx.core.djangoapps.django_comment_common.comment_client as cc
from openedx.core.djangoapps.django_comment_common.models import has_permission
from common.djangoapps.student.roles import GlobalStaff
from common.djangoapps.track import contexts
from common.djangoapps.util.file import store_uploaded_file
Expand All @@ -33,8 +34,7 @@
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
from lms.djangoapps.discussion.django_comment_client.permissions import (
check_permissions_by_view,
get_team,
has_permission
get_team
)
from lms.djangoapps.discussion.django_comment_client.utils import (
JsonError,
Expand Down
17 changes: 1 addition & 16 deletions lms/djangoapps/discussion/django_comment_client/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,11 @@
from openedx.core.djangoapps.django_comment_common.comment_client import Thread
from openedx.core.djangoapps.django_comment_common.models import (
CourseDiscussionSettings,
all_permissions_for_user_in_course
has_permission
)
from openedx.core.lib.cache_utils import request_cached


def has_permission(user, permission, course_id=None): # lint-amnesty, pylint: disable=missing-function-docstring
assert isinstance(course_id, (type(None), CourseKey))
request_cache_dict = DEFAULT_REQUEST_CACHE.data
cache_key = "django_comment_client.permissions.has_permission.all_permissions.{}.{}".format(
user.id, course_id
)
if cache_key in request_cache_dict:
all_permissions = request_cache_dict[cache_key]
else:
all_permissions = all_permissions_for_user_in_course(user, course_id)
request_cache_dict[cache_key] = all_permissions

return permission in all_permissions


CONDITIONS = ['is_open', 'is_author', 'is_question_author', 'is_team_member_if_applicable']


Expand Down
4 changes: 2 additions & 2 deletions lms/djangoapps/discussion/django_comment_client/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY
from lms.djangoapps.discussion.django_comment_client.permissions import (
check_permissions_by_view,
get_team,
has_permission
get_team
)
from lms.djangoapps.discussion.django_comment_client.settings import MAX_COMMENT_DEPTH
from openedx.core.djangoapps.django_comment_common.models import has_permission
from openedx.core.djangoapps.course_groups.cohorts import get_cohort_id
from openedx.core.djangoapps.discussions.utils import (
get_accessible_discussion_xblocks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from django.template.defaultfilters import escapejs
from django.urls import reverse

from lms.djangoapps.discussion.django_comment_client.permissions import has_permission
from openedx.core.djangoapps.django_comment_common.models import has_permission
from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_string
%>

Expand Down
2 changes: 1 addition & 1 deletion lms/djangoapps/discussion/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import lms.djangoapps.discussion.django_comment_client.utils as utils
import openedx.core.djangoapps.django_comment_common.comment_client as cc
from openedx.core.djangoapps.django_comment_common.models import has_permission
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole, GlobalStaff
from common.djangoapps.util.json_request import JsonResponse, expect_json
Expand All @@ -37,7 +38,6 @@
from lms.djangoapps.discussion.config.settings import is_forum_daily_digest_enabled
from lms.djangoapps.discussion.django_comment_client.base.views import track_thread_viewed_event
from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY
from lms.djangoapps.discussion.django_comment_client.permissions import has_permission
from lms.djangoapps.discussion.django_comment_client.utils import (
add_courseware_context,
course_discussion_division_enabled,
Expand Down
36 changes: 36 additions & 0 deletions openedx/core/djangoapps/discussions/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
Discussion Configuration Service for XBlock runtime.

This service provides discussion-related configuration and feature flags
that are specific to the edx-platform implementation
for the extracted discussion block in xblocks-contrib repository.
"""

from django.conf import settings
from openedx.core.djangoapps.django_comment_common.models import has_permission
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, Provider


class DiscussionConfigService:
"""
Service for providing discussion-related configuration and feature flags.
"""

def has_permission(self, user, permission, course_id=None):
"""
Return the discussion permission for a user in a given course.
"""
return has_permission(user, permission, course_id)

def is_discussion_visible(self, course_key):
"""
Discussion Xblock does not support new OPEN_EDX provider
"""
provider = DiscussionsConfiguration.get(course_key)
return provider.provider_type == Provider.LEGACY

def is_discussion_enabled(self):
"""
Return True if discussions are enabled; else False
"""
return settings.FEATURES.get('ENABLE_DISCUSSION_SERVICE')
33 changes: 33 additions & 0 deletions openedx/core/djangoapps/django_comment_common/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from django.utils.translation import gettext_noop
from jsonfield.fields import JSONField
from opaque_keys.edx.django.models import CourseKeyField
from edx_django_utils.cache import DEFAULT_REQUEST_CACHE
from opaque_keys.edx.keys import CourseKey

from openedx.core.djangoapps.xmodule_django.models import NoneToEmptyManager
from openedx.core.lib.cache_utils import request_cached
Expand Down Expand Up @@ -193,6 +195,37 @@ def all_permissions_for_user_in_course(user, course_id):
return permission_names


def has_permission(user, permission, course_id=None):
"""
This function resolves all discussion-related permissions for the given
user and course, caches them for the duration of the request, and verifies
whether the requested permission is present.

Args:
user (User): Django user whose permissions are being checked.
permission (str): Discussion permission identifier
(e.g., "create_comment", "create_thread").
course_id (CourseKey): Course context in which to evaluate
the permission

Returns:
bool: True if the user has the specified permission in the given
course context; False otherwise.
"""
assert isinstance(course_id, (type(None), CourseKey))
request_cache_dict = DEFAULT_REQUEST_CACHE.data
cache_key = "django_comment_client.permissions.has_permission.all_permissions.{}.{}".format(
user.id, course_id
)
if cache_key in request_cache_dict:
all_permissions = request_cache_dict[cache_key]
else:
all_permissions = all_permissions_for_user_in_course(user, course_id)
request_cache_dict[cache_key] = all_permissions

return permission in all_permissions


class ForumsConfig(ConfigurationModel):
"""
Config for the connection to the cs_comments_service forums backend.
Expand Down
3 changes: 3 additions & 0 deletions openedx/core/djangoapps/xblock/runtime/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ def service(self, block: XBlock, service_name: str):
# Import here to avoid circular dependency
from openedx.core.djangoapps.video_config.services import VideoConfigService
return VideoConfigService()
elif service_name == 'discussion_config':
from openedx.core.djangoapps.discussions.services import DiscussionConfigService
return DiscussionConfigService()

# Otherwise, fall back to the base implementation which loads services
# defined in the constructor:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from django.utils.translation import gettext as _
from django.template.defaultfilters import escapejs

from lms.djangoapps.discussion.django_comment_client.permissions import has_permission
from openedx.core.djangoapps.django_comment_common.models import has_permission
from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_string
from openedx.core.djangolib.markup import HTML
from openedx.features.course_experience import course_home_page_title
Expand Down
19 changes: 14 additions & 5 deletions xmodule/discussion_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from xblock.utils.studio_editable import StudioEditableXBlockMixin
from xblocks_contrib.discussion import DiscussionXBlock as _ExtractedDiscussionXBlock

from lms.djangoapps.discussion.django_comment_client.permissions import has_permission
from openedx.core.djangoapps.django_comment_common.models import has_permission
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, Provider
from openedx.core.djangolib.markup import HTML, Text
from openedx.core.lib.xblock_utils import get_css_dependencies, get_js_dependencies
Expand Down Expand Up @@ -282,8 +282,17 @@ def _apply_metadata_and_policy(cls, block, node, runtime):
setattr(block, field_name, value)


DiscussionXBlock = (
_ExtractedDiscussionXBlock if settings.USE_EXTRACTED_DISCUSSION_BLOCK
else _BuiltInDiscussionXBlock
)
DiscussionXBlock = None


def reset_class():
"""Reset class as per django settings flag"""
global DiscussionXBlock
DiscussionXBlock = (
_ExtractedDiscussionXBlock if settings.USE_EXTRACTED_DISCUSSION_BLOCK
else _BuiltInDiscussionXBlock
)
return DiscussionXBlock

reset_class()
DiscussionXBlock.__name__ = "DiscussionXBlock"
Loading