Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
fb693bf
feat: allow switching anonymous user ID hashing algorithm from shake …
kaustavb12 Aug 8, 2022
22b4445
temp: Add configuration option to redirect to external site when TAP …
xitij2000 May 24, 2023
bfa2081
feat: all eSHE role features squashed in one commit
0x29a Jun 26, 2023
5fb5130
feat: DEFAULT_COURSE_INVITATION_ONLY allow for invitation_only new co…
viadanna Apr 9, 2024
9e735ad
feat: add a feature flag to disable dates tab for all courses
Cup0fCoffee Apr 15, 2024
ad27ea7
feat: tpa automatic logout with a single redirect
CefBoud Apr 16, 2024
11688bd
feat: Allow trusted apps to perform cookie login.
Kelketek Sep 6, 2023
f7bcad0
fix: prevent redirects to /undefined after saml auth
tecoholic Aug 13, 2024
c4d4814
feat: in-context discussion for units can be disabled by default (#676)
kaustavb12 Sep 2, 2024
ecaa84f
fix: unhide discussion tab when enabling it (#677)
viadanna Sep 4, 2024
36d5889
fix: unhide discussion tab when enabling it (#677)
viadanna Sep 4, 2024
7fcc1ad
feat: add has_course_author_access to CourseHomeMetadataView response…
0x29a Sep 10, 2024
5c74009
feat: allow Bearer auth for sequence metadata
0x29a Oct 23, 2024
b2d3651
feat: User agreements API for generic agreement records
xitij2000 Nov 20, 2024
735a77c
fix: use a single 'provider_type' key for storing discussion provider…
0x29a Dec 24, 2024
ea05de5
fix: remove incorrect key type when filtering inaccessible blocks
Agrendalath Sep 7, 2024
1d2384f
chore: bump ora2 fork
viadanna Mar 7, 2025
793b7b1
Merge pull request #35713 from openedx/feanil/ubuntu-24.04
feanil Nov 7, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/check-consistent-dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ defaults:
jobs:
check-requirements:
name: Compile requirements
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04

steps:
# Only run remaining steps if there are changes to requirements/**
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
matrix:
python-version:
- "3.11"
os: ["ubuntu-22.04"]
os: ["ubuntu-24.04"]

steps:
- uses: actions/checkout@v4
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/migrations-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04]
os: [ubuntu-24.04]
python-version:
- "3.11"
# 'pinned' is used to install the latest patch version of Django
Expand Down Expand Up @@ -126,7 +126,7 @@ jobs:
if: always()
needs:
- check_migrations
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Decide whether the needed jobs succeeded or failed
# uses: re-actors/alls-green@v1.2.1
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pylint-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
run-pylint:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -75,7 +75,7 @@ jobs:
if: always()
needs:
- run-pylint
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Decide whether the needed jobs succeeded or failed
# uses: re-actors/alls-green@v1.2.1
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 @@ -13,7 +13,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04]
os: [ubuntu-24.04]
python-version:
- "3.11"
node-version: [20]
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 @@ -12,7 +12,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04]
os: [ubuntu-24.04]
python-version:
- "3.11"
node-version: [18, 20]
Expand Down
62 changes: 29 additions & 33 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ concurrency:
jobs:
run-tests:
name: ${{ matrix.shard_name }}(py=${{ matrix.python-version }},dj=${{ matrix.django-version }},mongo=${{ matrix.mongo-version }})
runs-on: ubuntu-22.04
runs-on: ${{ matrix.os-version }}
strategy:
matrix:
python-version:
Expand Down Expand Up @@ -43,22 +43,27 @@ jobs:
- "xmodule-with-cms"
mongo-version:
- "7.0"
os-version:
- ubuntu-24.04

