From b3c46a825fe60c9d5cffeccad26b259e87fd93da Mon Sep 17 00:00:00 2001 From: Samuel Paccoud Date: Fri, 4 Feb 2022 10:48:36 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(courses)=20hide=20unpublished=20ob?= =?UTF-8?q?jects=20from=20list=20views=20(#1580)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The template code was a bit too naïve and did not exclude unpublished objects on the public site. --- CHANGELOG.md | 1 + .../templates/courses/cms/category_list.html | 29 ++++++--- .../courses/cms/organization_list.html | 4 ++ .../templates/courses/cms/person_list.html | 7 ++- .../templates/courses/cms/program_list.html | 14 ++++- .../courses/test_templates_category_list.py | 59 +++++++++++++++++++ .../courses/test_templates_person_list.py | 57 ++++++++++++++++++ .../courses/test_templates_program_list.py | 59 +++++++++++++++++++ 8 files changed, 218 insertions(+), 12 deletions(-) create mode 100644 tests/apps/courses/test_templates_category_list.py create mode 100644 tests/apps/courses/test_templates_person_list.py create mode 100644 tests/apps/courses/test_templates_program_list.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bb8fc4f43..e0b04a56de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Versioning](https://semver.org/spec/v2.0.0.html). ### Fixed +- Hide unpublished objects from list views (category, person and program) - Add missing translation within search autocomplete menu - Fix a layout issue on autosuggest search menu - Fixed a layout issue on course glimpse diff --git a/src/richie/apps/courses/templates/courses/cms/category_list.html b/src/richie/apps/courses/templates/courses/cms/category_list.html index 7f53074caa..7418b78bc3 100644 --- a/src/richie/apps/courses/templates/courses/cms/category_list.html +++ b/src/richie/apps/courses/templates/courses/cms/category_list.html @@ -1,5 +1,5 @@ {% extends "richie/fullwidth.html" %} -{% load cms_tags i18n %} +{% load cms_tags i18n pagination_tags %} {% block subheader_content %}
@@ -11,15 +11,26 @@

{{ current_page.get_title }}

{% block content %}
- {% for page in current_page.get_child_pages %} - {% if page.category %} - {% include "courses/cms/fragment_category_glimpse.html" with category=page.category category_variant="glimpse" %} + {% if current_page.publisher_is_draft %} + {% autopaginate current_page.get_child_pages 100 as object_list %} + {% else %} + {% autopaginate current_page.get_child_pages.published.distinct 100 as object_list %} {% endif %} - {% empty %} -

- {% trans "No categories" %} -

- {% endfor %} + + {% for page in object_list %} + {% if page.category %} + {% include "courses/cms/fragment_category_glimpse.html" with category=page.category category_variant="glimpse" %} + {% endif %} + {% empty %} +

+ {% trans "No categories" %} +

+ {% endfor %} + + {% if object_list %} + {% paginate using "richie/pagination.html" %} + {% endif %} +
{% endblock content %} diff --git a/src/richie/apps/courses/templates/courses/cms/organization_list.html b/src/richie/apps/courses/templates/courses/cms/organization_list.html index 89966cbead..ca13b86c17 100644 --- a/src/richie/apps/courses/templates/courses/cms/organization_list.html +++ b/src/richie/apps/courses/templates/courses/cms/organization_list.html @@ -23,6 +23,10 @@

{{ current_page.get_title }}

{% empty %}

{% trans "No organization yet" %}

{% endfor %} + + {% if object_list %} + {% paginate using "richie/pagination.html" %} + {% endif %}
{% endblock content %} diff --git a/src/richie/apps/courses/templates/courses/cms/person_list.html b/src/richie/apps/courses/templates/courses/cms/person_list.html index 8074a2bb5e..55d32ecea3 100644 --- a/src/richie/apps/courses/templates/courses/cms/person_list.html +++ b/src/richie/apps/courses/templates/courses/cms/person_list.html @@ -11,7 +11,12 @@

{{ current_page.get_title }}

{% block content %}
- {% autopaginate current_page.get_child_pages 24 as object_list %} + {% if current_page.publisher_is_draft %} + {% autopaginate current_page.get_child_pages 100 as object_list %} + {% else %} + {% autopaginate current_page.get_child_pages.published.distinct 100 as object_list %} + {% endif %} + {% for page in object_list %} {% if page.person %} {% include "courses/cms/fragment_person_glimpse.html" with person=page.person %} diff --git a/src/richie/apps/courses/templates/courses/cms/program_list.html b/src/richie/apps/courses/templates/courses/cms/program_list.html index 7c995ca859..50c8bf063b 100644 --- a/src/richie/apps/courses/templates/courses/cms/program_list.html +++ b/src/richie/apps/courses/templates/courses/cms/program_list.html @@ -1,5 +1,5 @@ {% extends "richie/fullwidth.html" %} -{% load cms_tags extra_tags i18n %} +{% load cms_tags extra_tags i18n pagination_tags %} {% block subheader_content %}
@@ -19,7 +19,13 @@

{{ current_page.get_title }}

- {% for page in current_page.get_child_pages %} + {% if current_page.publisher_is_draft %} + {% autopaginate current_page.get_child_pages 100 as object_list %} + {% else %} + {% autopaginate current_page.get_child_pages.published.distinct 100 as object_list %} + {% endif %} + + {% for page in object_list %} {% if page.program %} {% include "courses/cms/fragment_program_glimpse.html" with program=page.program %} {% endif %} @@ -28,6 +34,10 @@

{{ current_page.get_title }}

{% trans "No associated programs" %}

{% endfor %} + + {% if object_list %} + {% paginate using "richie/pagination.html" %} + {% endif %}
diff --git a/tests/apps/courses/test_templates_category_list.py b/tests/apps/courses/test_templates_category_list.py new file mode 100644 index 0000000000..f7b79112fb --- /dev/null +++ b/tests/apps/courses/test_templates_category_list.py @@ -0,0 +1,59 @@ +""" +End-to-end tests for the category list view +""" +from datetime import timedelta +from unittest import mock + +from django.utils import timezone + +from cms.test_utils.testcases import CMSTestCase + +from richie.apps.core.factories import PageFactory, UserFactory +from richie.apps.courses.factories import CategoryFactory + + +class ListCategoryCMSTestCase(CMSTestCase): + """ + End-to-end test suite to validate the content and Ux of the category list view + """ + + def test_templates_category_list_cms_content(self): + """ + Validate that the public website only displays categories that are currently published, + while staff users can see draft and unpublished categories. + """ + page = PageFactory( + template="courses/cms/category_list.html", + title__language="en", + should_publish=True, + ) + + CategoryFactory(page_parent=page, page_title="First category") + CategoryFactory( + page_parent=page, page_title="Second category", should_publish=True + ) + + # Publish with a publication date in the future + future = timezone.now() + timedelta(hours=1) + with mock.patch("cms.models.pagemodel.now", return_value=future): + CategoryFactory( + page_parent=page, page_title="Third category", should_publish=True + ) + + # Anonymous users should only see published categories + response = self.client.get(page.get_absolute_url()) + + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, "First") + self.assertContains(response, "Second") + self.assertNotContains(response, "Third") + + # Staff users can see draft and unpublished categories + user = UserFactory(is_staff=True, is_superuser=True) + self.client.login(username=user.username, password="password") + + response = self.client.get(page.get_absolute_url()) + self.assertEqual(response.status_code, 200) + + for title in ["First", "Second", "Third"]: + self.assertContains(response, title) diff --git a/tests/apps/courses/test_templates_person_list.py b/tests/apps/courses/test_templates_person_list.py new file mode 100644 index 0000000000..8dd010bce3 --- /dev/null +++ b/tests/apps/courses/test_templates_person_list.py @@ -0,0 +1,57 @@ +""" +End-to-end tests for the person list view +""" +from datetime import timedelta +from unittest import mock + +from django.utils import timezone + +from cms.test_utils.testcases import CMSTestCase + +from richie.apps.core.factories import PageFactory, UserFactory +from richie.apps.courses.factories import PersonFactory + + +class ListPersonCMSTestCase(CMSTestCase): + """ + End-to-end test suite to validate the content and Ux of the person list view + """ + + def test_templates_person_list_cms_content(self): + """ + Validate that the public website only displays persons that are currently published, + while staff users can see draft and unpublished persons. + """ + page = PageFactory( + template="courses/cms/person_list.html", + title__language="en", + should_publish=True, + ) + + PersonFactory(page_parent=page, page_title="First person") + PersonFactory(page_parent=page, page_title="Second person", should_publish=True) + + # Publish with a publication date in the future + future = timezone.now() + timedelta(hours=1) + with mock.patch("cms.models.pagemodel.now", return_value=future): + PersonFactory( + page_parent=page, page_title="Third person", should_publish=True + ) + + # Anonymous users should only see published persons + response = self.client.get(page.get_absolute_url()) + + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, "First") + self.assertContains(response, "Second") + self.assertNotContains(response, "Third") + + # Staff users can see draft and unpublished persons + user = UserFactory(is_staff=True, is_superuser=True) + self.client.login(username=user.username, password="password") + + response = self.client.get(page.get_absolute_url()) + self.assertEqual(response.status_code, 200) + + for title in ["First", "Second", "Third"]: + self.assertContains(response, title) diff --git a/tests/apps/courses/test_templates_program_list.py b/tests/apps/courses/test_templates_program_list.py new file mode 100644 index 0000000000..891b75f91d --- /dev/null +++ b/tests/apps/courses/test_templates_program_list.py @@ -0,0 +1,59 @@ +""" +End-to-end tests for the program list view +""" +from datetime import timedelta +from unittest import mock + +from django.utils import timezone + +from cms.test_utils.testcases import CMSTestCase + +from richie.apps.core.factories import PageFactory, UserFactory +from richie.apps.courses.factories import ProgramFactory + + +class ListProgramCMSTestCase(CMSTestCase): + """ + End-to-end test suite to validate the content and Ux of the program list view + """ + + def test_templates_program_list_cms_content(self): + """ + Validate that the public website only displays programs that are currently published, + while staff users can see draft and unpublished programs. + """ + page = PageFactory( + template="courses/cms/program_list.html", + title__language="en", + should_publish=True, + ) + + ProgramFactory(page_parent=page, page_title="First program") + ProgramFactory( + page_parent=page, page_title="Second program", should_publish=True + ) + + # Publish with a publication date in the future + future = timezone.now() + timedelta(hours=1) + with mock.patch("cms.models.pagemodel.now", return_value=future): + ProgramFactory( + page_parent=page, page_title="Third program", should_publish=True + ) + + # Anonymous users should only see published programs + response = self.client.get(page.get_absolute_url()) + + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, "First") + self.assertContains(response, "Second") + self.assertNotContains(response, "Third") + + # Staff users can see draft and unpublished programs + user = UserFactory(is_staff=True, is_superuser=True) + self.client.login(username=user.username, password="password") + + response = self.client.get(page.get_absolute_url()) + self.assertEqual(response.status_code, 200) + + for title in ["First", "Second", "Third"]: + self.assertContains(response, title)