Skip to content

Commit

Permalink
Merge branch 'master' into keblysh/feat/correct-image-for-fb-sharing
Browse files Browse the repository at this point in the history
  • Loading branch information
vladislavkeblysh authored Jan 24, 2024
2 parents b69896e + d15aca1 commit b093976
Show file tree
Hide file tree
Showing 473 changed files with 11,825 additions and 10,348 deletions.
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,15 @@ updates:
interval: "weekly"
reviewers:
- "openedx/arbi-bom"
- package-ecosystem: "github-actions"
directory: "/.github/actions/unit-tests/"
schedule:
interval: "weekly"
reviewers:
- "openedx/arbi-bom"
- package-ecosystem: "github-actions"
directory: "/.github/actions/verify-tests-count/"
schedule:
interval: "weekly"
reviewers:
- "openedx/arbi-bom"
2 changes: 0 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
🌳🌳🌳🌳 or ask in the #wg-build-test-release Slack channel if you have any questions or need help.
🌳🌳
🌴🌴🌴🌴🌴🌴 🌴 Note: the Palm release is still supported.
Please consider whether your change should be applied to Palm as well.
Please give your pull request a short but descriptive title.
Use conventional commits to separate and summarize commits logically:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
uses: docker/setup-qemu-action@v2

- name: Login to DockerHub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/js-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
run: git fetch --depth=1 origin master

- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pylint-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- module-name: lms-1
path: "--django-settings-module=lms.envs.test lms/djangoapps/badges/ lms/djangoapps/branding/ lms/djangoapps/bulk_email/ lms/djangoapps/bulk_enroll/ lms/djangoapps/bulk_user_retirement/ lms/djangoapps/ccx/ lms/djangoapps/certificates/ lms/djangoapps/commerce/ lms/djangoapps/course_api/ lms/djangoapps/course_blocks/ lms/djangoapps/course_home_api/ lms/djangoapps/course_wiki/ lms/djangoapps/coursewarehistoryextended/ lms/djangoapps/debug/ lms/djangoapps/courseware/ lms/djangoapps/course_goals/ lms/djangoapps/rss_proxy/"
- module-name: lms-2
path: "--django-settings-module=lms.envs.test lms/djangoapps/gating/ lms/djangoapps/grades/ lms/djangoapps/instructor/ lms/djangoapps/instructor_analytics/ lms/djangoapps/discussion/ lms/djangoapps/edxnotes/ lms/djangoapps/email_marketing/ lms/djangoapps/experiments/ lms/djangoapps/instructor_task/ lms/djangoapps/learner_dashboard/ lms/djangoapps/learner_recommendations/ lms/djangoapps/learner_home/ lms/djangoapps/lms_initialization/ lms/djangoapps/lms_xblock/ lms/djangoapps/lti_provider/ lms/djangoapps/mailing/ lms/djangoapps/mobile_api/ lms/djangoapps/monitoring/ lms/djangoapps/ora_staff_grader/ lms/djangoapps/program_enrollments/ lms/djangoapps/rss_proxy lms/djangoapps/static_template_view/ lms/djangoapps/staticbook/ lms/djangoapps/support/ lms/djangoapps/survey/ lms/djangoapps/teams/ lms/djangoapps/tests/ lms/djangoapps/user_tours/ lms/djangoapps/verify_student/ lms/djangoapps/mfe_config_api/ lms/envs/ lms/lib/ lms/tests.py"
path: "--django-settings-module=lms.envs.test lms/djangoapps/gating/ lms/djangoapps/grades/ lms/djangoapps/instructor/ lms/djangoapps/instructor_analytics/ lms/djangoapps/discussion/ lms/djangoapps/edxnotes/ lms/djangoapps/email_marketing/ lms/djangoapps/experiments/ lms/djangoapps/instructor_task/ lms/djangoapps/learner_dashboard/ lms/djangoapps/learner_home/ lms/djangoapps/lms_initialization/ lms/djangoapps/lms_xblock/ lms/djangoapps/lti_provider/ lms/djangoapps/mailing/ lms/djangoapps/mobile_api/ lms/djangoapps/monitoring/ lms/djangoapps/ora_staff_grader/ lms/djangoapps/program_enrollments/ lms/djangoapps/rss_proxy lms/djangoapps/static_template_view/ lms/djangoapps/staticbook/ lms/djangoapps/support/ lms/djangoapps/survey/ lms/djangoapps/teams/ lms/djangoapps/tests/ lms/djangoapps/user_tours/ lms/djangoapps/verify_student/ lms/djangoapps/mfe_config_api/ lms/envs/ lms/lib/ lms/tests.py"
- module-name: openedx-1
path: "--django-settings-module=lms.envs.test openedx/core/types/ openedx/core/djangoapps/ace_common/ openedx/core/djangoapps/agreements/ openedx/core/djangoapps/api_admin/ openedx/core/djangoapps/auth_exchange/ openedx/core/djangoapps/bookmarks/ openedx/core/djangoapps/cache_toolbox/ openedx/core/djangoapps/catalog/ openedx/core/djangoapps/ccxcon/ openedx/core/djangoapps/commerce/ openedx/core/djangoapps/common_initialization/ openedx/core/djangoapps/common_views/ openedx/core/djangoapps/config_model_utils/ openedx/core/djangoapps/content/ openedx/core/djangoapps/content_libraries/ openedx/core/djangoapps/content_staging/ openedx/core/djangoapps/contentserver/ openedx/core/djangoapps/cookie_metadata/ openedx/core/djangoapps/cors_csrf/ openedx/core/djangoapps/course_apps/ openedx/core/djangoapps/course_date_signals/ openedx/core/djangoapps/course_groups/ openedx/core/djangoapps/courseware_api/ openedx/core/djangoapps/crawlers/ openedx/core/djangoapps/credentials/ openedx/core/djangoapps/credit/ openedx/core/djangoapps/dark_lang/ openedx/core/djangoapps/debug/ openedx/core/djangoapps/demographics/ openedx/core/djangoapps/discussions/ openedx/core/djangoapps/django_comment_common/ openedx/core/djangoapps/embargo/ openedx/core/djangoapps/enrollments/ openedx/core/djangoapps/external_user_ids/ openedx/core/djangoapps/zendesk_proxy/ openedx/core/djangolib/ openedx/core/lib/ openedx/core/tests/ openedx/core/djangoapps/course_live/"
- module-name: openedx-2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/quality-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
python-version: ${{ matrix.python-version }}

- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/static-assets-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
sudo apt-get install libxmlsec1-dev pkg-config
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

Expand Down
1 change: 0 additions & 1 deletion .github/workflows/unit-test-shards.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
"lms/djangoapps/instructor_task/",
"lms/djangoapps/learner_dashboard/",
"lms/djangoapps/learner_home/",
"lms/djangoapps/learner_recommendations/",
"lms/djangoapps/lms_initialization/",
"lms/djangoapps/lms_xblock/",
"lms/djangoapps/lti_provider/",
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ conf/locale/fake*/LC_MESSAGES/*.po
conf/locale/fake*/LC_MESSAGES/*.mo
# this was a mistake in i18n_tools, now fixed.
conf/locale/messages.mo
conf/plugins-locale/
/*/static/js/xblock.v1-i18n/

### Testing artifacts
.testids/
Expand Down
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ COPY . .
# Install Python requirements again in order to capture local projects
RUN pip install -e .

# Setting edx-platform directory as safe for git commands
RUN git config --global --add safe.directory /edx/app/edxapp/edx-platform

# Production target
FROM base as production

Expand Down
20 changes: 18 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
docker_auth docker_build docker_tag_build_push_lms docker_tag_build_push_lms_dev \
docker_tag_build_push_cms docker_tag_build_push_cms_dev docs extract_translations \
guides help lint-imports local-requirements migrate migrate-lms migrate-cms \
pre-requirements pull pull_translations push_translations requirements shell swagger \
pre-requirements pull pull_xblock_translations pull_translations push_translations \
requirements shell swagger \
technical-docs test-requirements ubuntu-requirements upgrade-package upgrade

# Careful with mktemp syntax: it has to work on Mac and Ubuntu, which have differences.
Expand Down Expand Up @@ -55,15 +56,30 @@ endif
push_translations: ## push source strings to Transifex for translation
i18n_tool transifex push

pull_translations: ## pull translations from Transifex
pull_xblock_translations: ## pull xblock translations via atlas
rm -rf conf/plugins-locale # Clean up existing atlas translations
rm -rf lms/static/i18n/xblock.v1 cms/static/i18n/xblock.v1 # Clean up existing xblock compiled translations
mkdir -p conf/plugins-locale/xblock.v1/ lms/static/js/xblock.v1-i18n cms/static/js
python manage.py lms pull_xblock_translations --verbose $(ATLAS_OPTIONS)
python manage.py lms compile_xblock_translations
cp -r lms/static/js/xblock.v1-i18n cms/static/js