# We only need to test older versions of Mongo with modules that directly interface with Mongo (that is: xmodule.modulestore)
# This code is left here as an example for future refernce in case we need to reduce the number of shards we're
# testing but still have good confidence with older versions of mongo. We use Mongo 4.4 in the example.
# It's useful to run some subset of the tests on the older version of Ubuntu
# so that we don't spend too many resources on this but can find major issues quickly
# while we're in a situation where we support two versions. This section may be commented
# out when not in use to easily add/drop future support for any given major dependency.
#
# exclude:
# - mongo-version: "4.4"
# include:
# - shard_name: "xmodule-with-cms"
# python-version: "3.11"
# django-version: "pinned"
# mongo-version: "4.4"
# - shard_name: "xmodule-with-lms"
# python-version: "3.11"
# django-version: "pinned"
# mongo-version: "4.4"
# We're testing the older version of Ubuntu and running the xmodule tests since those rely on many
# dependent complex libraries and will hopefully catch most issues quickly.
include:
- shard_name: "xmodule-with-cms"
python-version: "3.11"
django-version: "pinned"
mongo-version: "7.0"
os-version: "ubuntu-22.04"
- shard_name: "xmodule-with-lms"
python-version: "3.11"
django-version: "pinned"
mongo-version: "7.0"
os-version: "ubuntu-22.04"

steps:
- name: checkout repo
Expand Down Expand Up @@ -90,19 +95,10 @@ jobs:
activate = 1
EOF

- name: install mongo version
run: |
if [[ "${{ matrix.mongo-version }}" != "4.4" ]]; then
wget -qO - https://www.mongodb.org/static/pgp/server-${{ matrix.mongo-version }}.asc | sudo apt-key add -
echo "deb https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/${{ matrix.mongo-version }} multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-${{ matrix.mongo-version }}.list
sudo apt-get update && sudo apt-get install -y mongodb-org="${{ matrix.mongo-version }}.*"
fi

- name: start mongod server for tests
run: |
sudo mkdir -p /data/db
sudo chmod -R a+rw /data/db
mongod &
- name: Start MongoDB
uses: supercharge/mongodb-github-action@1.11.0
with:
mongodb-version: ${{ matrix.mongo-version }}

- name: Setup Python
uses: actions/setup-python@v5
Expand Down Expand Up @@ -164,7 +160,7 @@ jobs:
overwrite: true

collect-and-verify:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup Python
Expand Down Expand Up @@ -229,7 +225,7 @@ jobs:
# https://github.com/orgs/community/discussions/33579
success:
name: Unit tests successful
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
if: always()
needs: [run-tests]
steps:
Expand All @@ -240,7 +236,7 @@ jobs:
jobs: ${{ toJSON(needs) }}

compile-warnings-report:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
needs: [run-tests]
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -268,7 +264,7 @@ jobs:
overwrite: true

merge-artifacts:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
needs: [compile-warnings-report]
steps:
- name: Merge Pytest Warnings JSON Artifacts
Expand All @@ -288,7 +284,7 @@ jobs:
# Combine and upload coverage reports.
coverage:
if: (github.repository == 'edx/edx-platform-private') || (github.repository == 'openedx/edx-platform' && (startsWith(github.base_ref, 'open-release') == false))
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
needs: [run-tests]
strategy:
matrix:
Expand Down
2 changes: 1 addition & 1 deletion cms/djangoapps/contentstore/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,11 +454,11 @@ def sync_discussion_settings(course_key, user):
if (
ENABLE_NEW_STRUCTURE_DISCUSSIONS.is_enabled()
and not course.discussions_settings['provider_type'] == Provider.OPEN_EDX
and not course.discussions_settings['provider'] == Provider.OPEN_EDX
):
LOGGER.info(f"New structure is enabled, also updating {course_key} to use new provider")
course.discussions_settings['enable_graded_units'] = False
course.discussions_settings['unit_level_visibility'] = True
course.discussions_settings['provider'] = Provider.OPEN_EDX
course.discussions_settings['provider_type'] = Provider.OPEN_EDX
modulestore().update_item(course, user.id)

Expand Down
10 changes: 10 additions & 0 deletions cms/djangoapps/contentstore/tests/test_contentstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,16 @@ def test_create_course_with_unicode_in_id_disabled(self):
self.course_data['run'] = '����������'
self.assert_create_course_failed(error_message)

