Skip to content

Commit

Permalink
Merge branch 'open-release/palm.master' into fix-FB-share-Palm
Browse files Browse the repository at this point in the history
  • Loading branch information
e0d authored Jun 28, 2023
2 parents bf1c434 + 42e84e3 commit e48a132
Show file tree
Hide file tree
Showing 33 changed files with 422 additions and 233 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/migrations-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ jobs:
- name: Install Python dependencies
run: |
make dev-requirements
pip uninstall -y mysqlclient
pip install --no-binary mysqlclient mysqlclient
pip uninstall -y xmlsec
pip install --no-binary xmlsec xmlsec
- name: Initiate Services
run: |
Expand All @@ -78,6 +74,11 @@ jobs:
UPDATE mysql.user SET authentication_string = null WHERE user = 'root';
FLUSH PRIVILEGES;
EOF
- name: Install mysqlclient-dev binary
run: |
sudo apt-get update
sudo apt-get install -y libmysqlclient-dev
- name: Run Tests
env:
Expand Down
39 changes: 20 additions & 19 deletions .github/workflows/unit-tests-gh-hosted.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,32 @@ on:

jobs:
run-test:
if: github.repository != 'openedx/edx-platform' && github.repository != 'edx/edx-platform-private'
if: (github.repository != 'openedx/edx-platform' && github.repository != 'edx/edx-platform-private') || (github.repository == 'openedx/edx-platform' && (startsWith(github.base_ref, 'open-release') == true))
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
python-version: [ '3.8' ]
django-version:
- "pinned"
shard_name: [
"lms-1",
"lms-2",
"lms-3",
"lms-4",
"lms-5",
"lms-6",
"openedx-1",
"openedx-2",
"openedx-3",
"openedx-4",
"cms-1",
"cms-2",
"common-1",
"common-2",
"common-3",
]
# When updating the shards, remember to make the same changes in
# .github/workflows/unit-tests.yml
shard_name:
- "lms-1"
- "lms-2"
- "lms-3"
- "lms-4"
- "lms-5"
- "lms-6"
- "openedx-1"
- "openedx-2"
- "openedx-3"
- "openedx-4"
- "cms-1"
- "cms-2"
- "common-1"
- "common-2"
- "xmodule-1"
name: gh-hosted-python-${{ matrix.python-version }},django-${{ matrix.django-version }},${{ matrix.shard_name }}
steps:
- uses: actions/checkout@v2
Expand Down Expand Up @@ -78,7 +79,7 @@ jobs:
uses: ./.github/actions/unit-tests

collect-and-verify:
if: github.repository != 'openedx/edx-platform' && github.repository != 'edx/edx-platform-private'
if: (github.repository != 'openedx/edx-platform' && github.repository != 'edx/edx-platform-private') || (github.repository == 'openedx/edx-platform' && (startsWith(github.base_ref, 'open-release') == true))
runs-on: ubuntu-20.04
strategy:
matrix:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
jobs:
run-tests:
name: python-${{ matrix.python-version }},django-${{ matrix.django-version }},${{ matrix.shard_name }}
if: github.repository == 'edx/edx-platform-private' || github.repository == 'openedx/edx-platform'
if: (github.repository == 'edx/edx-platform-private') || (github.repository == 'openedx/edx-platform' && (startsWith(github.base_ref, 'open-release') == false))
runs-on: [ edx-platform-runner ]
strategy:
matrix:
Expand All @@ -18,6 +18,8 @@ jobs:
django-version:
- "pinned"
#- "4.0"
# When updating the shards, remember to make the same changes in
# .github/workflows/unit-tests-gh-hosted.yml
shard_name:
- "lms-1"
- "lms-2"
Expand Down Expand Up @@ -80,7 +82,7 @@ jobs:
# https://github.com/orgs/community/discussions/33579
success:
name: Tests successful
if: always()
if: (github.repository == 'edx/edx-platform-private') || (github.repository == 'openedx/edx-platform' && (startsWith(github.base_ref, 'open-release') == false))
needs:
- run-tests
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/verify-gha-unit-tests-count.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
collect-and-verify:
if: github.repository == 'edx/edx-platform-private' || github.repository == 'openedx/edx-platform'
if: (github.repository == 'edx/edx-platform-private') || (github.repository == 'openedx/edx-platform' && (startsWith(github.base_ref, 'open-release') == false))
runs-on: [ edx-platform-runner ]
steps:
- name: sync directory owner
Expand Down
28 changes: 15 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ pull: ## update the Docker image used by "make shell"
docker pull edxops/edxapp:latest