pull_translations: ## pull translations from Transifex
git clean -fdX conf/locale
ifeq ($(OPENEDX_ATLAS_PULL),)
i18n_tool transifex pull
i18n_tool extract
i18n_tool dummy
i18n_tool generate --verbose 1
git clean -fdX conf/locale/rtl
git clean -fdX conf/locale/eo
i18n_tool validate --verbose
else
make pull_xblock_translations
find conf/locale -mindepth 1 -maxdepth 1 -type d -exec rm -r {} \;
atlas pull $(ATLAS_OPTIONS) translations/edx-platform/conf/locale:conf/locale
i18n_tool generate
endif
paver i18n_compilejs


Expand Down
27 changes: 26 additions & 1 deletion cms/djangoapps/cms_user_tasks/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Receivers of signals sent from django-user-tasks
"""
import logging
import re
from urllib.parse import urljoin

from django.dispatch import receiver
Expand All @@ -15,6 +16,7 @@
from .tasks import send_task_complete_email

LOGGER = logging.getLogger(__name__)
LIBRARY_CONTENT_TASK_NAME_TEMPLATE = 'updating .*type@library_content.* from library'


@receiver(user_task_stopped, dispatch_uid="cms_user_task_stopped")
Expand All @@ -33,6 +35,22 @@ def user_task_stopped_handler(sender, **kwargs): # pylint: disable=unused-argum
Returns:
None
"""

def is_library_content_update(task_name: str) -> bool:
"""
Decides whether to suppress an end-of-task email on the basis that the just-ended task was a library content
XBlock update operation, and that emails following such operations amount to spam
Arguments:
task_name: The name of the just-ended task. By convention, if this was a library content XBlock update
task, then the task name follows the pattern prescribed in LibrarySyncChildrenTask
(content_libraries under openedx) 'Updating {key} from library'. Moreover, the block type
in the task name is always of type 'library_content' for such operations
Returns:
True if the end-of-task email should be suppressed
"""
p = re.compile(LIBRARY_CONTENT_TASK_NAME_TEMPLATE)
return p.match(task_name)