@override_settings(DEFAULT_COURSE_INVITATION_ONLY=True)
def test_create_course_invitation_only(self):
"""
Test new course creation with setting: DEFAULT_COURSE_INVITATION_ONLY=True.
"""
test_course_data = self.assert_created_course()
course_id = _get_course_id(self.store, test_course_data)
course = self.store.get_course(course_id)
self.assertEqual(course.invitation_only, True)

def assert_course_permission_denied(self):
"""
Checks that the course did not get created due to a PermissionError.
Expand Down
3 changes: 2 additions & 1 deletion cms/djangoapps/contentstore/views/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -1006,8 +1006,9 @@ def create_new_course_in_store(store, user, org, number, run, fields):

# Set default language from settings and enable web certs
fields.update({
'language': getattr(settings, 'DEFAULT_COURSE_LANGUAGE', 'en'),
'cert_html_view_enabled': True,
'invitation_only': getattr(settings, 'DEFAULT_COURSE_INVITATION_ONLY', False),
'language': getattr(settings, 'DEFAULT_COURSE_LANGUAGE', 'en'),
})

with modulestore().default_store(store):
Expand Down
23 changes: 23 additions & 0 deletions cms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,25 @@
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2024-04-10
'BADGES_ENABLED': False,

# .. toggle_name: FEATURES['IN_CONTEXT_DISCUSSION_ENABLED_DEFAULT']
# .. toggle_implementation: DjangoSetting
# .. toggle_default: True
# .. toggle_description: Set to False to not enable in-context discussion for units by default.
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2024-09-02
'IN_CONTEXT_DISCUSSION_ENABLED_DEFAULT': True,

# .. toggle_name: FEATURES['ENABLE_LEGACY_MD5_HASH_FOR_ANONYMOUS_USER_ID']
# .. toggle_implementation: DjangoSetting
# .. toggle_default: False
# .. toggle_description: Whether to enable the legacy MD5 hashing algorithm to generate anonymous user id
# instead of the newer SHAKE128 hashing algorithm
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2022-08-08
# .. toggle_target_removal_date: None
# .. toggle_tickets: 'https://github.com/openedx/edx-platform/pull/30832'
'ENABLE_LEGACY_MD5_HASH_FOR_ANONYMOUS_USER_ID': False,
}

# .. toggle_name: ENABLE_COPPA_COMPLIANCE
Expand Down Expand Up @@ -2943,3 +2962,7 @@ def _should_send_learning_badge_events(settings):
# .. for now it wil impact country listing in auth flow and user profile.
# .. eg ['US', 'CA']
DISABLED_COUNTRIES = []

############## Default value for invitation_only when creating courses ##############

DEFAULT_COURSE_INVITATION_ONLY = False
14 changes: 8 additions & 6 deletions common/djangoapps/student/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def user_has_role(user, role):
return False


def get_user_permissions(user, course_key, org=None):
def get_user_permissions(user, course_key, org=None, service_variant=None):
"""
Get the bitmask of permissions that this user has in the given course context.
Can also set course_key=None and pass in an org to get the user's
Expand Down Expand Up @@ -103,7 +103,7 @@ def get_user_permissions(user, course_key, org=None):
# the LMS and Studio permissions will be separated as a part of this project. Once this is done (and this code is
# not removed during its implementation), we can replace the Limited Staff permissions with more granular ones.
if course_key and user_has_role(user, CourseLimitedStaffRole(course_key)):
if settings.SERVICE_VARIANT == 'lms':
if (service_variant or settings.SERVICE_VARIANT) == 'lms':
return STUDIO_EDIT_CONTENT
else:
return STUDIO_NO_PERMISSIONS
Expand All @@ -119,7 +119,7 @@ def get_user_permissions(user, course_key, org=None):
return STUDIO_NO_PERMISSIONS


def has_studio_write_access(user, course_key):
def has_studio_write_access(user, course_key, service_variant=None):
"""
Return True if user has studio write access to the given course.
Note that the CMS permissions model is with respect to courses.
Expand All @@ -131,15 +131,17 @@ def has_studio_write_access(user, course_key):

:param user:
:param course_key: a CourseKey
:param service_variant: the variant of the service (lms or cms). Permissions may differ between the two,
see the comment in get_user_permissions for more details.
"""
return bool(STUDIO_EDIT_CONTENT & get_user_permissions(user, course_key))
return bool(STUDIO_EDIT_CONTENT & get_user_permissions(user, course_key, service_variant=service_variant))


