Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync opencraft-release/quince.1 with Upstream 20240520-1716214773 #658

Merged
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
7 changes: 6 additions & 1 deletion cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2273,7 +2273,6 @@

############################ OAUTH2 Provider ###################################


# 5 minute expiration time for JWT id tokens issued for external API requests.
OAUTH_ID_TOKEN_EXPIRATION = 5 * 60

Expand All @@ -2289,6 +2288,12 @@
API_DOCUMENTATION_URL = 'https://course-catalog-api-guide.readthedocs.io/en/latest/'
AUTH_DOCUMENTATION_URL = 'https://course-catalog-api-guide.readthedocs.io/en/latest/authentication/index.html'

EDX_DRF_EXTENSIONS = {
# Set this value to an empty dict in order to prevent automatically updating
# user data from values in (possibly stale) JWTs.
'JWT_PAYLOAD_USER_ATTRIBUTE_MAPPING': {},
}

############## Settings for Studio Context Sensitive Help ##############

HELP_TOKENS_INI_FILE = REPO_ROOT / "cms" / "envs" / "help_tokens.ini"
Expand Down
2 changes: 1 addition & 1 deletion cms/templates/widgets/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ <h3 class="title"><span class="label">${_("Tools")}</span> <span class="icon fa
% if user.is_authenticated:
<input title="preference api" type="hidden" id="preference-api-url" class="url-endpoint" value="${reverse('preferences_api', kwargs={'username': user.username})}" data-user-is-authenticated="true">
% else:
<input title="session update url" type="hidden" id="update-session-url" class="url-endpoint" value="${reverse('session_language')}" data-user-is-authenticated="false">
<input title="session update url" type="hidden" id="update-session-url" class="url-endpoint" value="${reverse('update_language')}" data-user-is-authenticated="false">
% endif
<label><span class="sr">${_("Choose Language")}</span>
<select class="input select language-selector" id="settings-language-value" name="language">
Expand Down
5 changes: 3 additions & 2 deletions lms/djangoapps/certificates/views/webview.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,14 +458,15 @@ def _update_organization_context(context, course):
Updates context with organization related info.
"""
partner_long_name, organization_logo = None, None
partner_short_name = course.display_organization if course.display_organization else course.org
course_org_display = course.display_organization
organizations = organizations_api.get_course_organizations(course_key=course.id)
if organizations:
# TODO Need to add support for multiple organizations, Currently we are interested in the first one.
organization = organizations[0]
partner_long_name = organization.get('name', partner_long_name)
partner_short_name = organization.get('short_name', partner_short_name)
course_org_display = course_org_display or organization.get('short_name')
organization_logo = organization.get('logo', None)
partner_short_name = course_org_display or course.org

context['organization_long_name'] = partner_long_name
context['organization_short_name'] = partner_short_name
Expand Down
37 changes: 27 additions & 10 deletions lms/djangoapps/course_api/blocks/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""
Utils for Blocks
"""
from rest_framework.utils.serializer_helpers import ReturnList

from openedx.core.djangoapps.discussions.models import (
DiscussionsConfiguration,
Provider,
Expand All @@ -15,16 +17,28 @@ def filter_discussion_xblocks_from_response(response, course_key):
provider = configuration.provider_type
if provider == Provider.OPEN_EDX:
# Finding ids of discussion xblocks
discussion_xblocks = [
key for key, value in response.data.get('blocks', {}).items()
if value.get('type') == 'discussion'
]
if isinstance(response.data, ReturnList):
discussion_xblocks = [
value.get('id') for value in response.data if value.get('type') == 'discussion'
]
else:
discussion_xblocks = [
key for key, value in response.data.get('blocks', {}).items()
if value.get('type') == 'discussion'
]
# Filtering discussion xblocks keys from blocks
filtered_blocks = {
key: value
for key, value in response.data.get('blocks', {}).items()
if value.get('type') != 'discussion'
}
if isinstance(response.data, ReturnList):
filtered_blocks = {
value.get('id'): value
for value in response.data
if value.get('type') != 'discussion'
}
else:
filtered_blocks = {
key: value
for key, value in response.data.get('blocks', {}).items()
if value.get('type') != 'discussion'
}
# Removing reference of discussion xblocks from unit
# These references needs to be removed because they no longer exist
for _, block_data in filtered_blocks.items():
Expand All @@ -36,5 +50,8 @@ def filter_discussion_xblocks_from_response(response, course_key):
if descendant not in discussion_xblocks
]
block_data[key] = descendants
response.data['blocks'] = filtered_blocks
if isinstance(response.data, ReturnList):
response.data = filtered_blocks
else:
response.data['blocks'] = filtered_blocks
return response
1 change: 1 addition & 0 deletions lms/djangoapps/course_home_api/progress/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,4 @@ class ProgressTabSerializer(VerifiedModeSerializer):
username = serializers.CharField()
user_has_passing_grade = serializers.BooleanField()
verification_data = VerificationDataSerializer()
disable_progress_graph = serializers.BooleanField()
2 changes: 2 additions & 0 deletions lms/djangoapps/course_home_api/progress/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ def get(self, request, *args, **kwargs):