def get_olx_validation_from_artifact():
"""
Get olx validation error if available for current task.
Expand All @@ -47,9 +65,17 @@ def get_olx_validation_from_artifact():
return olx_artifact.text

status = kwargs['status']

# Only send email when the entire task is complete, should only send when
# a chain / chord / etc completes, not on sub-tasks.
if status.parent is None:
task_name = status.name.lower()

# Also suppress emails on library content XBlock updates (too much like spam)
if is_library_content_update(task_name):
LOGGER.info(f"Suppressing end-of-task email on task {task_name}")
return

# `name` and `status` are not unique, first is our best guess
artifact = UserTaskArtifact.objects.filter(status=status, name="BASE_URL").first()

Expand All @@ -61,7 +87,6 @@ def get_olx_validation_from_artifact():
)

user_email = status.user.email
task_name = status.name.lower()
olx_validation_text = get_olx_validation_from_artifact()
task_args = [task_name, str(status.state_text), user_email, detail_url, olx_validation_text]
try:
Expand Down
13 changes: 13 additions & 0 deletions cms/djangoapps/cms_user_tasks/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,19 @@ def test_email_sent_with_site(self):
self.assert_msg_subject(msg)
self.assert_msg_body_fragments(msg, body_fragments)

def test_email_not_sent_with_libary_content_update(self):
"""
Check the signal receiver and email sending.
"""
UserTaskArtifact.objects.create(
status=self.status, name='BASE_URL', url='https://test.edx.org/'
)
end_of_task_status = self.status
end_of_task_status.name = "updating block-v1:course+type@library_content+block@uuid from library"
user_task_stopped.send(sender=UserTaskStatus, status=end_of_task_status)

self.assertEqual(len(mail.outbox), 0)

def test_email_sent_with_olx_validations_with_config_enabled(self):
"""
Tests that email is sent with olx validation errors.
Expand Down
63 changes: 40 additions & 23 deletions cms/djangoapps/contentstore/asset_storage_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,28 +126,41 @@ def _get_asset_usage_path(course_key, assets):
asset_key_string = str(asset_key)
static_path = StaticContent.get_static_path_from_location(asset_key)
is_video_block = getattr(block, 'category', '') == 'video'
if is_video_block:
handout = getattr(block, 'handout', '')
if handout and asset_key_string in handout:
unit = block.get_parent()
subsection = unit.get_parent()
subsection_display_name = getattr(subsection, 'display_name', '')
unit_display_name = getattr(unit, 'display_name', '')
xblock_display_name = getattr(block, 'display_name', '')
current_locations = usage_locations[asset_key_string]
new_location = f'{subsection_display_name} - {unit_display_name} / {xblock_display_name}'
usage_locations[asset_key_string] = [*current_locations, new_location]
else:
data = getattr(block, 'data', '')
if static_path in data or asset_key_string in data:
unit = block.get_parent()
subsection = unit.get_parent()
subsection_display_name = getattr(subsection, 'display_name', '')
unit_display_name = getattr(unit, 'display_name', '')
xblock_display_name = getattr(block, 'display_name', '')
current_locations = usage_locations[asset_key_string]
new_location = f'{subsection_display_name} - {unit_display_name} / {xblock_display_name}'
usage_locations[asset_key_string] = [*current_locations, new_location]
try:
if is_video_block:
handout = getattr(block, 'handout', '')
if handout and asset_key_string in handout:
usage_dict = {'display_location': '', 'url': ''}
xblock_display_name = getattr(block, 'display_name', '')
xblock_location = str(block.location)
unit = block.get_parent()
unit_location = str(block.parent)
unit_display_name = getattr(unit, 'display_name', '')
subsection = unit.get_parent()
subsection_display_name = getattr(subsection, 'display_name', '')
current_locations = usage_locations[asset_key_string]
usage_dict['display_location'] = (f'{subsection_display_name} - '
f'{unit_display_name} / {xblock_display_name}')
usage_dict['url'] = f'/container/{unit_location}#{xblock_location}'
usage_locations[asset_key_string] = [*current_locations, usage_dict]
else:
data = getattr(block, 'data', '')
if static_path in data or asset_key_string in data:
usage_dict = {'display_location': '', 'url': ''}
xblock_display_name = getattr(block, 'display_name', '')
xblock_location = str(block.location)
unit = block.get_parent()
unit_location = str(block.parent)
unit_display_name = getattr(unit, 'display_name', '')
subsection = unit.get_parent()
subsection_display_name = getattr(subsection, 'display_name', '')
current_locations = usage_locations[asset_key_string]
usage_dict['display_location'] = (f'{subsection_display_name} - '
f'{unit_display_name} / {xblock_display_name}')
usage_dict['url'] = f'/container/{unit_location}#{xblock_location}'
usage_locations[asset_key_string] = [*current_locations, usage_dict]
except AttributeError:
continue
return usage_locations


Expand Down Expand Up @@ -435,11 +448,15 @@ def _get_assets_in_json_format(assets, course_key, assets_usage_locations_map):
for asset in assets:
asset_key = asset['asset_key']
asset_key_string = str(asset_key)
usage_locations = getattr(assets_usage_locations_map, 'asset_key_string', [])
thumbnail_asset_key = _get_thumbnail_asset_key(asset, course_key)
asset_is_locked = asset.get('locked', False)
asset_file_size = asset.get('length', None)

try:
usage_locations = assets_usage_locations_map[asset_key_string]
except KeyError:
usage_locations = []

asset_in_json = get_asset_json(
asset['displayname'],
asset['contentType'],
Expand Down
3 changes: 3 additions & 0 deletions cms/djangoapps/contentstore/course_info_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from django.http import HttpResponseBadRequest
from django.utils.translation import gettext as _

from cms.djangoapps.contentstore.utils import track_course_update_event
from openedx.core.lib.xblock_utils import get_course_update_items
from xmodule.html_block import CourseInfoBlock # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
Expand Down Expand Up @@ -85,6 +86,8 @@ def update_course_updates(location, update, passed_id=None, user=None):

# update db record
save_course_update_items(location, course_updates, course_update_items, user)
# track course update event
track_course_update_event(location.course_key, user, course_update_dict)
# remove status key
if "status" in course_update_dict:
del course_update_dict["status"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
0003: Hybrid approach for public course authoring APIs
======================================================

Status
------

Rejected

Reason for rejection
--------------------

The objectives for public authoring APIs changed from the time this decision was made:
We are now limiting our offering to a set of experimental APIs with which to flesh our what a supported set of APIs might become. As such, the authoring APIs we are now implementing
are just a public set of wrappers around existing functionality, and are not fit for production course authoring. The responsibility for avoiding conflicts and resolving them, if they occur, is on the user.

Context
-------

Expand Down
Loading

0 comments on commit b093976

Please sign in to comment.