Skip to content

Commit

Permalink
Merge pull request #658 from open-craft/sync-open-release/quince.mast…
Browse files Browse the repository at this point in the history
…er-20240520-1716214773

Sync opencraft-release/quince.1 with Upstream 20240520-1716214773
  • Loading branch information
Agrendalath committed May 20, 2024
2 parents 96efd39 + 3ff69fd commit 13eaa68
Show file tree
Hide file tree
Showing 18 changed files with 125 additions and 44 deletions.
7 changes: 6 additions & 1 deletion cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2284,7 +2284,6 @@

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


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

Expand All @@ -2300,6 +2299,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
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/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
4 changes: 3 additions & 1 deletion requirements/edx/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,9 @@ deprecated==1.2.14
# via
# -r requirements/edx/base.txt
# jwcrypto
django==4.2.10
django==4.2.11
# via
# -c requirements/edx/../common_constraints.txt
# -r requirements/edx/base.txt
# django-appconf
# django-celery-results
Expand Down Expand Up @@ -711,6 +712,7 @@ imagesize==1.4.1
# via sphinx
importlib-metadata==6.8.0
# via
# -c requirements/edx/../common_constraints.txt
# -r requirements/edx/base.txt
# markdown
# sphinx
Expand Down
4 changes: 3 additions & 1 deletion requirements/edx/testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,9 @@ dill==0.3.7
# via pylint
distlib==0.3.7
# via virtualenv
django==4.2.10
django==4.2.11
# via
# -c requirements/edx/../common_constraints.txt
# -r requirements/edx/base.txt
# django-appconf
# django-celery-results
Expand Down Expand Up @@ -767,6 +768,7 @@ import-linter==1.12.0
# via -r requirements/edx/testing.in
importlib-metadata==6.8.0
# via
# -c requirements/edx/../common_constraints.txt
# -r requirements/edx/base.txt
# markdown
# pytest-randomly
Expand Down
Loading

0 comments on commit 13eaa68

Please sign in to comment.