Skip to content

Commit

Permalink
Merge branch 'rpenido/fal-3610-download-course-tag-spreadsheet' into …
Browse files Browse the repository at this point in the history
…rpenido/fal-3611-download-library-tag-spreadsheet
  • Loading branch information
rpenido authored Feb 9, 2024
2 parents f84abd0 + 5245264 commit 06810a2
Show file tree
Hide file tree
Showing 72 changed files with 1,251 additions and 548 deletions.
10 changes: 6 additions & 4 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ lms/djangoapps/grades/
lms/djangoapps/instructor/
lms/djangoapps/instructor_task/
lms/djangoapps/mobile_api/
openedx/core/djangoapps/credentials @openedx/2U-aperture
openedx/core/djangoapps/credit @openedx/2U-aperture
openedx/core/djangoapps/heartbeat/
openedx/core/djangoapps/oauth_dispatch
openedx/core/djangoapps/user_api/
openedx/core/djangoapps/user_api/ @openedx/2U-aperture
openedx/core/djangoapps/user_authn/
openedx/features/course_experience/
xmodule/
Expand All @@ -30,15 +32,15 @@ lms/djangoapps/edxnotes
common/djangoapps/track/

# Credentials
lms/djangoapps/certificates/
lms/djangoapps/certificates/ @openedx/2U-aperture

