Skip to content

Commit

Permalink
fix: don't show language without any catalog visible course (#3405)
Browse files Browse the repository at this point in the history
* fix: don't show languages without any catalog visible course
  • Loading branch information
arslanashraf7 authored Feb 26, 2025
1 parent 9033a18 commit 9d9c4fb
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 13 deletions.
13 changes: 4 additions & 9 deletions cms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@
Program,
ProgramCertificate,
ProgramRun,
CourseLanguage,
)
from courses.utils import get_catalog_languages
from ecommerce.models import Product
from mitol.olposthog.features import is_enabled
from mitxpro.features import CATALOG_LANGUAGE_FILTER
Expand Down Expand Up @@ -547,6 +547,7 @@ def get_context(self, request, *args, **kwargs): # noqa: ARG002
)
external_program_qset = (
ExternalProgramPage.objects.live()
.filter(program__live=True)
.select_related("program", "language")
.order_by("title")
)
Expand All @@ -559,6 +560,7 @@ def get_context(self, request, *args, **kwargs): # noqa: ARG002
)
external_course_qset = (
ExternalCoursePage.objects.live()
.filter(course__live=True)
.select_related("course", "language")
.order_by("title")
)
Expand All @@ -572,7 +574,6 @@ def get_context(self, request, *args, **kwargs): # noqa: ARG002
external_course_qset = external_course_qset.filter(
language__name=language_filter
)

if topic_filter != ALL_TOPICS:
program_page_qset = program_page_qset.related_pages(topic_filter)
external_program_qset = external_program_qset.related_pages(topic_filter)
Expand Down Expand Up @@ -665,13 +666,7 @@ def get_context(self, request, *args, **kwargs): # noqa: ARG002
],
show_language_filter=is_language_filter_enabled,
selected_language=language_filter,
language_options=[
ALL_LANGUAGES,
*[
course_language.name
for course_language in CourseLanguage.objects.filter(is_active=True)
],
]
language_options=[ALL_LANGUAGES, *get_catalog_languages()]
if is_language_filter_enabled
else [],
)
Expand Down
20 changes: 17 additions & 3 deletions cms/models_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
)
from courses.models import CourseLanguage
from ecommerce.factories import ProductFactory, ProductVersionFactory
from mitxpro.utils import now_in_utc

pytestmark = [pytest.mark.django_db]

Expand Down Expand Up @@ -266,10 +267,16 @@ def test_catalog_page_language_context(
mocker.patch("cms.models.is_enabled", return_value=True)
CourseLanguage.objects.all().delete()
catalog_page = CatalogPageFactory.create()
now = now_in_utc()

if languages:
CourseLanguageFactory.create_batch(
len(languages), name=factory.Iterator(languages)
)
for language in languages:
created_language = CourseLanguageFactory.create(name=language)
CourseRunFactory.create(
start_date=now + timedelta(days=1),
course__page__language=created_language,
course__program__page__language=created_language,
)

rf = RequestFactory()
request = rf.get(f"/?language={selected_language}")
Expand Down Expand Up @@ -299,6 +306,13 @@ def test_catalog_page_language_feature_flag(mocker, staff_user, is_enabled):
CourseLanguage.objects.all().delete()
catalog_page = CatalogPageFactory.create()
languages = CourseLanguageFactory.create_batch(2)
now = now_in_utc()
CourseRunFactory.create_batch(
2,
start_date=now + timedelta(days=1),
course__page__language=factory.Iterator(languages),
course__program__page__language=factory.Iterator(languages),
)

rf = RequestFactory()
request = rf.get("/")
Expand Down
12 changes: 12 additions & 0 deletions cms/templates/catalog_page.html
Original file line number Diff line number Diff line change
Expand Up @@ -261,13 +261,17 @@ <h1>{{ site_name }}—Professional Development, the MIT Way</h1>
aria-labelledby="all-tab"
>
{% endif %}
{% if not all_pages%}
{% include "partials/catalog_empty.html" %}
{% else %}
{% for page in all_pages %}
{% if page.program or page.is_external_program_page %}
{% include "partials/catalog_card.html" with courseware_page=page object_type="program" tab="all" %}
{% elif page.course or page.is_external_course_page %}
{% include "partials/catalog_card.html" with courseware_page=page object_type="course" tab="all"%}
{% endif %}
{% endfor %}
{% endif %}
</div>

{% if active_tab == "programs-tab" %}
Expand All @@ -286,9 +290,13 @@ <h1>{{ site_name }}—Professional Development, the MIT Way</h1>
>
{% endif %}
<h1>PROGRAMS</h1>
{% if not program_pages %}
{% include "partials/catalog_empty.html" %}
{% else %}
{% for program_page in program_pages %}
{% include "partials/catalog_card.html" with courseware_page=program_page object_type="program" tab="program" %}
{% endfor %}
{% endif %}
</div>

{% if active_tab == "courses-tab" %}
Expand All @@ -307,9 +315,13 @@ <h1>PROGRAMS</h1>
>
{% endif %}
<h1>COURSES</h1>
{% if not course_pages %}
{% include "partials/catalog_empty.html" %}
{% else %}
{% for course_page in course_pages %}
{% include "partials/catalog_card.html" with courseware_page=course_page object_type="course" tab="course" %}
{% endfor %}
{% endif %}
</div>
</div>
</div>
Expand Down
5 changes: 5 additions & 0 deletions cms/templates/partials/catalog_empty.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="empty-catalog-message">
<div>
<h1>No results found</h1>
</div>
</div>
4 changes: 3 additions & 1 deletion cms/views_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,9 @@ def test_catalog_page_languages( # noqa: PLR0913
resp = client.get(f"{catalog_page.get_url()}?language={selected_language}")

assert resp.status_code == status.HTTP_200_OK
assert resp.context_data["language_options"] == [ALL_LANGUAGES] + language_options
assert resp.context_data["language_options"] == [ALL_LANGUAGES] + [
assign_language.name
]
assert resp.context_data["selected_language"] == selected_language
assert len(resp.context_data["course_pages"]) == expected_courses_count
assert len(resp.context_data["program_pages"]) == expected_program_count
Expand Down
28 changes: 28 additions & 0 deletions courses/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
Program,
ProgramCertificate,
ProgramEnrollment,
CourseLanguage,
)
from courseware.api import get_edx_api_course_detail_client
from mitxpro.utils import has_equal_properties, now_in_utc
Expand Down Expand Up @@ -344,3 +345,30 @@ def get_catalog_course_filter(relative_filter=""):
Q(**courseware_live_filter)
& Q(Q(**courserun_start_date_filter) | Q(**courserun_enrollment_end_filter))
)