def has_course_author_access(user, course_key):
def has_course_author_access(user, course_key, service_variant=None):
"""
Old name for has_studio_write_access
"""
return has_studio_write_access(user, course_key)
return has_studio_write_access(user, course_key, service_variant)


def has_studio_advanced_settings_access(user):
Expand Down
13 changes: 11 additions & 2 deletions common/djangoapps/student/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,21 @@ def anonymous_id_for_user(user, course_id):
# function: Rotate at will, since the hashes are stored and
# will not change.
# include the secret key as a salt, and to make the ids unique across different LMS installs.
hasher = hashlib.shake_128()
legacy_hash_enabled = settings.FEATURES.get('ENABLE_LEGACY_MD5_HASH_FOR_ANONYMOUS_USER_ID', False)
if legacy_hash_enabled:
# Use legacy MD5 algorithm if flag enabled
hasher = hashlib.md5()
else:
hasher = hashlib.shake_128()
hasher.update(settings.SECRET_KEY.encode('utf8'))
hasher.update(str(user.id).encode('utf8'))
if course_id:
hasher.update(str(course_id).encode('utf-8'))
anonymous_user_id = hasher.hexdigest(16)

if legacy_hash_enabled:
anonymous_user_id = hasher.hexdigest()
else:
anonymous_user_id = hasher.hexdigest(16) # pylint: disable=too-many-function-args

try:
AnonymousUserId.objects.create(
Expand Down
21 changes: 20 additions & 1 deletion common/djangoapps/student/roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ class GlobalStaff(AccessRole):
The global staff role
"""
def has_user(self, user):
return bool(user and user.is_staff)
return bool(user and (user.is_superuser or user.is_staff))

def add_users(self, *users):
for user in users:
Expand Down Expand Up @@ -361,6 +361,25 @@ class CourseLimitedStaffRole(CourseStaffRole):
BASE_ROLE = CourseStaffRole.ROLE


@register_access_role
class eSHEInstructorRole(CourseStaffRole):
"""A Staff member of a course without access to the membership tab and enrollment-related operations."""

ROLE = 'eshe_instructor'
BASE_ROLE = CourseStaffRole.ROLE


@register_access_role
class TeachingAssistantRole(CourseStaffRole):
"""
A Staff member of a course without access to the membership tab, enrollment-related operations and
grade-related operations.
"""

ROLE = 'teaching_assistant'
BASE_ROLE = CourseStaffRole.ROLE


@register_access_role
class CourseInstructorRole(CourseRole):
"""A course Instructor"""
Expand Down
4 changes: 4 additions & 0 deletions common/djangoapps/student/tests/test_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
CourseStaffRole,
CourseFinanceAdminRole,
CourseSalesAdminRole,
eSHEInstructorRole,
TeachingAssistantRole,
LibraryUserRole,
CourseDataResearcherRole,
GlobalStaff,
Expand Down Expand Up @@ -199,6 +201,8 @@ class RoleCacheTestCase(TestCase): # lint-amnesty, pylint: disable=missing-clas
ROLES = (
(CourseStaffRole(IN_KEY), ('staff', IN_KEY, 'edX')),
(CourseLimitedStaffRole(IN_KEY), ('limited_staff', IN_KEY, 'edX')),
(eSHEInstructorRole(IN_KEY), ('eshe_instructor', IN_KEY, 'edX')),
(TeachingAssistantRole(IN_KEY), ('teaching_assistant', IN_KEY, 'edX')),
(CourseInstructorRole(IN_KEY), ('instructor', IN_KEY, 'edX')),
(OrgStaffRole(IN_KEY.org), ('staff', None, 'edX')),
(CourseFinanceAdminRole(IN_KEY), ('finance_admin', IN_KEY, 'edX')),
Expand Down
Loading
Loading