From b7b87e06a8e1051a42b65aec42a9528dc934464f Mon Sep 17 00:00:00 2001 From: Muhammad Arslan Date: Mon, 6 Jan 2025 16:41:54 +0500 Subject: [PATCH 1/8] feat: edx-username-changer plugin added --- .github/workflows/ci.yml | 8 +- src/edx_username_changer/BUILD | 21 ++++ src/edx_username_changer/LICENCE | 28 ++++++ src/edx_username_changer/README.rst | 60 ++++++++++++ src/edx_username_changer/__init__.py | 3 + src/edx_username_changer/admin.py | 38 ++++++++ src/edx_username_changer/apps.py | 33 +++++++ src/edx_username_changer/exceptions.py | 18 ++++ src/edx_username_changer/signals.py | 42 ++++++++ src/edx_username_changer/tasks.py | 42 ++++++++ src/edx_username_changer/utils.py | 128 +++++++++++++++++++++++++ 11 files changed, 417 insertions(+), 4 deletions(-) create mode 100644 src/edx_username_changer/BUILD create mode 100644 src/edx_username_changer/LICENCE create mode 100644 src/edx_username_changer/README.rst create mode 100644 src/edx_username_changer/__init__.py create mode 100644 src/edx_username_changer/admin.py create mode 100644 src/edx_username_changer/apps.py create mode 100644 src/edx_username_changer/exceptions.py create mode 100644 src/edx_username_changer/signals.py create mode 100644 src/edx_username_changer/tasks.py create mode 100644 src/edx_username_changer/utils.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da6dc92a..5d49feb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,8 +10,8 @@ jobs: - 3.11 edx_branch: - master - - open-release/quince.master - open-release/redwood.master + - open-release/sumac.master # Add more branches as needed steps: @@ -31,13 +31,13 @@ jobs: - name: Install tutor run: | - if [[ "${{ matrix.edx_branch }}" == "open-release/quince.master" ]]; then - pip install tutor==17.0.6 + if [[ "${{ matrix.edx_branch }}" == "open-release/redwood.master" ]]; then + pip install tutor==18.2.2 elif [[ "${{ matrix.edx_branch }}" == "master" ]]; then git clone --branch=main https://github.com/overhangio/tutor.git pip install -e "./tutor" else - pip install tutor==18.0.0 + pip install tutor==19.0.0 fi - name: Set up tutor with edx-platform diff --git a/src/edx_username_changer/BUILD b/src/edx_username_changer/BUILD new file mode 100644 index 00000000..b77364fd --- /dev/null +++ b/src/edx_username_changer/BUILD @@ -0,0 +1,21 @@ +python_distribution( + name="edx_username_changer_package", + provides=setup_py( + name="edx-username-changer", + version="0.3.3", + description="An edX plugin to change username of edx accounts through admin panel", + license="BSD-3-Clause", + author="MIT Office of Digital Learning", + include_package_data=True, + zip_safe=False, + keywords="Python edx", + entry_points={ + "lms.djangoapp": [ + "edx_username_changer = edx_username_changer.apps:EdxUsernameChangerConfig", + ], + "cms.djangoapp": [ + "edx_username_changer = edx_username_changer.apps:EdxUsernameChangerConfig", + ], + }, + ), +) diff --git a/src/edx_username_changer/LICENCE b/src/edx_username_changer/LICENCE new file mode 100644 index 00000000..83284fb7 --- /dev/null +++ b/src/edx_username_changer/LICENCE @@ -0,0 +1,28 @@ +Copyright (C) 2022 MIT Open Learning + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/edx_username_changer/README.rst b/src/edx_username_changer/README.rst new file mode 100644 index 00000000..af7aa2da --- /dev/null +++ b/src/edx_username_changer/README.rst @@ -0,0 +1,60 @@ +Edx Username Changer +======================= + +A plugin to enable update usernames through admin panel in Open edX (and other apps that log into Open edX via OAuth). + +Version Compatibility +--------------------- + +It only supports koa and latest releases of Open edX. + +Installing The Plugin +--------------------- + +You can install this plugin into any Open edX instance by using any of the following methods: + +**Option 1: Install from PyPI** + +.. code-block:: + + # If running devstack in docker, first open a shell in LMS (make lms-shell) + + pip install edx-username-changer + + +**Option 2: Build the package locally and install it** + +Follow these steps in a terminal on your machine: + +1. Navigate to ``edx-username-changer`` directory +2. If you haven't done so already, run ``./pants build`` +3. Run ``./pants package ::``. This will create a "dist" directory inside "open-edx-plugins" directory with ".whl" & ".tar.gz" format packages for all plugins in the src directory +4. Move/copy any of the ".whl" or ".tar.gz" files for this plugin that were generated in the above step to the machine/container running Open edX (NOTE: If running devstack via Docker, you can use ``docker cp`` to copy these files into your LMS or CMS containers) +5. Run a shell in the machine/container running Open edX, and install this plugin using pip + + +``Note``: In some cases you might need to restart edx-platform after installing the plugin to reflect the changes. + +Configurations +-------------- +To configure this plugin, you need to do the following one step: + +1. Add/Enable a feature flag (ENABLE_EDX_USERNAME_CHANGER) into your environment variables (through lms.yml or studio.yml, depending upon where you are installing the plugin) + +.. code-block:: + ... + ... + ENABLE_EDX_USERNAME_CHANGER: true + ... + +How to use +---------- +Its usage is as simple as changing the username of a user account through django's admin panel. Here are the steps (for clarity): + +1. Install edx-username-changer plugin. +2. Use an admin account to access django admin panel. +3. Go to Users model and select an account to change its username. +4. In the account editor page change the username field. +5. Hit Save (present at the bottom-right of page). + +The whole process can be done on lms or studio or on both of them. diff --git a/src/edx_username_changer/__init__.py b/src/edx_username_changer/__init__.py new file mode 100644 index 00000000..b4832711 --- /dev/null +++ b/src/edx_username_changer/__init__.py @@ -0,0 +1,3 @@ +# pylint: disable=missing-module-docstring + +default_app_config = "edx_username_changer.apps.EdxUsernameChangerConfig" diff --git a/src/edx_username_changer/admin.py b/src/edx_username_changer/admin.py new file mode 100644 index 00000000..9b0aebb8 --- /dev/null +++ b/src/edx_username_changer/admin.py @@ -0,0 +1,38 @@ +""" +Django admin pages for edx-username-changer plugin +""" + +import contextlib + +from common.djangoapps.student.admin import ( + UserAdmin as BaseUserAdmin, +) +from django.conf import settings +from django.contrib import admin +from django.contrib.admin.sites import NotRegistered +from django.contrib.auth import get_user_model + +User = get_user_model() + + +class UserAdmin(BaseUserAdmin): + """ + Admin interface for the User model. + """ + + def get_readonly_fields(self, request, obj=None): + """ + Remove 'username' from the read-only fields + to make it editable through the admin panel + """ + readonly_fields = super().get_readonly_fields(request, obj) + if settings.FEATURES.get("ENABLE_EDX_USERNAME_CHANGER") and obj: + return tuple([name for name in readonly_fields if name != "username"]) + return readonly_fields + + +# We must first un-register the User model since it was registered by edX's core code. +with contextlib.suppress(NotRegistered): + admin.site.unregister(User) + +admin.site.register(User, UserAdmin) diff --git a/src/edx_username_changer/apps.py b/src/edx_username_changer/apps.py new file mode 100644 index 00000000..ecb3433f --- /dev/null +++ b/src/edx_username_changer/apps.py @@ -0,0 +1,33 @@ +""" +App configuration for edx-username-changer plugin +""" + +from django.apps import AppConfig +from edx_django_utils.plugins.constants import PluginSignals +from openedx.core.djangoapps.plugins.constants import ( + ProjectType, +) + + +class EdxUsernameChangerConfig(AppConfig): + name = "edx_username_changer" + verbose_name = "Open edX Username Changer" + + plugin_app = { + PluginSignals.CONFIG: { + ProjectType.LMS: { + PluginSignals.RECEIVERS: [ + { + PluginSignals.RECEIVER_FUNC_NAME: "user_pre_save_callback", + PluginSignals.SIGNAL_PATH: "django.db.models.signals.pre_save", + PluginSignals.SENDER_PATH: "django.contrib.auth.models.User", + }, + { + PluginSignals.RECEIVER_FUNC_NAME: "user_post_save_callback", + PluginSignals.SIGNAL_PATH: "django.db.models.signals.post_save", + PluginSignals.SENDER_PATH: "django.contrib.auth.models.User", + }, + ], + }, + }, + } diff --git a/src/edx_username_changer/exceptions.py b/src/edx_username_changer/exceptions.py new file mode 100644 index 00000000..3bacc579 --- /dev/null +++ b/src/edx_username_changer/exceptions.py @@ -0,0 +1,18 @@ +""" +Exceptions for edx-username-changer plugin +""" + + +class UpdateFailedException(Exception): # noqa: N818 + """ + Exception to throw when there is an update failure in username + """ + + def __init__(self, url, new_username): + self.url = url + self.new_username = new_username + + def __str__(self): + return ( + f"Username update failed for username: {self.new_username}, url: {self.url}" + ) diff --git a/src/edx_username_changer/signals.py b/src/edx_username_changer/signals.py new file mode 100644 index 00000000..774129ec --- /dev/null +++ b/src/edx_username_changer/signals.py @@ -0,0 +1,42 @@ +""" +Signals and Signal Handlers for edx-username-changer plugin +""" + +from common.djangoapps.util.model_utils import ( # pylint: disable=import-error + get_changed_fields_dict, +) +from django.conf import settings +from django.db import transaction +from tasks import task_update_username_in_forum +from utils import update_user_social_auth_uid + + +def user_pre_save_callback(sender, **kwargs): + """ + Pre-save signal handler of User model to store changed fields to be used later + """ + if settings.FEATURES.get("ENABLE_EDX_USERNAME_CHANGER"): + user = kwargs["instance"] + fields_to_update = get_changed_fields_dict(user, sender) + if "username" in fields_to_update: + fields_to_update.update({"new_username": user.username}) + user._updated_fields = fields_to_update # noqa: SLF001 + + +def user_post_save_callback(sender, **kwargs): # noqa: ARG001 + """ + Post-save signal handler of User model to update username throughout the application + """ + if settings.FEATURES.get("ENABLE_EDX_USERNAME_CHANGER"): + user = kwargs["instance"] + if ( + hasattr(user, "_updated_fields") + and user._updated_fields # noqa: SLF001 + and {"username", "new_username"}.issubset(user._updated_fields) # noqa: SLF001 + ): + new_username = user._updated_fields["new_username"] # noqa: SLF001 + transaction.on_commit( + lambda: task_update_username_in_forum.delay(new_username) + ) + update_user_social_auth_uid(user._updated_fields["username"], new_username) # noqa: SLF001 + delattr(user, "_updated_fields") diff --git a/src/edx_username_changer/tasks.py b/src/edx_username_changer/tasks.py new file mode 100644 index 00000000..abf38d75 --- /dev/null +++ b/src/edx_username_changer/tasks.py @@ -0,0 +1,42 @@ +""" +This file contains celery tasks related to edx_username_changer plugin. +""" + +from celery import shared_task +from django.contrib.auth import get_user_model +from openedx.core.djangoapps.django_comment_common.comment_client.user import ( + User as CommentUser, +) +from utils import ( + get_authored_threads_and_comments, + get_enrolled_course_ids, + update_comment_user_username, + update_comment_username, + update_thread_username, +) + +COMMENT_TYPE = "comment" +THREAD_TYPE = "thread" +User = get_user_model() + + +@shared_task() +def task_update_username_in_forum(username): + """ + Change username in Discussion-Forum service + """ + user = User.objects.get(username=username) + comment_user = CommentUser.from_django_user(user) + update_comment_user_username(comment_user, user.username) + enrolled_course_ids = get_enrolled_course_ids(user) + authored_items = get_authored_threads_and_comments( + comment_user, enrolled_course_ids + ) + + for authored_item in authored_items: + item_id = authored_item["id"] + item_type = str(authored_item.get("type")) + if item_type == THREAD_TYPE: + update_thread_username(item_id, user.username) + elif item_type == COMMENT_TYPE: + update_comment_username(item_id, user.username) diff --git a/src/edx_username_changer/utils.py b/src/edx_username_changer/utils.py new file mode 100644 index 00000000..981b1310 --- /dev/null +++ b/src/edx_username_changer/utils.py @@ -0,0 +1,128 @@ +""" +Utility methods for edx-username-changer plugin +""" + +from common.djangoapps.student.models import ( + CourseEnrollment, +) +from django.contrib.auth import get_user_model +from django.db import transaction +from exceptions import UpdateFailedException +from openedx.core.djangoapps.django_comment_common.comment_client.comment import ( + Comment, +) +from openedx.core.djangoapps.django_comment_common.comment_client.thread import ( + Thread, +) +from openedx.core.djangoapps.django_comment_common.comment_client.utils import ( + perform_request as perform_forum_request, +) +from social_django.models import UserSocialAuth + +User = get_user_model() + + +def update_user_social_auth_uid(old_username, new_username): + """ + Change uid in django-social-auth for OAuth based user accounts + iff uid is based on username otherwise it doesn't make any effect + """ + with transaction.atomic(): + UserSocialAuth.objects.filter(uid=old_username).update(uid=new_username) + + +def get_enrolled_course_ids(user): + """ + Return course ids of all the active enrollments of the provided user + """ + return [ + str(enrollment.course_id) + for enrollment in CourseEnrollment.enrollments_for_user(user) + ] + + +def get_involved_threads(course_id, user_id): + """ + Return an iterator of all the discussion-forum threads + against provided user and course + """ + page = 0 + involved_threads = [] + while len(involved_threads) > 0 or page == 0: + involved_threads = [ + Thread.find(id=thread["id"]).retrieve( + with_responses=True, recursive=True, mark_as_read=False + ) + for thread in Thread.search( + {"course_id": course_id, "user_id": user_id, "page": page} + ).collection + ] + yield from involved_threads + page += 1 + + +def get_authored_threads_and_comments(comment_user, enrolled_course_ids): + """ + Return an iterator of all the discussion-forum threads + and comments of provided user and course + """ + + for course_id in enrolled_course_ids: + involved_threads = get_involved_threads(course_id, comment_user.id) + for thread in involved_threads: + if thread["user_id"] == comment_user.id: + yield thread.to_dict() + + children_to_scan = ( + thread.get("children", []) + + thread.get("endorsed_responses", []) + + thread.get("non_endorsed_responses", []) + ) + + while children_to_scan: + child = children_to_scan.pop(0) + children_to_scan.extend(child["children"]) + if child["user_id"] == comment_user.id: + yield child + + +def update_comment_user_username(comment_user, new_username): + """ + Update username for discussion-forum comment-users via Forum APIs + """ + user_detail_url = comment_user.url_with_id(params={"id": comment_user.id}) + response_data = perform_forum_request( + "put", + user_detail_url, + data_or_params={"username": new_username}, + ) + if response_data["username"] != new_username: + raise UpdateFailedException(url=user_detail_url, new_username=new_username) + + +def update_thread_username(thread_id, new_username): + """ + Update username for discussion-forum threads via Forum APIs + """ + thread_detail_url = Thread.url_with_id(params={"id": thread_id}) + response_data = perform_forum_request( + "put", + thread_detail_url, + data_or_params={"username": new_username}, + ) + if response_data["username"] != new_username: + raise UpdateFailedException(url=thread_detail_url, new_username=new_username) + + +def update_comment_username(comment_id, new_username): + """ + Update username for discussion-forum comments via Forum APIs + """ + comment_detail_url = Comment.url_for_comments(params={"parent_id": comment_id}) + response_data = perform_forum_request( + "put", + comment_detail_url, + data_or_params={"username": new_username}, + ) + if response_data["username"] != new_username: + raise UpdateFailedException(url=comment_detail_url, new_username=new_username) From 99deec7757bbdbaddaab1cc32bcc0c1b4258a4a3 Mon Sep 17 00:00:00 2001 From: Muhammad Arslan Date: Mon, 6 Jan 2025 18:06:11 +0500 Subject: [PATCH 2/8] fix: absolute import added --- src/edx_username_changer/signals.py | 4 ++-- src/edx_username_changer/tasks.py | 8 ++++---- src/edx_username_changer/utils.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/edx_username_changer/signals.py b/src/edx_username_changer/signals.py index 774129ec..5cf1ee7d 100644 --- a/src/edx_username_changer/signals.py +++ b/src/edx_username_changer/signals.py @@ -7,8 +7,8 @@ ) from django.conf import settings from django.db import transaction -from tasks import task_update_username_in_forum -from utils import update_user_social_auth_uid +from edx_username_changer.tasks import task_update_username_in_forum +from edx_username_changer.utils import update_user_social_auth_uid def user_pre_save_callback(sender, **kwargs): diff --git a/src/edx_username_changer/tasks.py b/src/edx_username_changer/tasks.py index abf38d75..8cbcd59f 100644 --- a/src/edx_username_changer/tasks.py +++ b/src/edx_username_changer/tasks.py @@ -4,16 +4,16 @@ from celery import shared_task from django.contrib.auth import get_user_model -from openedx.core.djangoapps.django_comment_common.comment_client.user import ( - User as CommentUser, -) -from utils import ( +from edx_username_changer.utils import ( get_authored_threads_and_comments, get_enrolled_course_ids, update_comment_user_username, update_comment_username, update_thread_username, ) +from openedx.core.djangoapps.django_comment_common.comment_client.user import ( + User as CommentUser, +) COMMENT_TYPE = "comment" THREAD_TYPE = "thread" diff --git a/src/edx_username_changer/utils.py b/src/edx_username_changer/utils.py index 981b1310..0f2481f9 100644 --- a/src/edx_username_changer/utils.py +++ b/src/edx_username_changer/utils.py @@ -7,7 +7,7 @@ ) from django.contrib.auth import get_user_model from django.db import transaction -from exceptions import UpdateFailedException +from edx_username_changer.exceptions import UpdateFailedException from openedx.core.djangoapps.django_comment_common.comment_client.comment import ( Comment, ) From 062be2afae7f3b1b4ed297d8a0b4bdddb3cb6cab Mon Sep 17 00:00:00 2001 From: Muhammad Arslan Date: Mon, 6 Jan 2025 20:30:14 +0500 Subject: [PATCH 3/8] build: paver removed from OpenedX master --- .github/workflows/ci.yml | 2 +- run_devstack_integration_tests.sh | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d49feb4..9df3a643 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,7 +60,7 @@ jobs: DIRECTORY="tutor" DEV="tutor_dev" fi - EDX_WORKSPACE=$PWD/.. docker compose -f /home/runner/.local/share/$DIRECTORY/env/local/docker-compose.yml -f /home/runner/.local/share/$DIRECTORY/env/dev/docker-compose.yml --project-name $DEV run -v $PWD/../open-edx-plugins:/open-edx-plugins lms /open-edx-plugins/run_devstack_integration_tests.sh + EDX_WORKSPACE=$PWD/.. docker compose -f /home/runner/.local/share/$DIRECTORY/env/local/docker-compose.yml -f /home/runner/.local/share/$DIRECTORY/env/dev/docker-compose.yml --project-name $DEV run -v $PWD/../open-edx-plugins:/open-edx-plugins lms /open-edx-plugins/run_devstack_integration_tests.sh "${{ matrix.edx_branch }}" - name: Upload coverage to CodeCov uses: codecov/codecov-action@v4 diff --git a/run_devstack_integration_tests.sh b/run_devstack_integration_tests.sh index 9be8adff..a1cdcf5b 100755 --- a/run_devstack_integration_tests.sh +++ b/run_devstack_integration_tests.sh @@ -8,13 +8,20 @@ pwd mkdir -p reports pip install -r ./requirements/edx/testing.txt -pip install -r ./requirements/edx/paver.txt +if [ "$1" != "master" ]; then + pip install -r ./requirements/edx/paver.txt +fi # Installing edx-platform pip install -e . mkdir -p test_root # for edx -paver update_assets lms --settings=test_static_optimized + +if [ "$1" != "master" ]; then + paver update_assets lms --settings=test_static_optimized +else + npm run build && ./manage.py lms collectstatic --noinput && ./manage.py cms collectstatic --noinput +fi cp test_root/staticfiles/lms/webpack-stats.json test_root/staticfiles/webpack-stats.json cd /open-edx-plugins From de300330bf2eeddb71d5af66041069176a264e07 Mon Sep 17 00:00:00 2001 From: Muhammad Arslan Date: Mon, 6 Jan 2025 21:09:27 +0500 Subject: [PATCH 4/8] build: missing webpack static file fixed --- run_devstack_integration_tests.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/run_devstack_integration_tests.sh b/run_devstack_integration_tests.sh index a1cdcf5b..5f08b012 100755 --- a/run_devstack_integration_tests.sh +++ b/run_devstack_integration_tests.sh @@ -17,13 +17,14 @@ pip install -e . mkdir -p test_root # for edx -if [ "$1" != "master" ]; then - paver update_assets lms --settings=test_static_optimized -else +if [ "$1" == "master" ]; then npm run build && ./manage.py lms collectstatic --noinput && ./manage.py cms collectstatic --noinput + cp /openedx/staticfiles/webpack-stats.json test_root/staticfiles/webpack-stats.json +else + paver update_assets lms --settings=test_static_optimized + cp test_root/staticfiles/lms/webpack-stats.json test_root/staticfiles/webpack-stats.json fi -cp test_root/staticfiles/lms/webpack-stats.json test_root/staticfiles/webpack-stats.json cd /open-edx-plugins # Installing test dependencies From b13a9b6287a06ae616f71747f1f564d9610fe645 Mon Sep 17 00:00:00 2001 From: Muhammad Arslan Date: Tue, 7 Jan 2025 14:10:59 +0500 Subject: [PATCH 5/8] revert: Revert github action updates --- .github/workflows/ci.yml | 10 +++++----- run_devstack_integration_tests.sh | 14 +++----------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9df3a643..da6dc92a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,8 +10,8 @@ jobs: - 3.11 edx_branch: - master + - open-release/quince.master - open-release/redwood.master - - open-release/sumac.master # Add more branches as needed steps: @@ -31,13 +31,13 @@ jobs: - name: Install tutor run: | - if [[ "${{ matrix.edx_branch }}" == "open-release/redwood.master" ]]; then - pip install tutor==18.2.2 + if [[ "${{ matrix.edx_branch }}" == "open-release/quince.master" ]]; then + pip install tutor==17.0.6 elif [[ "${{ matrix.edx_branch }}" == "master" ]]; then git clone --branch=main https://github.com/overhangio/tutor.git pip install -e "./tutor" else - pip install tutor==19.0.0 + pip install tutor==18.0.0 fi - name: Set up tutor with edx-platform @@ -60,7 +60,7 @@ jobs: DIRECTORY="tutor" DEV="tutor_dev" fi - EDX_WORKSPACE=$PWD/.. docker compose -f /home/runner/.local/share/$DIRECTORY/env/local/docker-compose.yml -f /home/runner/.local/share/$DIRECTORY/env/dev/docker-compose.yml --project-name $DEV run -v $PWD/../open-edx-plugins:/open-edx-plugins lms /open-edx-plugins/run_devstack_integration_tests.sh "${{ matrix.edx_branch }}" + EDX_WORKSPACE=$PWD/.. docker compose -f /home/runner/.local/share/$DIRECTORY/env/local/docker-compose.yml -f /home/runner/.local/share/$DIRECTORY/env/dev/docker-compose.yml --project-name $DEV run -v $PWD/../open-edx-plugins:/open-edx-plugins lms /open-edx-plugins/run_devstack_integration_tests.sh - name: Upload coverage to CodeCov uses: codecov/codecov-action@v4 diff --git a/run_devstack_integration_tests.sh b/run_devstack_integration_tests.sh index 5f08b012..9be8adff 100755 --- a/run_devstack_integration_tests.sh +++ b/run_devstack_integration_tests.sh @@ -8,23 +8,15 @@ pwd mkdir -p reports pip install -r ./requirements/edx/testing.txt -if [ "$1" != "master" ]; then - pip install -r ./requirements/edx/paver.txt -fi +pip install -r ./requirements/edx/paver.txt # Installing edx-platform pip install -e . mkdir -p test_root # for edx +paver update_assets lms --settings=test_static_optimized -if [ "$1" == "master" ]; then - npm run build && ./manage.py lms collectstatic --noinput && ./manage.py cms collectstatic --noinput - cp /openedx/staticfiles/webpack-stats.json test_root/staticfiles/webpack-stats.json -else - paver update_assets lms --settings=test_static_optimized - cp test_root/staticfiles/lms/webpack-stats.json test_root/staticfiles/webpack-stats.json -fi - +cp test_root/staticfiles/lms/webpack-stats.json test_root/staticfiles/webpack-stats.json cd /open-edx-plugins # Installing test dependencies From ddc5f7ae5d98d611da59f919279336f7f840b9da Mon Sep 17 00:00:00 2001 From: Muhammad Arslan Date: Wed, 8 Jan 2025 19:33:51 +0500 Subject: [PATCH 6/8] build: keeping the version same --- src/edx_username_changer/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edx_username_changer/BUILD b/src/edx_username_changer/BUILD index b77364fd..7355c5f7 100644 --- a/src/edx_username_changer/BUILD +++ b/src/edx_username_changer/BUILD @@ -2,7 +2,7 @@ python_distribution( name="edx_username_changer_package", provides=setup_py( name="edx-username-changer", - version="0.3.3", + version="0.3.2", description="An edX plugin to change username of edx accounts through admin panel", license="BSD-3-Clause", author="MIT Office of Digital Learning", From 2454ea4134cfdaaccc8b6413ca423e2754b1f305 Mon Sep 17 00:00:00 2001 From: Muhammad Arslan Date: Thu, 9 Jan 2025 14:33:57 +0500 Subject: [PATCH 7/8] fix: pants build fixed --- src/edx_username_changer/BUILD | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/edx_username_changer/BUILD b/src/edx_username_changer/BUILD index 7355c5f7..b0b8ec28 100644 --- a/src/edx_username_changer/BUILD +++ b/src/edx_username_changer/BUILD @@ -1,5 +1,12 @@ +python_sources( + name="edx_username_changer_source", +) + python_distribution( name="edx_username_changer_package", + dependencies=[ + ":edx_username_changer_source", + ], provides=setup_py( name="edx-username-changer", version="0.3.2", From 4e55cc87b0208eb3f2a0761395d8253799e23228 Mon Sep 17 00:00:00 2001 From: Muhammad Arslan Date: Thu, 9 Jan 2025 16:45:51 +0500 Subject: [PATCH 8/8] docs: unnecessary steps removed --- src/edx_username_changer/README.rst | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/edx_username_changer/README.rst b/src/edx_username_changer/README.rst index af7aa2da..9c00fc8d 100644 --- a/src/edx_username_changer/README.rst +++ b/src/edx_username_changer/README.rst @@ -26,11 +26,10 @@ You can install this plugin into any Open edX instance by using any of the follo Follow these steps in a terminal on your machine: -1. Navigate to ``edx-username-changer`` directory -2. If you haven't done so already, run ``./pants build`` -3. Run ``./pants package ::``. This will create a "dist" directory inside "open-edx-plugins" directory with ".whl" & ".tar.gz" format packages for all plugins in the src directory -4. Move/copy any of the ".whl" or ".tar.gz" files for this plugin that were generated in the above step to the machine/container running Open edX (NOTE: If running devstack via Docker, you can use ``docker cp`` to copy these files into your LMS or CMS containers) -5. Run a shell in the machine/container running Open edX, and install this plugin using pip +1. Navigate to ``open-edx-plugins`` directory +2. Run ``./pants package ::``. This will create a "dist" directory inside "open-edx-plugins" directory with ".whl" & ".tar.gz" format packages for all plugins in the src directory +3. Move/copy any of the ".whl" or ".tar.gz" files for this plugin that were generated in the above step to the machine/container running Open edX (NOTE: If running devstack via Docker, you can use ``docker cp`` to copy these files into your LMS or CMS containers) +4. Run a shell in the machine/container running Open edX, and install this plugin using pip ``Note``: In some cases you might need to restart edx-platform after installing the plugin to reflect the changes. @@ -39,13 +38,10 @@ Configurations -------------- To configure this plugin, you need to do the following one step: -1. Add/Enable a feature flag (ENABLE_EDX_USERNAME_CHANGER) into your environment variables (through lms.yml or studio.yml, depending upon where you are installing the plugin) +1. Add/Enable a feature flag (ENABLE_EDX_USERNAME_CHANGER) into your environment variables (through ``private.py`` in LMS or CMS, depending upon where you are installing the plugin) .. code-block:: - ... - ... - ENABLE_EDX_USERNAME_CHANGER: true - ... + FEATURES["ENABLE_EDX_USERNAME_CHANGER"] = True How to use ----------