pre-requirements: ## install Python requirements for running pip-tools
pip install -qr requirements/pip.txt
pip install -qr requirements/edx/pip-tools.txt
pip install -r requirements/pip.txt
pip install -r requirements/pip-tools.txt

local-requirements:
# edx-platform installs some Python projects from within the edx-platform repo itself.
Expand All @@ -74,7 +74,7 @@ local-requirements:
dev-requirements: pre-requirements
@# The "$(wildcard..)" is to include private.txt if it exists, and make no mention
@# of it if it does not. Shell wildcarding can't do that with default options.
pip-sync -q requirements/edx/development.txt $(wildcard requirements/edx/private.txt)
pip-sync requirements/edx/development.txt $(wildcard requirements/edx/private.txt)
make local-requirements

base-requirements: pre-requirements
Expand All @@ -96,7 +96,6 @@ shell: ## launch a bash shell in a Docker container with all edx-platform depend

# Order is very important in this list: files must appear after everything they include!
REQ_FILES = \
requirements/edx/pip-tools \
requirements/edx/coverage \
requirements/edx/doc \
requirements/edx/paver \
Expand All @@ -117,23 +116,26 @@ $(COMMON_CONSTRAINTS_TXT):
echo "$(COMMON_CONSTRAINTS_TEMP_COMMENT)" | cat - $(@) > temp && mv temp $(@)

compile-requirements: export CUSTOM_COMPILE_COMMAND=make upgrade
compile-requirements: $(COMMON_CONSTRAINTS_TXT) ## Re-compile *.in requirements to *.txt
pip install -q pip-tools
pip-compile --allow-unsafe --upgrade -o requirements/edx/pip.txt requirements/edx/pip.in
compile-requirements: pre-requirements $(COMMON_CONSTRAINTS_TXT) ## Re-compile *.in requirements to *.txt
@# Bootstrapping: Rebuild pip and pip-tools first, and then install them
@# so that if there are any failures we'll know now, rather than the next
@# time someone tries to use the outputs.
pip-compile -v --allow-unsafe ${COMPILE_OPTS} -o requirements/pip.txt requirements/pip.in
pip install -r requirements/pip.txt

pip-compile -v ${COMPILE_OPTS} -o requirements/pip-tools.txt requirements/pip-tools.in
pip install -r requirements/pip-tools.txt

@ export REBUILD='--rebuild'; \
for f in $(REQ_FILES); do \
echo ; \
echo "== $$f ===============================" ; \
echo "pip-compile -v --no-emit-trusted-host --no-emit-index-url $$REBUILD ${COMPILE_OPTS} -o $$f.txt $$f.in"; \
pip-compile -v --no-emit-trusted-host --no-emit-index-url $$REBUILD ${COMPILE_OPTS} -o $$f.txt $$f.in || exit 1; \
echo "pip-compile -v $$REBUILD ${COMPILE_OPTS} -o $$f.txt $$f.in"; \
pip-compile -v $$REBUILD ${COMPILE_OPTS} -o $$f.txt $$f.in || exit 1; \
export REBUILD=''; \
done

pip install -qr requirements/edx/pip.txt
pip install -qr requirements/edx/pip-tools.txt

upgrade: pre-requirements ## update the pip requirements files to use the latest releases satisfying our constraints
upgrade: ## update the pip requirements files to use the latest releases satisfying our constraints
$(MAKE) compile-requirements COMPILE_OPTS="--upgrade"

check-types: ## run static type-checking tests
Expand Down
59 changes: 49 additions & 10 deletions cms/djangoapps/contentstore/tests/test_course_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,12 @@ def setUp(self):
super().setUp()
self.fullcourse = CourseFactory.create()
self.course_setting_url = get_url(self.course.id, 'advanced_settings_handler')
self.non_staff_client, _ = self.create_non_staff_authed_user_client()

self.non_staff_client, self.nonstaff = self.create_non_staff_authed_user_client()
# "nonstaff" means "non Django staff" here. We assign this user to course staff
# role to check that even so they won't have advanced settings access when explicitly
# restricted.
CourseStaffRole(self.course.id).add_users(self.nonstaff)

