Skip to content

Commit

Permalink
feat: [AXM-644] Add authorization via cms worker for content generati…
Browse files Browse the repository at this point in the history
…on view
  • Loading branch information
NiedielnitsevIvan authored and GlugovGrGlib committed Jun 19, 2024
1 parent 8f0a187 commit 4a5ad34
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 5 deletions.
5 changes: 3 additions & 2 deletions cms/djangoapps/contentstore/signals/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@


import logging
import requests
from datetime import datetime, timezone
from functools import wraps
from typing import Optional
Expand All @@ -23,6 +22,7 @@
CoursewareSearchIndexer,
LibrarySearchIndexer,
)
from cms.djangoapps.contentstore.utils import get_cms_api_client
from common.djangoapps.track.event_transaction_utils import get_event_transaction_id, get_event_transaction_type
from common.djangoapps.util.block_utils import yield_dynamic_block_descendants
from lms.djangoapps.grades.api import task_compute_all_grades_for_course
Expand Down Expand Up @@ -160,7 +160,8 @@ def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=
transaction.on_commit(lambda: emit_catalog_info_changed_signal(course_key))

if is_offline_mode_enabled(course_key):
requests.post(
client = get_cms_api_client()
client.post(
url=urljoin(settings.LMS_ROOT_URL, LMS_OFFLINE_HANDLER_URL),
data={'course_id': str(course_key)},
)
Expand Down
17 changes: 17 additions & 0 deletions cms/djangoapps/contentstore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
import configparser
import logging
import re
import requests
from collections import defaultdict
from contextlib import contextmanager
from datetime import datetime, timezone
from urllib.parse import quote_plus
from uuid import uuid4

from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.urls import reverse
from django.utils import translation
from django.utils.translation import gettext as _
from edx_rest_api_client.auth import SuppliedJwtAuth
from eventtracking import tracker
from help_tokens.core import HelpUrlExpert
from lti_consumer.models import CourseAllowPIISharingInLTIFlag
Expand Down Expand Up @@ -67,6 +70,7 @@
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
from openedx.core.djangoapps.models.course_details import CourseDetails
from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user
from openedx.core.lib.courses import course_image_url
from openedx.core.lib.html_to_text import html_to_text
from openedx.features.content_type_gating.models import ContentTypeGatingConfig
Expand Down Expand Up @@ -107,6 +111,7 @@

IMPORTABLE_FILE_TYPES = ('.tar.gz', '.zip')
log = logging.getLogger(__name__)
User = get_user_model()


def add_instructor(course_key, requesting_user, new_instructor):
Expand Down Expand Up @@ -2317,3 +2322,15 @@ def get_xblock_render_context(request, block):
return str(exc)

return ""


def get_cms_api_client():
"""
Returns an API client which can be used to make Exams API requests.
"""
user = User.objects.get(username=settings.EDXAPP_CMS_SERVICE_USER_NAME)
jwt = create_jwt_for_user(user)
client = requests.Session()
client.auth = SuppliedJwtAuth(jwt)

return client
2 changes: 2 additions & 0 deletions cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2525,6 +2525,8 @@
EXAMS_SERVICE_URL = 'http://localhost:18740/api/v1'
EXAMS_SERVICE_USERNAME = 'edx_exams_worker'

CMS_SERVICE_USER_NAME = 'edxapp_cms_worker'

FINANCIAL_REPORTS = {
'STORAGE_TYPE': 'localfs',
'BUCKET': None,
Expand Down
3 changes: 3 additions & 0 deletions cms/envs/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ def get_env_setting(setting):
AUTHORING_API_URL = ENV_TOKENS.get('AUTHORING_API_URL', '')
# Note that FEATURES['PREVIEW_LMS_BASE'] gets read in from the environment file.

CMS_SERVICE_USER_NAME = ENV_TOKENS.get('CMS_SERVICE_USER_NAME', CMS_SERVICE_USER_NAME)


OPENAI_API_KEY = ENV_TOKENS.get('OPENAI_API_KEY', '')
LEARNER_ENGAGEMENT_PROMPT_FOR_ACTIVE_CONTRACT = ENV_TOKENS.get('LEARNER_ENGAGEMENT_PROMPT_FOR_ACTIVE_CONTRACT', '')
LEARNER_ENGAGEMENT_PROMPT_FOR_NON_ACTIVE_CONTRACT = ENV_TOKENS.get(
Expand Down
2 changes: 1 addition & 1 deletion lms/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -1055,5 +1055,5 @@
]

urlpatterns += [
path('offline_mode/', include('openedx.features.offline_mode.urls')),
path('offline_mode/', include('openedx.features.offline_mode.urls', namespace='offline_mode')),
]
1 change: 1 addition & 0 deletions openedx/features/offline_mode/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from .views import SudioCoursePublishedEventHandler

app_name = 'offline_mode'
urlpatterns = [
path('handle_course_published', SudioCoursePublishedEventHandler.as_view(), name='handle_course_published'),
]
18 changes: 16 additions & 2 deletions openedx/features/offline_mode/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
Views for the offline_mode app.
"""
from opaque_keys.edx.keys import CourseKey
from opaque_keys import InvalidKeyError
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
from rest_framework import status
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response
from rest_framework.views import APIView

from openedx.core.lib.api.authentication import BearerAuthentication
from .tasks import generate_offline_content_for_course
from .toggles import is_offline_mode_enabled

Expand All @@ -18,6 +23,9 @@ class SudioCoursePublishedEventHandler(APIView):
and it triggers the generation of offline content.
"""

authentication_classes = (JwtAuthentication, BearerAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser,)

def post(self, request, *args, **kwargs):
"""
Trigger the generation of offline content task.
Expand All @@ -30,14 +38,20 @@ def post(self, request, *args, **kwargs):
Returns:
Response: The response object.
"""

course_id = request.data.get('course_id')
if not course_id:
return Response(
data={'error': 'course_id is required'},
status=status.HTTP_400_BAD_REQUEST
)
course_key = CourseKey.from_string(course_id)
try:
course_key = CourseKey.from_string(course_id)
except InvalidKeyError:
return Response(
data={'error': 'Invalid course_id'},
status=status.HTTP_400_BAD_REQUEST
)

if is_offline_mode_enabled(course_key):
generate_offline_content_for_course.apply_async(args=[course_id])
return Response(status=status.HTTP_200_OK)
Expand Down

0 comments on commit 4a5ad34

Please sign in to comment.