# Discovery
common/djangoapps/course_modes/
common/djangoapps/enrollment/
lms/djangoapps/commerce/
lms/djangoapps/experiments/
lms/djangoapps/learner_dashboard/
lms/djangoapps/learner_home/
lms/djangoapps/learner_dashboard/ @openedx/2U-aperture
lms/djangoapps/learner_home/ @openedx/2U-aperture
openedx/features/content_type_gating/
openedx/features/course_duration_limits/
openedx/features/discounts/
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* This is a high level diagram visualizing how the `CERTIFICATE_AVAILBLE_DATE` and "visible date" attribute updates
* are updated internally and transmit to the Credentials IDA.
*
* It is written using Structurizr DSL (https://structurizr.org/).
*/
workspace {
model {
properties {
"structurizr.groupSeparator" "/"
}
author = person "Course Author" "External user from partner org with course authoring privileges in the CMS"
credentials = softwareSystem "Credentials IDA"
group "edx-platform" {
modulestore = element "edx-platform Mongo DB"
monolith_db = element "edx-platform Relational DB"
celery = softwareSystem "Celery"

group "CMS" {
studio = softwareSystem "CMS FrontEnd"
contentstore_app = softwareSystem "Contentstore Django app"
}
group "CORE (shared)" {
co_app = softwareSystem "CourseOverview Django App"
programs_app = softwareSystem "Programs Django App"
}
}

author -> studio "Updates certificate available date setting"
studio -> contentstore_app "Processes course settings update"
contentstore_app -> modulestore "Saves course settings update"
contentstore_app -> co_app "Emits COURSE PUBLISHED signal"
co_app -> modulestore "Retrieves course details from Mongo"
co_app -> monolith_db "Updates CourseOverview record"
co_app -> programs_app "Emits COURSE_CERT_DATE_CHANGED signal"
programs_app -> celery "Enqueue UPDATE_CERTIFICATE_VISIBLE_DATE task"
programs_app -> celery "Enqueue UPDATE_CERTIFICATE_AVAILABLE_DATE task"
celery -> credentials "REST requests to update `visible_date` attributes"
celery -> credentials "REST request to update `certificate_available_date` setting"
}

views {
systemLandscape "SystemLandscape" {
include *
autolayout lr
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class CourseIndexSerializer(serializers.Serializer):
deprecated_blocks_info = serializers.DictField()
discussions_incontext_feedback_url = serializers.CharField()
discussions_incontext_learnmore_url = serializers.CharField()
discussions_settings = serializers.DictField()
initial_state = InitialIndexStateSerializer()
initial_user_clipboard = serializers.DictField()
language_code = serializers.CharField()
Expand All @@ -29,4 +30,5 @@ class CourseIndexSerializer(serializers.Serializer):
proctoring_errors = ProctoringErrorListSerializer(many=True)
reindex_link = serializers.CharField()
rerun_notification_id = serializers.IntegerField()
advance_settings_url = serializers.CharField()
is_custom_relative_dates_active = serializers.BooleanField()
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,13 @@ def test_course_index_response(self):
"notification_dismiss_url": None,
"proctoring_errors": [],
"reindex_link": f"/course/{self.course.id}/search_reindex",
"rerun_notification_id": None
"rerun_notification_id": None,
"discussions_settings": {
"enable_in_context": True,
"enable_graded_units": False,
"unit_level_visibility": True,
},
"advance_settings_url": f"/settings/advanced/{self.course.id}",
}

self.assertEqual(response.status_code, status.HTTP_200_OK)
Expand Down Expand Up @@ -117,7 +123,13 @@ def test_course_index_response_with_show_locators(self):
"notification_dismiss_url": None,
"proctoring_errors": [],
"reindex_link": f"/course/{self.course.id}/search_reindex",
"rerun_notification_id": None
"rerun_notification_id": None,
"discussions_settings": {
"enable_in_context": True,
"enable_graded_units": False,
"unit_level_visibility": True,
},
"advance_settings_url": f"/settings/advanced/{self.course.id}",
}

self.assertEqual(response.status_code, status.HTTP_200_OK)
Expand Down
1 change: 1 addition & 0 deletions cms/djangoapps/contentstore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1760,6 +1760,7 @@ def _get_course_index_context(request, course_key, course_block):
course_index_context = {
'language_code': request.LANGUAGE_CODE,
'context_course': course_block,
'discussions_settings': course_block.discussions_settings,
'lms_link': lms_link,
'sections': sections,
'course_structure': course_structure,
Expand Down
4 changes: 2 additions & 2 deletions cms/djangoapps/contentstore/views/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import load_services_for_studio
from openedx.core.lib.xblock_utils import get_aside_from_xblock, is_xblock_aside
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration
from openedx.core.djangoapps.content_tagging.api import get_content_tags
from openedx.core.djangoapps.content_tagging.api import get_object_tags
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.exceptions import ItemNotFoundError # lint-amnesty, pylint: disable=wrong-import-order

Expand Down Expand Up @@ -533,7 +533,7 @@ def get_unit_tags(usage_key):
which already provides this grouping + sorting logic.
"""
# Get content tags from content tagging API
content_tags = get_content_tags(usage_key)
content_tags = get_object_tags(str(usage_key))

# Group content tags by taxonomy
taxonomy_dict = {}
Expand Down
11 changes: 10 additions & 1 deletion cms/envs/devstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing
CLOSEST_CLIENT_IP_FROM_HEADERS = []

#################### Credentials Settings ####################
CREDENTIALS_INTERNAL_SERVICE_URL = 'http://localhost:18150'
CREDENTIALS_INTERNAL_SERVICE_URL = 'http://edx.devstack.credentials:18150'
CREDENTIALS_PUBLIC_SERVICE_URL = 'http://localhost:18150'

########################## ORA MFE APP ##############################
Expand All @@ -307,6 +307,15 @@ def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing
############################ AI_TRANSLATIONS ##################################
AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1'

############################ CSRF ##################################

# MFEs that will call this service in devstack
CSRF_TRUSTED_ORIGINS = [
'http://localhost:3001', # frontend-app-library-authoring
'http://localhost:2001', # frontend-app-course-authoring
'http://localhost:1992', # frontend-app-ora
]

#################### Event bus backend ########################

EVENT_BUS_PRODUCER = 'edx_event_bus_redis.create_producer'
Expand Down
6 changes: 6 additions & 0 deletions cms/static/sass/elements/_system-feedback.scss
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,12 @@

.action-secondary {
@extend %t-action4;
cursor: pointer;
color: $white;

&:hover {
color: $gray-l3;
}
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions common/djangoapps/student/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,12 @@ def test_redirect_account_settings(self):
response = self.client.get(self.path)
self.assertRedirects(response, reverse('account_settings'))

@patch('common.djangoapps.student.views.dashboard.should_redirect_to_learner_home_mfe')
def test_redirect_to_learner_home(self, mock_should_redirect_to_learner_home_mfe):
@patch('common.djangoapps.student.views.dashboard.learner_home_mfe_enabled')
def test_redirect_to_learner_home(self, mock_learner_home_mfe_enabled):
"""
if learner home mfe is enabled, redirect to learner home mfe
"""
mock_should_redirect_to_learner_home_mfe.return_value = True
mock_learner_home_mfe_enabled.return_value = True
response = self.client.get(self.path)
self.assertRedirects(response, settings.LEARNER_HOME_MICROFRONTEND_URL, fetch_redirect_response=False)

Expand Down
4 changes: 2 additions & 2 deletions common/djangoapps/student/views/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from common.djangoapps.entitlements.models import CourseEntitlement
from lms.djangoapps.commerce.utils import EcommerceService
from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.learner_home.waffle import should_redirect_to_learner_home_mfe
from lms.djangoapps.learner_home.waffle import learner_home_mfe_enabled
from lms.djangoapps.experiments.utils import get_dashboard_course_info, get_experiment_user_metadata_context
from lms.djangoapps.verify_student.services import IDVerificationService
from openedx.core.djangoapps.catalog.utils import (
Expand Down Expand Up @@ -521,7 +521,7 @@ def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statem
if not UserProfile.objects.filter(user=user).exists():
return redirect(reverse('account_settings'))

if should_redirect_to_learner_home_mfe(user):
if learner_home_mfe_enabled():
return redirect(settings.LEARNER_HOME_MICROFRONTEND_URL)

platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)
Expand Down
Binary file modified common/static/data/geoip/GeoLite2-Country.mmdb
Binary file not shown.
4 changes: 2 additions & 2 deletions lms/djangoapps/certificates/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,9 +929,9 @@ def invalidate_certificate(user_id, course_key_or_id, source):
Invalidate the user certificate in a given course if it exists and the user is not on the allowlist for this
course run.
This function is called in services.py and handlers.py within the certificates folder. As of now,
This function is called in services.py and signals.py within the certificates folder. As of now,
The call in services.py occurs when an exam attempt is rejected in the legacy exams backend, edx-proctoring.
The call in handlers.py is occurs when an exam attempt is rejected in the newer exams backend, edx-exams.
The call in signals.py is occurs when an exam attempt is rejected in the newer exams backend, edx-exams.
"""
course_key = _get_key(course_key_or_id, CourseKey)
if _is_on_certificate_allowlist(user_id, course_key):
Expand Down
1 change: 0 additions & 1 deletion lms/djangoapps/certificates/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ def ready(self):
# Can't import models at module level in AppConfigs, and models get
# included from the signal handlers
from lms.djangoapps.certificates import signals # pylint: disable=unused-import
from lms.djangoapps.certificates import handlers # pylint: disable=unused-import
if settings.FEATURES.get('ENABLE_SPECIAL_EXAMS'):
from lms.djangoapps.certificates.services import CertificateService
set_runtime_service('certificates', CertificateService())
28 changes: 0 additions & 28 deletions lms/djangoapps/certificates/handlers.py

This file was deleted.

23 changes: 22 additions & 1 deletion lms/djangoapps/certificates/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import logging

from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver

Expand All @@ -22,14 +23,20 @@
CertificateStatuses,
GeneratedCertificate
)
from lms.djangoapps.certificates.api import auto_certificate_generation_enabled
from lms.djangoapps.certificates.api import (
auto_certificate_generation_enabled,
invalidate_certificate
)
from lms.djangoapps.verify_student.services import IDVerificationService
from openedx.core.djangoapps.content.course_overviews.signals import COURSE_PACING_CHANGED
from openedx.core.djangoapps.signals.signals import (
COURSE_GRADE_NOW_FAILED,
COURSE_GRADE_NOW_PASSED,
LEARNER_NOW_VERIFIED
)
from openedx_events.learning.signals import EXAM_ATTEMPT_REJECTED

User = get_user_model()

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -156,3 +163,17 @@ def _listen_for_enrollment_mode_change(sender, user, course_key, mode, **kwargs)
course_key,
)
return False


@receiver(EXAM_ATTEMPT_REJECTED)
def handle_exam_attempt_rejected_event(sender, signal, **kwargs):
"""
Consume `EXAM_ATTEMPT_REJECTED` events from the event bus.
Pass the received data to invalidate_certificate in the services.py file in this folder.
"""
event_data = kwargs.get('exam_attempt')
user_data = event_data.student_user
course_key = event_data.course_key

# Note that the course_key is the same as the course_key_or_id, and is being passed in as the course_key param
invalidate_certificate(user_data.id, course_key, source='exam_event')
Loading

0 comments on commit 06810a2

Please sign in to comment.