block = modulestore().get_course(course_key)
grading_policy = block.grading_policy
disable_progress_graph = block.disable_progress_graph
verification_status = IDVerificationService.user_status(student)
verification_link = None
if verification_status['status'] is None or verification_status['status'] == 'expired':
Expand Down Expand Up @@ -259,6 +260,7 @@ def get(self, request, *args, **kwargs):
'username': username,
'user_has_passing_grade': user_has_passing_grade,
'verification_data': verification_data,
'disable_progress_graph': disable_progress_graph,
}
context = self.get_serializer_context()
context['staff_access'] = is_staff
Expand Down
45 changes: 34 additions & 11 deletions lms/static/js/instructor_dashboard/membership.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,14 +503,20 @@ such that the value can be defined later than this assignment (file load order).
}));
$idsList = $('<ul/>');
$taskResSection.append($idsList);
for (j = 0, len1 = ids.length; j < len1; j++) {
identifier = ids[j];
$idsList.append($('<li/>', {
text: identifier
}));
}
if (ids && ids.length > 0) {
for (j = 0, len1 = ids.length; j < len1; j++) {
identifier = ids[j];
$idsList.append($('<li/>', {
text: identifier
}));
}
}
return displayResponse.$task_response.append($taskResSection);
};
if (errors.length === 0 && successes.length === 0 && noUsers.length === 0) {
// Translators: For cases when the input field is empty;
renderList(gettext('This field must not be blank'), []);
}
if (successes.length && dataFromServer.action === 'add') {
var j, len1, inActiveUsers, activeUsers; // eslint-disable-line vars-on-top
activeUsers = [];
Expand Down Expand Up @@ -585,6 +591,9 @@ such that the value can be defined later than this assignment (file load order).
sr = noUsers[j];
results.push(sr.identifier);
}
results.unshift(
gettext('Users must create and activate their account before they can be promoted to beta tester.')
);
return results;
}()));
}
Expand Down Expand Up @@ -699,14 +708,28 @@ such that the value can be defined later than this assignment (file load order).
}));
$idsList = $('<ul/>');
$taskResSection.append($idsList);
for (h = 0, len3 = ids.length; h < len3; h++) {
identifier = ids[h];
$idsList.append($('<li/>', {
text: identifier
}));
if (ids && ids.length > 0) {
for (h = 0, len3 = ids.length; h < len3; h++) {
identifier = ids[h];
$idsList.append($('<li/>', {
text: identifier
}));
}
}
return displayResponse.$task_response.append($taskResSection);
};
if (
invalidIdentifier.length === 0
&& errors.length === 0
&& enrolled.length === 0
&& allowed.length === 0
&& autoenrolled.length === 0
&& notenrolled.length === 0
&& notunenrolled.length === 0
) {
// Translators: For cases when the input field is empty;
renderList(gettext('This field must not be blank'), []);
}
if (invalidIdentifier.length) {
renderList(gettext('The following email addresses and/or usernames are invalid:'), (function() {
var m, len4, results;
Expand Down
2 changes: 1 addition & 1 deletion lms/static/sass/course/wiki/_wiki.scss
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,9 @@
a {
display: block;
padding: 2px 4px 2px 10px;
border-radius: 3px;
font-size: 0.9em;
line-height: 25px;
border-left: 1px solid $m-blue;

&:hover,
&:focus {
Expand Down
2 changes: 1 addition & 1 deletion lms/templates/header/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
% if user.is_authenticated:
<input title="preference api" type="hidden" class="url-endpoint" value="${reverse('preferences_api', kwargs={'username': user.username})}" data-user-is-authenticated="true">
% else:
<input title="session update url" type="hidden" class="url-endpoint" value="${reverse('session_language')}" data-user-is-authenticated="false">
<input title="session update url" type="hidden" class="url-endpoint" value="${reverse('update_language')}" data-user-is-authenticated="false">
% endif
<label><span class="sr">${_("Choose Language")}</span>
<select class="input select language-selector" id="settings-language-value" name="language">
Expand Down
4 changes: 2 additions & 2 deletions lms/templates/navigation/navigation.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
% if user.is_authenticated:
<input title="preference api" type="hidden" class="url-endpoint" value="${reverse('preferences_api', kwargs={'username': user.username})}" data-user-is-authenticated="true">
% else:
<input title="session update url" type="hidden" class="url-endpoint" value="${reverse('session_language')}" data-user-is-authenticated="false">
<input title="session update url" type="hidden" class="url-endpoint" value="${reverse('update_language')}" data-user-is-authenticated="false">
% endif
<label><span class="sr">${_("Choose Language")}</span>
<select class="input select language-selector" id="settings-language-value" name="language">
Expand Down Expand Up @@ -92,4 +92,4 @@

% if settings.FEATURES.get('ENABLE_COOKIE_CONSENT', False):
<%include file="../widgets/cookie-consent.html" />
% endif
% endif
2 changes: 1 addition & 1 deletion lms/templates/wiki/article.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ <h3 class="entry-title">{{ article.current_revision.title }}</h3>

{% if urlpath %}
<div class="see-children">
<a href="{% url 'wiki:dir' path=urlpath.path %}">{% trans "See all children" as tmsg %} | {{ tmsg | force_escape}}</a>
<a href="{% url 'wiki:dir' path=urlpath.path %}">{% trans "See all children" as tmsg %} {{ tmsg | force_escape}}</a>
</div>
{% endif %}
</div>
Expand Down
16 changes: 13 additions & 3 deletions openedx/core/djangoapps/credentials/tasks/v1/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,11 @@ def send_grade_if_interesting(
# Don't worry about whether it's available as well as awarded. Just awarded is good enough to record a verified
# attempt at a course. We want even the grades that didn't pass the class because Credentials wants to know about
# those too.
if mode not in INTERESTING_MODES or status not in INTERESTING_STATUSES:
if (
mode not in INTERESTING_MODES
and not CourseMode.is_eligible_for_certificate(mode)
or status not in INTERESTING_STATUSES
):
if verbose:
logger.info(f"Skipping send grade: mode/status uninteresting for mode [{mode}] & status [{status}]")
return
Expand Down Expand Up @@ -452,7 +456,10 @@ def backfill_date_for_all_course_runs():
course_key = str(course_run.id)
course_modes = CourseMode.objects.filter(course_id=course_key)
# There should only ever be one certificate relevant mode per course run
modes = [mode.slug for mode in course_modes if mode.slug in CourseMode.CERTIFICATE_RELEVANT_MODES]
modes = [
mode.slug for mode in course_modes
if mode.slug in CourseMode.CERTIFICATE_RELEVANT_MODES or CourseMode.is_eligible_for_certificate(mode.slug)
]
if len(modes) != 1:
logger.exception(
f'Either course {course_key} has no certificate mode or multiple modes. Task failed.'
Expand Down Expand Up @@ -503,7 +510,10 @@ def clean_certificate_available_date():
course_key = str(course_run.id)
course_modes = CourseMode.objects.filter(course_id=course_key)
# There should only ever be one certificate relevant mode per course run
modes = [mode.slug for mode in course_modes if mode.slug in CourseMode.CERTIFICATE_RELEVANT_MODES]
modes = [
mode.slug for mode in course_modes
if mode.slug in CourseMode.CERTIFICATE_RELEVANT_MODES or CourseMode.is_eligible_for_certificate(mode.slug)
]
if len(modes) != 1:
logger.exception(f'Either course {course_key} has no certificate mode or multiple modes. Task failed.')
# if there is only one relevant mode, post to credentials
Expand Down
10 changes: 8 additions & 2 deletions openedx/core/djangoapps/programs/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,10 @@ def update_credentials_course_certificate_configuration_available_date(
course_key = str(course_key)
course_modes = CourseMode.objects.filter(course_id=course_key)
# There should only ever be one certificate relevant mode per course run
modes = [mode.slug for mode in course_modes if mode.slug in CourseMode.CERTIFICATE_RELEVANT_MODES]
modes = [
mode.slug for mode in course_modes
if mode.slug in CourseMode.CERTIFICATE_RELEVANT_MODES or CourseMode.is_eligible_for_certificate(mode.slug)
]
if len(modes) != 1:
LOGGER.exception(
f'Either course {course_key} has no certificate mode or multiple modes. Task failed.'
Expand Down Expand Up @@ -471,7 +474,10 @@ def _retry_with_custom_exception(username, course_run_key, reason, countdown):
f"for {course_key} to user {username}"
)
return
if certificate.mode in CourseMode.CERTIFICATE_RELEVANT_MODES:
if (
certificate.mode in CourseMode.CERTIFICATE_RELEVANT_MODES
or CourseMode.is_eligible_for_certificate(certificate.mode)
):
try:
course_overview = CourseOverview.get_from_id(course_key)
except (CourseOverview.DoesNotExist, OSError):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def validate_social_link(self, social_platform, link):
('twitter', 'https://www.twiter.com/edX/', None, False),
('twitter', 'https://www.twitter.com/edX/123s', None, False),
('twitter', 'twitter.com/edX', 'https://www.twitter.com/edX', True),
('twitter', 'twitter.com/edX?foo=bar', 'https://www.twitter.com/edX', True),
('twitter', 'twitter.com/edX?foo=bar', 'https://www.twitter.com/edX?foo=bar', True),
('twitter', 'twitter.com/test.user', 'https://www.twitter.com/test.user', True),
('linkedin', 'www.linkedin.com/harryrein', None, False),
('linkedin', 'www.linkedin.com/in/harryrein-1234', 'https://www.linkedin.com/in/harryrein-1234', True),
Expand Down
6 changes: 1 addition & 5 deletions openedx/core/djangoapps/user_api/accounts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import random
import re
import string
from urllib.parse import urlparse # pylint: disable=import-error

import waffle # lint-amnesty, pylint: disable=invalid-django-waffle-import
from completion.models import BlockCompletion
Expand Down Expand Up @@ -85,11 +84,8 @@ def _get_username_from_social_link(platform_name, new_social_link):
if not new_social_link:
return new_social_link

# Parse the social link as if it were a URL.
parse_result = urlparse(new_social_link)
url_domain_and_path = parse_result[1] + parse_result[2]
url_stub = re.escape(settings.SOCIAL_PLATFORMS[platform_name]['url_stub'])
username_match = re.search(r'(www\.)?' + url_stub + r'(?P<username>.*?)[/]?$', url_domain_and_path, re.IGNORECASE)
username_match = re.search(r'(www\.)?' + url_stub + r'(?P<username>.+?)(?:/)?$', new_social_link, re.IGNORECASE)
if username_match:
username = username_match.group('username')
else:
Expand Down
11 changes: 10 additions & 1 deletion requirements/common_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,19 @@


# using LTS django version

Django<5.0

# elasticsearch>=7.14.0 includes breaking changes in it which caused issues in discovery upgrade process.
# elastic search changelog: https://www.elastic.co/guide/en/enterprise-search/master/release-notes-7.14.0.html
elasticsearch<7.14.0

# django-simple-history>3.0.0 adds indexing and causes a lot of migrations to be affected

# opentelemetry requires version 6.x at the moment:
# https://github.com/open-telemetry/opentelemetry-python/issues/3570
# Normally this could be added as a constraint in edx-django-utils, where we're
# adding the opentelemetry dependency. However, when we compile pip-tools.txt,
# that uses version 7.x, and then there's no undoing that when compiling base.txt.
# So we need to pin it globally, for now.
# Ticket for unpinning: https://github.com/openedx/edx-lint/issues/407
importlib-metadata<7
7 changes: 5 additions & 2 deletions requirements/edx/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,9 @@ defusedxml==0.7.1
# social-auth-core
deprecated==1.2.14
# via jwcrypto
django==4.2.10
django==4.2.11
# via
# -c requirements/edx/../common_constraints.txt
# -r requirements/edx/kernel.in
# django-appconf
# django-celery-results
Expand Down Expand Up @@ -610,7 +611,9 @@ idna==3.4
# snowflake-connector-python
# yarl
importlib-metadata==6.8.0
# via markdown
# via
# -c requirements/edx/../common_constraints.txt
# markdown
importlib-resources==6.1.0
# via
# jsonschema
Expand Down
4 changes: 3 additions & 1 deletion requirements/edx/development.txt
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,9 @@ distlib==0.3.7
# via
# -r requirements/edx/testing.txt
# virtualenv
django==4.2.10
django==4.2.11
# via
# -c requirements/edx/../common_constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# django-appconf
Expand Down Expand Up @@ -1011,6 +1012,7 @@ import-linter==1.12.0
# via -r requirements/edx/testing.txt
importlib-metadata==6.8.0
# via
# -c requirements/edx/../common_constraints.txt
# -r requirements/edx/../pip-tools.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
Expand Down
Loading
Loading