Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feanil/fix docs build #36004

Closed
wants to merge 40 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
defee16
fix: do not open mfe editors automatically on block paste (#35729)
navinkarkera Oct 30, 2024
2f49b81
chore: upgrade edx-search to 4.1.1 (#35756)
regisb Nov 1, 2024
13769e1
fix: adds content.search to docs apps
sarina Nov 5, 2024
5a42d35
build: kickoff the Sumac release
cmltaWt0 Nov 5, 2024
e445d8a
Merge pull request #35781 from raccoongang/max/release_line_update_sumac
cmltaWt0 Nov 6, 2024
46c3616
Merge branch 'open-release/sumac.master' into sarina/update-docs-config
cmltaWt0 Nov 6, 2024
7ecd6a5
Merge pull request #35778 from openedx/sarina/update-docs-config
cmltaWt0 Nov 6, 2024
8616aa5
fix: bump MAX_BLOCKS_PER_CONTENT_LIBRARY default to 100,000 (#35768)
pomegranited Nov 5, 2024
1cc1485
fix: remove the "Legacy Library" button if libraries v1 are disabled …
pomegranited Nov 7, 2024
db0b890
fix: allow non-Elasticsearch search engines when reindexing courses […
pomegranited Nov 6, 2024
326f2d2
fix: set upstream link for re-copied block from course originally fro…
navinkarkera Nov 7, 2024
2e95777
fix: image aspect ratio on component preview (#35791)
rpenido Nov 8, 2024
f7e275a
test: re-enable content libraries runtime tests [FC-0062] (#35783) (#…
pomegranited Nov 8, 2024
79886a6
fix: component asset api views (#35765) (#35800)
navinkarkera Nov 8, 2024
5b7deaf
fix: hide library_v2 and itembank in legacy library page (#35772) (#3…
navinkarkera Nov 13, 2024
8ddc582
Merge pull request #34859 from raccoongang/kireiev/AXM-549/feat/upstr…
KyryloKireiev Nov 1, 2024
e9e1308
Merge pull request #35835 from raccoongang/max/backport-mobile-api
cmltaWt0 Nov 14, 2024
2c57520
[sumac] fix: keep library collection card component count in sync (#3…
ChrisChV Nov 21, 2024
2aea0ea
fix: bypass access checks when populating course blocks cache
asadali145 Oct 16, 2024
0dbf7e0
test: add tests
asadali145 Oct 23, 2024
0490dab
style: pylint
asadali145 Oct 23, 2024
397555d
test: add tests for known and unknown user
asadali145 Oct 31, 2024
e4f22c3
refactor: revert imports
asadali145 Oct 31, 2024
3dcfd55
refactor: revert imports
asadali145 Oct 31, 2024
c1a2726
style: pycodestyle fix
asadali145 Oct 31, 2024
5800a67
refactor: update docs
asadali145 Nov 1, 2024
8f01f78
test: add tests when user is not in any group
asadali145 Nov 1, 2024
5d91e92
Merge pull request #35919 from mitodl/asad/backport-35655
pdpinch Nov 25, 2024
38f7344
chore: Bump openedx-learning to version 0.18.1 (#35931)
marslanabdulrauf Dec 3, 2024
e3d7f66
fix: docs build issues (#35978)
irtazaakram Dec 6, 2024
145d59e
fix: content libraries permissions
rpenido Dec 5, 2024
e587a7d
feat: Integrate Forum V2 into edx-platform
Nov 19, 2024
ada6b76
fix: flag API positional arguments
Dec 5, 2024
583fd1a
feat: upgrade openedx-forum to v0.1.4
Dec 5, 2024
9b96b6f
refactor: Update get block OLX view to support versions (backport) (#…
ChrisChV Dec 6, 2024
280bcf6
feat: incremental reindex_studio management command (backport) (#35981)
DanielVZ96 Dec 6, 2024
139580a
chore: upgrade Django to v4.2.17
magajh Dec 6, 2024
2cb9aef
fix: return empty list when no courses are found for request (#35942)
mariajgrimaldi Dec 5, 2024
dafcac7
fix: render library assets named xblock-
DanielVZ96 Dec 9, 2024
1abe11f
fix: Build docs with python 3.11
feanil Dec 10, 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
15 changes: 0 additions & 15 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
<!--

Note: Please refer to the Support Development Guidelines on the wiki page to consider backporting to active releases:
https://openedx.atlassian.net/wiki/spaces/COMM/pages/4248436737/Support+Guidelines+for+active+releases

Please give your pull request a short but descriptive title.
Use conventional commits to separate and summarize commits logically:
https://open-edx-proposals.readthedocs.io/en/latest/oep-0051-bp-conventional-commits.html

Use this template as a guide. Omit sections that don't apply.
You may link to information rather than copy it, but only if the link is publicly readable.
If the linked information must be private (because it contains secrets), clearly label the link as private.

-->

## Description

Describe what this pull request changes, and why. Include implications for people using this change.
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: 2
build:
os: "ubuntu-22.04"
tools:
python: "3.12"
python: "3.11"

sphinx:
configuration: docs/conf.py
Expand Down
3 changes: 2 additions & 1 deletion cms/djangoapps/contentstore/courseware_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ def prepare_item_index(item, skip_index=False, groups_usage_info=None):
# Now index the content
for item in structure.get_children():
prepare_item_index(item, groups_usage_info=groups_usage_info)
searcher.index(items_index, request_timeout=timeout)
if items_index:
searcher.index(items_index, request_timeout=timeout)
cls.remove_deleted_items(searcher, structure_key, indexed_items)
except Exception as err: # pylint: disable=broad-except
# broad exception so that index operation does not prevent the rest of the application from working
Expand Down
77 changes: 53 additions & 24 deletions cms/djangoapps/contentstore/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from xmodule.xml_block import XmlMixin

from cms.djangoapps.models.settings.course_grading import CourseGradingModel
from cms.lib.xblock.upstream_sync import UpstreamLink, BadUpstream, BadDownstream, fetch_customizable_fields
from cms.lib.xblock.upstream_sync import UpstreamLink, UpstreamLinkException, fetch_customizable_fields
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
import openedx.core.djangoapps.content_staging.api as content_staging_api
import openedx.core.djangoapps.content_tagging.api as content_tagging_api
Expand Down Expand Up @@ -323,6 +323,56 @@ def import_staged_content_from_user_clipboard(parent_key: UsageKey, request) ->
return new_xblock, notices


def _fetch_and_set_upstream_link(
copied_from_block: str,
copied_from_version_num: int,
temp_xblock: XBlock,
user: User
):
"""
Fetch and set upstream link for the given xblock. This function handles following cases:
* the xblock is copied from a v2 library; the library block is set as upstream.
* the xblock is copied from a course; no upstream is set, only copied_from_block is set.
* the xblock is copied from a course where the source block was imported from a library; the original libary block
is set as upstream.
"""
# Try to link the pasted block (downstream) to the copied block (upstream).
temp_xblock.upstream = copied_from_block
try:
UpstreamLink.get_for_block(temp_xblock)
except UpstreamLinkException:
# Usually this will fail. For example, if the copied block is a modulestore course block, it can't be an
# upstream. That's fine! Instead, we store a reference to where this block was copied from, in the
# 'copied_from_block' field (from AuthoringMixin).

# In case if the source block was imported from a library, we need to check its upstream
# and set the same upstream link for the new block.
source_descriptor = modulestore().get_item(UsageKey.from_string(copied_from_block))
if source_descriptor.upstream:
_fetch_and_set_upstream_link(
source_descriptor.upstream,
source_descriptor.upstream_version,
temp_xblock,
user,
)
else:
# else we store a reference to where this block was copied from, in the 'copied_from_block'
# field (from AuthoringMixin).
temp_xblock.upstream = None
temp_xblock.copied_from_block = copied_from_block
else:
# But if it doesn't fail, then populate the `upstream_version` field based on what was copied. Note that
# this could be the latest published version, or it could be an an even newer draft version.
temp_xblock.upstream_version = copied_from_version_num
# Also, fetch upstream values (`upstream_display_name`, etc.).
# Recall that the copied block could be a draft. So, rather than fetching from the published upstream (which
# could be older), fetch from the copied block itself. That way, if an author customizes a field, but then
# later wants to restore it, it will restore to the value that the field had when the block was pasted. Of
# course, if the author later syncs updates from a *future* published upstream version, then that will fetch
# new values from the published upstream content.
fetch_customizable_fields(upstream=temp_xblock, downstream=temp_xblock, user=user)


def _import_xml_node_to_parent(
node,
parent_xblock: XBlock,
Expand Down Expand Up @@ -404,28 +454,7 @@ def _import_xml_node_to_parent(
raise NotImplementedError("We don't yet support pasting XBlocks with children")
temp_xblock.parent = parent_key
if copied_from_block:
# Try to link the pasted block (downstream) to the copied block (upstream).
temp_xblock.upstream = copied_from_block
try:
UpstreamLink.get_for_block(temp_xblock)
except (BadDownstream, BadUpstream):
# Usually this will fail. For example, if the copied block is a modulestore course block, it can't be an
# upstream. That's fine! Instead, we store a reference to where this block was copied from, in the
# 'copied_from_block' field (from AuthoringMixin).
temp_xblock.upstream = None
temp_xblock.copied_from_block = copied_from_block
else:
# But if it doesn't fail, then populate the `upstream_version` field based on what was copied. Note that
# this could be the latest published version, or it could be an an even newer draft version.
temp_xblock.upstream_version = copied_from_version_num
# Also, fetch upstream values (`upstream_display_name`, etc.).
# Recall that the copied block could be a draft. So, rather than fetching from the published upstream (which
# could be older), fetch from the copied block itself. That way, if an author customizes a field, but then
# later wants to restore it, it will restore to the value that the field had when the block was pasted. Of
# course, if the author later syncs updates from a *future* published upstream version, then that will fetch
# new values from the published upstream content.
fetch_customizable_fields(upstream=temp_xblock, downstream=temp_xblock, user=user)

_fetch_and_set_upstream_link(copied_from_block, copied_from_version_num, temp_xblock, user)
# Save the XBlock into modulestore. We need to save the block and its parent for this to work:
new_xblock = store.update_item(temp_xblock, user.id, allow_not_found=True)
parent_xblock.children.append(new_xblock.location)
Expand All @@ -436,7 +465,7 @@ def _import_xml_node_to_parent(
# Allow an XBlock to do anything fancy it may need to when pasted from the clipboard.
# These blocks may handle their own children or parenting if needed. Let them return booleans to
# let us know if we need to handle these or not.
children_handed = new_xblock.studio_post_paste(store, node)
children_handled = new_xblock.studio_post_paste(store, node)

if not children_handled:
for child_node in child_nodes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,16 @@ def handle(self, *args, **options): # pylint: disable=too-many-statements
logging.exception('Search Engine error - %s', exc)
return

index_exists = searcher._es.indices.exists(index=index_name) # pylint: disable=protected-access
# Legacy Elasticsearch engine
if hasattr(searcher, '_es'): # pylint: disable=protected-access
index_exists = searcher._es.indices.exists(index=index_name) # pylint: disable=protected-access

index_mapping = searcher._es.indices.get_mapping( # pylint: disable=protected-access
index=index_name,
) if index_exists else {}
index_mapping = searcher._es.indices.get_mapping( # pylint: disable=protected-access
index=index_name,
) if index_exists else {}

if index_exists and index_mapping:
return
if index_exists and index_mapping:
return

# if reindexing is done during devstack setup step, don't prompt the user
if setup_option or query_yes_no(self.CONFIRMATION_PROMPT, default="no"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class StudioHomeSerializer(serializers.Serializer):
request_course_creator_url = serializers.CharField()
rerun_creator_status = serializers.BooleanField()
show_new_library_button = serializers.BooleanField()
show_new_library_v2_button = serializers.BooleanField()
split_studio_home = serializers.BooleanField()
studio_name = serializers.CharField()
studio_short_name = serializers.CharField()
Expand Down
1 change: 1 addition & 0 deletions cms/djangoapps/contentstore/rest_api/v1/views/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def get(self, request: Request):
"request_course_creator_url": "/request_course_creator",
"rerun_creator_status": true,
"show_new_library_button": true,
"show_new_library_v2_button": true,
"split_studio_home": false,
"studio_name": "Studio",
"studio_short_name": "Studio",
Expand Down
87 changes: 84 additions & 3 deletions cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
Unit tests for home page view.
"""
import ddt
import pytz
from collections import OrderedDict
from datetime import datetime, timedelta
from django.conf import settings
from django.test import override_settings
from django.urls import reverse
Expand Down Expand Up @@ -54,6 +56,7 @@ def setUp(self):
"request_course_creator_url": "/request_course_creator",
"rerun_creator_status": True,
"show_new_library_button": True,
"show_new_library_v2_button": True,
"split_studio_home": False,
"studio_name": settings.STUDIO_NAME,
"studio_short_name": settings.STUDIO_SHORT_NAME,
Expand Down Expand Up @@ -100,12 +103,13 @@ class HomePageCoursesViewTest(CourseTestCase):
def setUp(self):
super().setUp()
self.url = reverse("cms.djangoapps.contentstore:v1:courses")
CourseOverviewFactory.create(
self.course_overview = CourseOverviewFactory.create(
id=self.course.id,
org=self.course.org,
display_name=self.course.display_name,
display_number_with_default=self.course.number,
)
self.non_staff_client, _ = self.create_non_staff_authed_user_client()

def test_home_page_response(self):
"""Check successful response content"""
Expand All @@ -131,6 +135,7 @@ def test_home_page_response(self):
print(response.data)
self.assertDictEqual(expected_response, response.data)

@override_settings(FEATURES=FEATURES_WITH_HOME_PAGE_COURSE_V2_API)
def test_home_page_response_with_api_v2(self):
"""Check successful response content with api v2 modifications.

Expand All @@ -155,12 +160,88 @@ def test_home_page_response_with_api_v2(self):
"in_process_course_actions": [],
}

with override_settings(FEATURES=FEATURES_WITH_HOME_PAGE_COURSE_V2_API):
response = self.client.get(self.url)
response = self.client.get(self.url)

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertDictEqual(expected_response, response.data)

@override_settings(FEATURES=FEATURES_WITH_HOME_PAGE_COURSE_V2_API)
@ddt.data(
("active_only", "true", 2, 0),
("archived_only", "true", 0, 1),
("search", "sample", 1, 0),
("search", "demo", 0, 1),
("order", "org", 2, 1),
("order", "display_name", 2, 1),
("order", "number", 2, 1),
("order", "run", 2, 1)
)
@ddt.unpack
def test_filter_and_ordering_courses(
self,
filter_key,
filter_value,
expected_active_length,
expected_archived_length
):
"""Test home page with org filter and ordering for a staff user.

The test creates an active/archived course, and then filters/orders them using the query parameters.
"""
archived_course_key = self.store.make_course_key("demo-org", "demo-number", "demo-run")
CourseOverviewFactory.create(
display_name="Course (Demo)",
id=archived_course_key,
org=archived_course_key.org,
end=(datetime.now() - timedelta(days=365)).replace(tzinfo=pytz.UTC),
)
active_course_key = self.store.make_course_key("sample-org", "sample-number", "sample-run")
CourseOverviewFactory.create(
display_name="Course (Sample)",
id=active_course_key,
org=active_course_key.org,
)

response = self.client.get(self.url, {filter_key: filter_value})

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data["archived_courses"]), expected_archived_length)
self.assertEqual(len(response.data["courses"]), expected_active_length)

@override_settings(FEATURES=FEATURES_WITH_HOME_PAGE_COURSE_V2_API)
@ddt.data(
("active_only", "true"),
("archived_only", "true"),
("search", "sample"),
("order", "org"),
)
@ddt.unpack
def test_filter_and_ordering_no_courses_staff(self, filter_key, filter_value):
"""Test home page with org filter and ordering when there are no courses for a staff user."""
self.course_overview.delete()

response = self.client.get(self.url, {filter_key: filter_value})

self.assertEqual(len(response.data["courses"]), 0)
self.assertEqual(response.status_code, status.HTTP_200_OK)

@override_settings(FEATURES=FEATURES_WITH_HOME_PAGE_COURSE_V2_API)
@ddt.data(
("active_only", "true"),
("archived_only", "true"),
("search", "sample"),
("order", "org"),
)
@ddt.unpack
def test_home_page_response_no_courses_non_staff(self, filter_key, filter_value):
"""Test home page with org filter and ordering when there are no courses for a non-staff user."""
self.course_overview.delete()

response = self.non_staff_client.get(self.url)

self.assertEqual(len(response.data["courses"]), 0)
self.assertEqual(response.status_code, status.HTTP_200_OK)

@override_waffle_switch(ENABLE_GLOBAL_STAFF_OPTIMIZATION, True)
def test_org_query_if_passed(self):
"""Test home page when org filter passed as a query param"""
Expand Down
Loading
Loading