Skip to content

Commit

Permalink
Merge branch 'master' into navin/fal-4014/fix-modal-padding
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisChV authored Jan 10, 2025
2 parents 0f45297 + 5ae7187 commit 320f099
Show file tree
Hide file tree
Showing 30 changed files with 405 additions and 331 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ jobs:
run: |
sudo apt-get update && sudo apt-get install libmysqlclient-dev libxmlsec1-dev lynx
- name: Login to Docker Hub
uses: docker/[email protected]
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

- name: Start MongoDB
uses: supercharge/[email protected]
with:
Expand Down Expand Up @@ -197,7 +203,6 @@ jobs:
to add any missing apps and match the count. for more details please take a look at scripts/gha-shards-readme.md"
exit 1
# This job aggregates test results. It's the required check for branch protection.
# https://github.com/marketplace/actions/alls-green#why
# https://github.com/orgs/community/discussions/33579
Expand Down
2 changes: 2 additions & 0 deletions common/djangoapps/student/models/course_enrollment.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,8 @@ def enroll(cls, user, course_key, mode=None, check_access=False, can_upgrade=Fal
Also emits relevant events for analytics purposes.
"""
try:
# .. filter_implemented_name: CourseEnrollmentStarted
# .. filter_type: org.openedx.learning.course.enrollment.started.v1
user, course_key, mode = CourseEnrollmentStarted.run_filter(
user=user, course_key=course_key, mode=mode,
)
Expand Down
3 changes: 3 additions & 0 deletions common/djangoapps/student/views/management.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
from common.djangoapps.student.models import ( # lint-amnesty, pylint: disable=unused-import
AccountRecovery,
CourseEnrollment,
EnrollmentNotAllowed,
PendingEmailChange, # unimport:skip
PendingSecondaryEmailChange,
Registration,
Expand Down Expand Up @@ -422,6 +423,8 @@ def change_enrollment(request, check_access=True):
enroll_mode = CourseMode.auto_enroll_mode(course_id, available_modes)
if enroll_mode:
CourseEnrollment.enroll(user, course_id, check_access=check_access, mode=enroll_mode)
except EnrollmentNotAllowed as exc:
return HttpResponseBadRequest(str(exc))
except Exception: # pylint: disable=broad-except
return HttpResponseBadRequest(_("Could not enroll"))

Expand Down
Binary file modified common/static/data/geoip/GeoLite2-Country.mmdb
Binary file not shown.
6 changes: 5 additions & 1 deletion lms/djangoapps/bulk_email/signals.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""
Signal handlers for the bulk_email app
"""
import logging

from django.dispatch import receiver
from eventtracking import tracker

Expand All @@ -10,6 +12,8 @@

from .models import Optout

log = logging.getLogger(__name__)


@receiver(USER_RETIRE_MAILINGS)
def force_optout_all(sender, **kwargs): # lint-amnesty, pylint: disable=unused-argument
Expand Down Expand Up @@ -43,7 +47,7 @@ def ace_email_sent_handler(sender, **kwargs):
if not course_id:
course_email = context.get('course_email', None)
course_id = course_email.course_id if course_email else None

log.info(f'Email sent for {message_name} for course {course_id} using channel {channel}')
tracker.emit(
'edx.ace.message_sent',
{
Expand Down
11 changes: 0 additions & 11 deletions lms/djangoapps/grades/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,12 +467,6 @@ def update_or_create_grade(cls, **params):
defaults=params,
)

# TODO: Remove as part of EDUCATOR-4602.
if str(usage_key.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Created/updated grade ***{}*** for user ***{}*** in course ***{}***'
'for subsection ***{}*** with default params ***{}***'
.format(grade, user_id, usage_key.course_key, usage_key, params))

grade.override = PersistentSubsectionGradeOverride.get_override(user_id, usage_key)
if first_attempted is not None and grade.first_attempted is None:
grade.first_attempted = first_attempted
Expand Down Expand Up @@ -822,11 +816,6 @@ def update_or_create_override(
grade_defaults['override_reason'] = override_data['comment'] if 'comment' in override_data else None
grade_defaults['system'] = override_data['system'] if 'system' in override_data else None

# TODO: Remove as part of EDUCATOR-4602.
if str(subsection_grade_model.course_id) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Creating override for user ***{}*** for PersistentSubsectionGrade'
'***{}*** with override data ***{}*** and derived grade_defaults ***{}***.'
.format(requesting_user, subsection_grade_model, override_data, grade_defaults))
try:
override = PersistentSubsectionGradeOverride.objects.get(grade=subsection_grade_model)
for key, value in grade_defaults.items():
Expand Down
5 changes: 0 additions & 5 deletions lms/djangoapps/grades/rest_api/v1/gradebook_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -859,11 +859,6 @@ def post(self, request, course_key):
subsection = course.get_child(usage_key)
if subsection:
subsection_grade_model = self._create_subsection_grade(user, course, subsection)
# TODO: Remove as part of EDUCATOR-4602.
if str(course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('PersistentSubsectionGrade ***{}*** created for'
' subsection ***{}*** in course ***{}*** for user ***{}***.'
.format(subsection_grade_model, subsection.location, course, user.id))
else:
self._log_update_result(request.user, requested_user_id, requested_usage_id, success=False)
result.append(GradebookUpdateResponseItem(
Expand Down
20 changes: 0 additions & 20 deletions lms/djangoapps/grades/scores.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ def get_score(submissions_scores, csm_scores, persisted_block, block):
weight, graded - retrieved from the latest block content
"""
weight = _get_weight_from_block(persisted_block, block)
# TODO: Remove as part of EDUCATOR-4602.
if str(block.location.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Weight for block: ***{}*** is {}'
.format(str(block.location), weight))

# Priority order for retrieving the scores:
# submissions API -> CSM -> grades persisted block -> latest block content
Expand All @@ -115,13 +111,6 @@ def get_score(submissions_scores, csm_scores, persisted_block, block):
_get_score_from_persisted_or_latest_block(persisted_block, block, weight)
)

# TODO: Remove as part of EDUCATOR-4602.
if str(block.location.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Calculated raw-earned: {}, raw_possible: {}, weighted_earned: '
'{}, weighted_possible: {}, first_attempted: {} for block: ***{}***.'
.format(raw_earned, raw_possible, weighted_earned,
weighted_possible, first_attempted, str(block.location)))

if weighted_possible is None or weighted_earned is None:
return None

Expand Down Expand Up @@ -219,22 +208,13 @@ def _get_score_from_persisted_or_latest_block(persisted_block, block, weight):
Uses the raw_possible value from the persisted_block if found, else from
the latest block content.
"""
# TODO: Remove as part of EDUCATOR-4602.
if str(block.location.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Using _get_score_from_persisted_or_latest_block to calculate score for block: ***{}***.'.format(
str(block.location)
))
raw_earned = 0.0
first_attempted = None

if persisted_block:
raw_possible = persisted_block.raw_possible
else:
raw_possible = block.transformer_data[GradesTransformer].max_score
# TODO: Remove as part of EDUCATOR-4602.
if str(block.location.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Using latest block content to calculate score for block: ***{}***.')
log.info(f'weight for block: ***{str(block.location)}*** is {raw_possible}.')

# TODO TNL-5982 remove defensive code for scorables without max_score
if raw_possible is None:
Expand Down
37 changes: 1 addition & 36 deletions lms/djangoapps/grades/subsection_grade.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,39 +170,21 @@ def _compute_block_score( # lint-amnesty, pylint: disable=missing-function-docs
csm_scores,
persisted_block=None,
):
# TODO: Remove as part of EDUCATOR-4602.
if str(block_key.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Computing block score for block: ***{}*** in course: ***{}***.'.format(
str(block_key),
str(block_key.course_key),
))
try:
block = course_structure[block_key]
except KeyError:
# TODO: Remove as part of EDUCATOR-4602.
if str(block_key.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('User\'s access to block: ***{}*** in course: ***{}*** has changed. '
'No block score calculated.'.format(str(block_key), str(block_key.course_key)))
# It's possible that the user's access to that
# block has changed since the subsection grade
# was last persisted.
pass
else:
if getattr(block, 'has_score', False):
# TODO: Remove as part of EDUCATOR-4602.
if str(block_key.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Block: ***{}*** in course: ***{}*** HAS has_score attribute. Continuing.'
.format(str(block_key), str(block_key.course_key)))
return get_score(
submissions_scores,
csm_scores,
persisted_block,
block,
)
# TODO: Remove as part of EDUCATOR-4602.
if str(block_key.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Block: ***{}*** in course: ***{}*** DOES NOT HAVE has_score attribute. '
'No block score calculated.'
.format(str(block_key), str(block_key.course_key)))

@staticmethod
def _aggregated_score_from_model(grade_model, is_graded):
Expand Down Expand Up @@ -283,35 +265,18 @@ def __init__(self, subsection, course_structure, submissions_scores, csm_scores)
start_node=subsection.location,
):
problem_score = self._compute_block_score(block_key, course_structure, submissions_scores, csm_scores)

# TODO: Remove as part of EDUCATOR-4602.
if str(block_key.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Calculated problem score ***{}*** for block ***{!s}***'
' in subsection ***{}***.'
.format(problem_score, block_key, subsection.location))
if problem_score:
self.problem_scores[block_key] = problem_score

all_total, graded_total = graders.aggregate_scores(list(self.problem_scores.values()))

# TODO: Remove as part of EDUCATOR-4602.
if str(subsection.location.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Calculated aggregate all_total ***{}***'
' and grade_total ***{}*** for subsection ***{}***'
.format(all_total, graded_total, subsection.location))

super().__init__(subsection, all_total, graded_total)

def update_or_create_model(self, student, score_deleted=False, force_update_subsections=False):
"""
Saves or updates the subsection grade in a persisted model.
"""
if self._should_persist_per_attempted(score_deleted, force_update_subsections):
# TODO: Remove as part of EDUCATOR-4602.
if str(self.location.course_key) == 'course-v1:UQx+BUSLEAD5x+2T2019':
log.info('Updating PersistentSubsectionGrade for student ***{}*** in'
' subsection ***{}*** with params ***{}***.'
.format(student.id, self.location, self._persisted_model_params(student)))
model = PersistentSubsectionGrade.update_or_create_grade(**self._persisted_model_params(student))

if hasattr(model, 'override'):
Expand Down
5 changes: 3 additions & 2 deletions openedx/core/djangoapps/content_libraries/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
from openedx.core.lib.api.view_utils import view_auth_classes
from openedx.core.djangoapps.safe_sessions.middleware import mark_user_change_as_expected
from openedx.core.djangoapps.xblock import api as xblock_api
from openedx.core.types.http import RestRequest

from .models import ContentLibrary, LtiGradedResource, LtiProfile

Expand Down Expand Up @@ -667,7 +668,7 @@ class LibraryBlockCollectionsView(APIView):
View to set collections for a component.
"""
@convert_exceptions
def patch(self, request, usage_key_str) -> Response:
def patch(self, request: RestRequest, usage_key_str) -> Response:
"""
Sets Collections for a Component.
Expand All @@ -688,7 +689,7 @@ def patch(self, request, usage_key_str) -> Response:
library_key=key.lib_key,
component=component,
collection_keys=collection_keys,
created_by=self.request.user.id,
created_by=request.user.id,
content_library=content_library,
)

Expand Down
17 changes: 9 additions & 8 deletions openedx/core/djangoapps/content_libraries/views_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
ContentLibraryCollectionComponentsUpdateSerializer,
ContentLibraryCollectionUpdateSerializer,
)
from openedx.core.types.http import RestRequest


class LibraryCollectionsView(ModelViewSet):
Expand Down Expand Up @@ -89,23 +90,23 @@ def get_object(self) -> Collection:
return collection

@convert_exceptions
def retrieve(self, request, *args, **kwargs) -> Response:
def retrieve(self, request: RestRequest, *args, **kwargs) -> Response:
"""
Retrieve the Content Library Collection
"""
# View declared so we can wrap it in @convert_exceptions
return super().retrieve(request, *args, **kwargs)

@convert_exceptions
def list(self, request, *args, **kwargs) -> Response:
def list(self, request: RestRequest, *args, **kwargs) -> Response:
"""
List Collections that belong to Content Library
"""
# View declared so we can wrap it in @convert_exceptions
return super().list(request, *args, **kwargs)

@convert_exceptions
def create(self, request, *args, **kwargs) -> Response:
def create(self, request: RestRequest, *args, **kwargs) -> Response:
"""
Create a Collection that belongs to a Content Library
"""
Expand Down Expand Up @@ -139,7 +140,7 @@ def create(self, request, *args, **kwargs) -> Response:
return Response(serializer.data)

@convert_exceptions
def partial_update(self, request, *args, **kwargs) -> Response:
def partial_update(self, request: RestRequest, *args, **kwargs) -> Response:
"""
Update a Collection that belongs to a Content Library
"""
Expand All @@ -161,7 +162,7 @@ def partial_update(self, request, *args, **kwargs) -> Response:
return Response(serializer.data)

@convert_exceptions
def destroy(self, request, *args, **kwargs) -> Response:
def destroy(self, request: RestRequest, *args, **kwargs) -> Response:
"""
Soft-deletes a Collection that belongs to a Content Library
"""
Expand All @@ -176,7 +177,7 @@ def destroy(self, request, *args, **kwargs) -> Response:

@convert_exceptions
@action(detail=True, methods=['post'], url_path='restore', url_name='collection-restore')
def restore(self, request, *args, **kwargs) -> Response:
def restore(self, request: RestRequest, *args, **kwargs) -> Response:
"""
Restores a soft-deleted Collection that belongs to a Content Library
"""
Expand All @@ -191,7 +192,7 @@ def restore(self, request, *args, **kwargs) -> Response:

@convert_exceptions
@action(detail=True, methods=['delete', 'patch'], url_path='components', url_name='components-update')
def update_components(self, request, *args, **kwargs) -> Response:
def update_components(self, request: RestRequest, *args, **kwargs) -> Response:
"""
Adds (PATCH) or removes (DELETE) Components to/from a Collection.
Expand All @@ -209,7 +210,7 @@ def update_components(self, request, *args, **kwargs) -> Response:
content_library=content_library,
collection_key=collection_key,
usage_keys=usage_keys,
created_by=self.request.user.id,
created_by=request.user.id,
remove=(request.method == "DELETE"),
)

Expand Down
4 changes: 2 additions & 2 deletions openedx/core/djangoapps/content_staging/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def save_xblock_to_user_clipboard(block: XBlock, user_id: int, version_num: int
olx=block_data.olx_str,
display_name=block_metadata_utils.display_name_with_default(block),
suggested_url_name=usage_key.block_id,
tags=block_data.tags,
tags=block_data.tags or {},
version_num=(version_num or 0),
)
(clipboard, _created) = _UserClipboard.objects.update_or_create(user_id=user_id, defaults={
Expand Down Expand Up @@ -209,7 +209,7 @@ def _user_clipboard_model_to_data(clipboard: _UserClipboard) -> UserClipboardDat
status=content.status,
block_type=content.block_type,
display_name=content.display_name,
tags=content.tags,
tags=content.tags or {},
version_num=content.version_num,
),
source_usage_key=clipboard.source_usage_key,
Expand Down
4 changes: 3 additions & 1 deletion openedx/core/djangoapps/content_staging/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ class Meta:
version_num = models.PositiveIntegerField(default=0)

# Tags applied to the original source block(s) will be copied to the new block(s) on paste.
tags = models.JSONField(null=True, help_text=_("Content tags applied to these blocks"))
tags: models.JSONField[dict | None, dict | None] = models.JSONField(
null=True, help_text=_("Content tags applied to these blocks")
)

@property
def olx_filename(self) -> str:
Expand Down
Loading

0 comments on commit 320f099

Please sign in to comment.