def get_catalog_languages():
"""
Returns the languages that are associated with courses or programs visible in the catalog
"""

course_languages = (
CourseLanguage.objects.filter(
Q(get_catalog_course_filter("coursepage__"))
| Q(
get_catalog_course_filter("programpage__program__courses__coursepage__")
)
| Q(get_catalog_course_filter("externalcoursepage__"))
| Q(
get_catalog_course_filter(
"externalprogrampage__program__courses__externalcoursepage__"
)
),
is_active=True,
)
.distinct()
.order_by("priority")
.values_list("name", flat=True)
)

return list(course_languages)
44 changes: 44 additions & 0 deletions courses/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
Tests for signals
"""

from datetime import timedelta

from unittest.mock import Mock

import factory
import pytest
from edx_api.course_detail import CourseDetail, CourseDetails
from requests.exceptions import HTTPError
Expand All @@ -16,13 +19,16 @@
ProgramCertificateFactory,
ProgramFactory,
UserFactory,
CourseLanguageFactory,
)
from courses.models import ProgramCertificate
from courses.utils import (
generate_program_certificate,
process_course_run_grade_certificate,
sync_course_runs,
get_catalog_languages,
)
from mitxpro.utils import now_in_utc

pytestmark = pytest.mark.django_db

Expand Down Expand Up @@ -208,3 +214,41 @@ def test_sync_course_runs(settings, mocker, mocked_api_response, expect_success)
else:
assert success_count == 0
assert failure_count == 1


def test_catalog_visible_languages():
"""Test that get_catalog_languages returns the expected languages"""

catalog_visible_languages = CourseLanguageFactory.create_batch(
2, name=factory.Iterator(["Language1", "Language2"])
)
catalog_invisble_languages = CourseLanguageFactory.create_batch(
2, name=factory.Iterator(["Language3", "Language4"])
)
catalog_visible_inactive_languages = CourseLanguageFactory.create_batch(
2, name=factory.Iterator(["Language5", "Language6"]), is_active=False
)
now = now_in_utc()
# Creates active courses (Course runs will create underlying course and page objects)
CourseRunFactory.create_batch(
4,
start_date=now + timedelta(days=1),
enrollment_end=now + timedelta(days=2),
course__page__language=factory.Iterator(catalog_visible_languages),
course__program__page__language=factory.Iterator(
catalog_visible_languages + catalog_visible_inactive_languages
),
)
# Creates expired courses (Course runs will create underlying course and page objects)
CourseRunFactory.create_batch(
2,
start_date=now - timedelta(days=1),
enrollment_end=now - timedelta(days=2),
course__page__language=factory.Iterator(catalog_invisble_languages),
course__program__page__language=factory.Iterator(catalog_invisble_languages),
)

# The expected languages are the ones that are associated with unexpuired/catalog visible courses
assert get_catalog_languages() == [
catalog_language.name for catalog_language in catalog_visible_languages
]
10 changes: 10 additions & 0 deletions static/scss/catalog/tabs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@
@include media-breakpoint-down(md) {
padding-left: 20px;
}

.empty-catalog-message {
display: flex;
flex-direction: column;
margin-top: 90px;
justify-content: center;
align-items: center;
height: 100%;
text-align: center;
}
}
}

Expand Down

0 comments on commit 9d9c4fb

Please sign in to comment.