@override_settings(FEATURES={'DISABLE_MOBILE_COURSE_AVAILABLE': True})
def test_mobile_field_available(self):
Expand Down Expand Up @@ -145,16 +150,50 @@ def test_discussion_fields_available(self, is_pages_and_resources_enabled,
self.assertEqual('discussion_blackouts' in response, fields_visible)
self.assertEqual('discussion_topics' in response, fields_visible)

@override_settings(FEATURES={'DISABLE_ADVANCED_SETTINGS': True})
def test_disable_advanced_settings_feature(self):
"""
If this feature is enabled, only staff should be able to access the advanced settings page.
"""
response = self.non_staff_client.get_html(self.course_setting_url)
self.assertEqual(response.status_code, 403)
@ddt.data(False, True)
def test_disable_advanced_settings_feature(self, disable_advanced_settings):
"""
If this feature is enabled, only Django Staff/Superuser should be able to access the "Advanced Settings" page.
For non-staff users the "Advanced Settings" tab link should not be visible.
"""
advanced_settings_link_html = f"<a href=\"{self.course_setting_url}\">Advanced Settings</a>".encode('utf-8')

with override_settings(FEATURES={'DISABLE_ADVANCED_SETTINGS': disable_advanced_settings}):
for handler in (
'import_handler',
'export_handler',
'course_team_handler',
'course_info_handler',
'assets_handler',
'tabs_handler',
'settings_handler',
'grading_handler',
'textbooks_list_handler',
):
# Test that non-staff users don't see the "Advanced Settings" tab link.
response = self.non_staff_client.get_html(
get_url(self.course.id, handler)
)
self.assertEqual(response.status_code, 200)
if disable_advanced_settings:
self.assertNotIn(advanced_settings_link_html, response.content)
else:
self.assertIn(advanced_settings_link_html, response.content)

# Test that staff users see the "Advanced Settings" tab link.
response = self.client.get_html(
get_url(self.course.id, handler)
)
self.assertEqual(response.status_code, 200)
self.assertIn(advanced_settings_link_html, response.content)

response = self.client.get_html(self.course_setting_url)
self.assertEqual(response.status_code, 200)
# Test that non-staff users can't access the "Advanced Settings" page.
response = self.non_staff_client.get_html(self.course_setting_url)
self.assertEqual(response.status_code, 403 if disable_advanced_settings else 200)

# Test that staff users can access the "Advanced Settings" page.
response = self.client.get_html(self.course_setting_url)
self.assertEqual(response.status_code, 200)


@ddt.ddt
Expand Down
4 changes: 2 additions & 2 deletions cms/djangoapps/contentstore/views/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,8 @@ def create_support_legend_dict():
# by the components in the order listed in COMPONENT_TYPES.
component_types = COMPONENT_TYPES[:]

# Libraries do not support discussions and openassessment and other libraries
component_not_supported_by_library = ['discussion', 'library', 'openassessment']
# Libraries do not support discussions, drag-and-drop, and openassessment and other libraries
component_not_supported_by_library = ['discussion', 'library', 'openassessment', 'drag-and-drop-v2']
if library:
component_types = [component for component in component_types
if component not in set(component_not_supported_by_library)]
Expand Down
21 changes: 7 additions & 14 deletions cms/djangoapps/contentstore/views/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@
from common.djangoapps.course_action_state.models import CourseRerunState, CourseRerunUIStateManager
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.edxmako.shortcuts import render_to_response
from common.djangoapps.student.auth import has_course_author_access, has_studio_read_access, has_studio_write_access
from common.djangoapps.student.auth import (
has_course_author_access,
has_studio_read_access,
has_studio_write_access,
has_studio_advanced_settings_access
)
from common.djangoapps.student.roles import (
CourseInstructorRole,
CourseStaffRole,
Expand Down Expand Up @@ -147,17 +152,6 @@ class AccessListFallback(Exception):
pass # lint-amnesty, pylint: disable=unnecessary-pass


def has_advanced_settings_access(user):
"""
If DISABLE_ADVANCED_SETTINGS feature is enabled, only global staff can access "Advanced Settings".
"""
return (
not settings.FEATURES.get('DISABLE_ADVANCED_SETTINGS', False)
or user.is_staff
or user.is_superuser
)


def get_course_and_check_access(course_key, user, depth=0):
"""
Function used to calculate and return the locator and course block
Expand Down Expand Up @@ -763,7 +757,6 @@ def course_index(request, course_key):
'frontend_app_publisher_url': frontend_app_publisher_url,
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_block.id),
'advance_settings_url': reverse_course_url('advanced_settings_handler', course_block.id),
'advance_settings_access': has_advanced_settings_access(request.user),
'proctoring_errors': proctoring_errors,
})

Expand Down Expand Up @@ -1432,7 +1425,7 @@ def advanced_settings_handler(request, course_key_string):
json: update the Course's settings. The payload is a json rep of the
metadata dicts.
"""
if not has_advanced_settings_access(request.user):
if not has_studio_advanced_settings_access(request.user):
raise PermissionDenied()

course_key = CourseKey.from_string(course_key_string)
Expand Down
3 changes: 3 additions & 0 deletions cms/templates/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<%namespace name='static' file='static_content.html'/>
<%!
from django.utils.translation import gettext as _
from common.djangoapps.student.auth import has_studio_advanced_settings_access
from cms.djangoapps.contentstore import utils
from lms.djangoapps.certificates.api import can_show_certificate_available_date_field
from openedx.core.djangolib.js_utils import (
Expand Down Expand Up @@ -721,7 +722,9 @@ <h3 class="title-3">${_("Other Course Settings")}</h3>
<li class="nav-item"><a href="${grading_config_url}">${_("Grading")}</a></li>
<li class="nav-item"><a href="${course_team_url}">${_("Course Team")}</a></li>
<li class="nav-item"><a href="${utils.reverse_course_url('group_configurations_list_handler', context_course.id)}">${_("Group Configurations")}</a></li>
% if has_studio_advanced_settings_access(request.user):
<li class="nav-item"><a href="${advanced_config_url}">${_("Advanced Settings")}</a></li>
% endif
% if mfe_proctored_exam_settings_url:
<li class="nav-item"><a href="${mfe_proctored_exam_settings_url}">${_("Proctored Exam Settings")}</a></li>
% endif
Expand Down
3 changes: 3 additions & 0 deletions cms/templates/settings_graders.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import json
from cms.djangoapps.contentstore import utils
from django.utils.translation import gettext as _
from common.djangoapps.student.auth import has_studio_advanced_settings_access
from cms.djangoapps.models.settings.encoder import CourseSettingsEncoder
from openedx.core.djangolib.js_utils import (
dump_js_escaped_json, js_escaped_string
Expand Down Expand Up @@ -165,7 +166,9 @@ <h3 class="title-3">${_("Other Course Settings")}</h3>
<li class="nav-item"><a href="${detailed_settings_url}">${_("Details & Schedule")}</a></li>
<li class="nav-item"><a href="${course_team_url}">${_("Course Team")}</a></li>
<li class="nav-item"><a href="${utils.reverse_course_url('group_configurations_list_handler', context_course.id)}">${_("Group Configurations")}</a></li>
% if has_studio_advanced_settings_access(request.user):
<li class="nav-item"><a href="${advanced_settings_url}">${_("Advanced Settings")}</a></li>
% endif
% if mfe_proctored_exam_settings_url:
<li class="nav-item"><a href="${mfe_proctored_exam_settings_url}">${_("Proctored Exam Settings")}</a></li>
% endif
Expand Down
3 changes: 2 additions & 1 deletion cms/templates/widgets/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.urls import reverse
from django.utils.translation import gettext as _
from urllib.parse import quote_plus
from common.djangoapps.student.auth import has_studio_advanced_settings_access
from cms.djangoapps.contentstore import toggles
from cms.djangoapps.contentstore.utils import get_pages_and_resources_url
from openedx.core.djangoapps.discussions.config.waffle import ENABLE_PAGES_AND_RESOURCES_MICROFRONTEND
Expand Down Expand Up @@ -120,7 +121,7 @@ <h3 class="title"><span class="label"><span class="label-prefix sr">${_("Course"
<a href="${mfe_proctored_exam_settings_url}">${_("Proctored Exam Settings")}</a>
</li>
% endif
% if advance_settings_access:
% if has_studio_advanced_settings_access(request.user):
<li class="nav-item nav-course-settings-advanced">
<a href="${advanced_settings_url}">${_("Advanced Settings")}</a>
</li>
Expand Down
16 changes: 15 additions & 1 deletion common/djangoapps/student/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,23 @@ def has_course_author_access(user, course_key):
return has_studio_write_access(user, course_key)


def has_studio_advanced_settings_access(user):
"""
If DISABLE_ADVANCED_SETTINGS feature is enabled, only Django Superuser
or Django Staff can access "Advanced Settings".
By default, this feature is disabled.
"""
return (
not settings.FEATURES.get('DISABLE_ADVANCED_SETTINGS', False)
or user.is_staff
or user.is_superuser
)


def has_studio_read_access(user, course_key):
"""
Return True iff user is allowed to view this course/library in studio.
Return True if user is allowed to view this course/library in studio.
Will also return True if user has write access in studio (has_course_author_access)
There is currently no such thing as read-only course access in studio, but
Expand Down
Loading

0 comments on commit e48a132

Please sign in to comment.