Skip to content

Release 0.33.1 #2269

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

Merged
merged 11 commits into from
May 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions RELEASE.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
Release Notes
=============

Version 0.33.1
--------------

- fix(deps): update dependency django-anymail to v13 (#2201)
- Prevent test courses from being overwritten (#2262)
- fix(deps): update dependency django-guardian to v3 (#2266)
- fix(deps): update dependency ulid-py to v1 (#2268)
- chore(deps): update dependency jest-extended to v5 (#2264)
- fix(deps): update dependency cryptography to v45 (#2265)
- fix(deps): update dependency moment-timezone to ^0.6.0 (#2263)
- fix(deps): update dependency tika to v3 (#2202)
- Tweaks to the nextjs dockerfile to give a build target for production. (#2260)

Version 0.33.0 (Released May 28, 2025)
--------------

Expand Down
22 changes: 21 additions & 1 deletion frontends/main/Dockerfile.web
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
# heroku container:release --app mitopen-rc-nextjs frontend


FROM node:22-alpine
FROM node:22-alpine AS base

RUN apk update
RUN apk add --no-cache libc6-compat && \
Expand Down Expand Up @@ -152,6 +152,26 @@ ENV NEXT_PUBLIC_DEFAULT_SEARCH_STALENESS_PENALTY="2.5"
ENV NEXT_PUBLIC_DEFAULT_SEARCH_MINIMUM_SCORE_CUTOFF="0"
ENV NEXT_PUBLIC_DEFAULT_SEARCH_MAX_INCOMPLETENESS_PENALTY="90"

# NEW STAGE: build_skip_yarn
# This stage is intended for scenarios where the 'yarn build' step
# is not needed (e.g., build artifacts are provided externally or
# for a development setup where 'yarn dev' might be used).
# Note: 'yarn start' in the CMD requires a prior build to have occurred
# and the '.next' directory to be present.
FROM base AS build_skip_yarn

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

CMD ["yarn", "start"]

# DEFAULT STAGE: build
# This stage performs the 'yarn build' step and is the default target
# if no --target is specified during the Docker build command.
FROM base AS build

RUN yarn build

EXPOSE 3000
Expand Down
2 changes: 1 addition & 1 deletion frontends/main/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"eslint-config-next": "^14.2.7",
"http-proxy-middleware": "^3.0.0",
"jest": "^29.7.0",
"jest-extended": "^4.0.2",
"jest-extended": "^5.0.0",
"jest-next-dynamic-ts": "^0.1.1",
"ol-test-utilities": "0.0.0",
"ts-jest": "^29.2.4",
Expand Down
2 changes: 1 addition & 1 deletion frontends/ol-test-utilities/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"css-mediaquery": "^0.1.2",
"dom-accessibility-api": "^0.7.0",
"lodash": "^4.17.21",
"moment-timezone": "^0.5.47",
"moment-timezone": "^0.6.0",
"next-router-mock": "^0.9.13",
"tiny-invariant": "^1.3.1"
},
Expand Down
2 changes: 1 addition & 1 deletion frontends/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"eslint-plugin-testing-library": "^7.0.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.5.0",
"jest-extended": "^4.0.2",
"jest-extended": "^5.0.0",
"jest-fail-on-console": "^3.3.1",
"jest-watch-typeahead": "^2.2.2",
"jest-when": "^3.6.0",
Expand Down
23 changes: 18 additions & 5 deletions learning_resources/etl/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from django.contrib.auth import get_user_model
from django.db import transaction
from django.db.models import Q

from learning_resources.constants import (
LearningResourceDelivery,
Expand Down Expand Up @@ -70,7 +71,11 @@ def update_index(learning_resource, newly_created):
learning resource (LearningResource): a learning resource
newly_created (bool): whether the learning resource has just been created
"""
if not newly_created and not learning_resource.published:
if (
not newly_created
and not learning_resource.published
and not learning_resource.test_mode
):
resource_unpublished_actions(learning_resource)
elif learning_resource.published:
resource_upserted_actions(learning_resource, percolate=False)
Expand Down Expand Up @@ -293,6 +298,7 @@ def load_run(
LearningResourceRun: the created/updated resource run
"""
run_id = run_data.pop("run_id")

image_data = run_data.pop("image", None)
status = run_data.pop("status", None)
instructors_data = run_data.pop("instructors", [])
Expand All @@ -305,6 +311,9 @@ def load_run(
run_data["prices"] = []
resource_prices = []

if learning_resource.test_mode:
run_data["published"] = True

with transaction.atomic():
(
learning_resource_run,
Expand All @@ -314,7 +323,6 @@ def load_run(
run_id=run_id,
defaults={**run_data},
)

load_instructors(learning_resource_run, instructors_data)
load_prices(learning_resource_run, resource_prices)
load_image(learning_resource_run, image_data)
Expand Down Expand Up @@ -498,7 +506,8 @@ def load_course(
# The course ETL should be the ultimate source of truth for
# courses and their runs.
for run in learning_resource.runs.exclude(
run_id__in=run_ids_to_update_or_create
Q(run_id__in=run_ids_to_update_or_create)
| Q(learning_resource__test_mode=True)
).filter(published=True):
run.published = False
run.save()
Expand Down Expand Up @@ -548,7 +557,10 @@ def load_courses(
if courses and config.prune:
for learning_resource in LearningResource.objects.filter(
etl_source=etl_source, resource_type=LearningResourceType.course.name
).exclude(id__in=[learning_resource.id for learning_resource in courses]):
).exclude(
Q(id__in=[learning_resource.id for learning_resource in courses])
| Q(test_mode=True)
):
learning_resource.published = False
learning_resource.save()
resource_unpublished_actions(learning_resource)
Expand Down Expand Up @@ -613,7 +625,8 @@ def load_program(
if config.prune:
# mark runs no longer included here as unpublished
for run in learning_resource.runs.exclude(
run_id__in=run_ids_to_update_or_create
Q(run_id__in=run_ids_to_update_or_create)
| Q(learning_resource__test_mode=True)
).filter(published=True):
run.published = False
run.save()
Expand Down
60 changes: 60 additions & 0 deletions learning_resources/etl/loaders_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
PlatformType,
RunStatus,
)
from learning_resources.etl import loaders
from learning_resources.etl.constants import (
CourseLoaderConfig,
ETLSource,
Expand Down Expand Up @@ -143,6 +144,28 @@ def mock_upsert_tasks(mocker):
)


@pytest.mark.parametrize("published", [False, True])
@pytest.mark.parametrize("test_mode", [False, True])
@pytest.mark.parametrize("newly_created", [False, True])
def test_update_index_test_mode_behavior(
mocker,
published,
test_mode,
newly_created,
):
"""Test update_index does not remove test_mode content files from index"""
resource_unpublished_actions = mocker.patch(
"learning_resources.etl.loaders.resource_unpublished_actions"
)
lr = LearningResourceFactory.create(published=published, test_mode=test_mode)

loaders.update_index(lr, newly_created)
if test_mode:
resource_unpublished_actions.assert_not_called()
elif not published and not newly_created:
resource_unpublished_actions.assert_called_once()


@pytest.fixture
def learning_resource_offeror():
"""Return a LearningResourceOfferer"""
Expand Down Expand Up @@ -276,6 +299,43 @@ def test_load_program( # noqa: PLR0913
mock_upsert_tasks.upsert_learning_resource_immutable_signature.assert_not_called()


@pytest.mark.django_db
def test_load_run_sets_test_resource_run_to_published(mocker):
"""
Test that load_run sets the test_mode run to published
"""

mock_qs = mocker.patch.object(
loaders.LearningResourceRun.objects, "filter", autospec=True
)
mock_qs.return_value.exists.return_value = True

test_mode_learning_resource = LearningResourceFactory.create(test_mode=True)

test_mode_run_id = "test_run_id"
test_mode_run_data = {"run_id": test_mode_run_id, "published": False}

LearningResourceRunFactory.create(
learning_resource=test_mode_learning_resource,
run_id=test_mode_run_id,
published=False,
)

result = loaders.load_run(test_mode_learning_resource, test_mode_run_data)
assert result.published
regular_learning_resource = LearningResourceFactory.create(test_mode=False)
regular_run_id = "test_run_id"
regular_run_data = {"run_id": regular_run_id, "published": False}
LearningResourceRunFactory.create(
learning_resource=regular_learning_resource,
run_id=regular_run_id,
published=False,
)

result = loaders.load_run(regular_learning_resource, regular_run_data)
assert not result.published


def test_load_program_bad_platform(mocker):
"""A bad platform should log an exception and not create the program"""
mock_log = mocker.patch("learning_resources.etl.loaders.log.exception")
Expand Down
5 changes: 4 additions & 1 deletion learning_resources/management/commands/mixins.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from learning_resources.models import LearningResource
from learning_resources.models import LearningResource, LearningResourceRun


class TestResourceConfigurationMixin:
Expand All @@ -13,6 +13,9 @@ def configure_test_resources(self, options):
)
if options.get("test_ids"):
test_ids = options["test_ids"].split(",")
LearningResourceRun.objects.filter(
learning_resource__id__in=test_ids
).update(published=True)
LearningResource.objects.filter(id__in=test_ids).update(
test_mode=True, published=False
)
Expand Down
2 changes: 1 addition & 1 deletion main/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from main.settings_pluggy import * # noqa: F403
from openapi.settings_spectacular import open_spectacular_settings

VERSION = "0.33.0"
VERSION = "0.33.1"

log = logging.getLogger()

Expand Down
Loading
Loading