def test_models_category_get_courses_descendants(self): """ Related courses should include the courses linked to the category's descendants, unless specifically deactivated by the "include_descendants" argument. """ category_page = create_page("Subjects", "courses/cms/category_detail.html", "en", published=True) category = CategoryFactory(extended_object=category_page, should_publish=True) courses = CourseFactory.create_batch(2, fill_categories=[category], should_publish=True) child_category_page = create_page( "Literature", "courses/cms/category_detail.html", "en", parent=category_page, published=True, ) child_category = CategoryFactory(extended_object=child_category_page, should_publish=True) courses_child = CourseFactory.create_batch( 2, fill_categories=[child_category], should_publish=True) grand_child_category_page = create_page( "Literature", "courses/cms/category_detail.html", "en", parent=child_category_page, published=True, ) grand_child_category = CategoryFactory( extended_object=grand_child_category_page, should_publish=True) courses_grand_child = CourseFactory.create_batch( 2, fill_categories=[grand_child_category], should_publish=True) # Check that each category gets courses from its descendants # ...unless we pass an argument to deactivate it self.assertEqual(list(category.get_courses()), courses + courses_child + courses_grand_child) self.assertEqual(list(category.get_courses(include_descendants=False)), courses) self.assertEqual(list(child_category.get_courses()), courses_child + courses_grand_child) self.assertEqual( list(child_category.get_courses(include_descendants=False)), courses_child) self.assertEqual( list(grand_child_category.get_courses(include_descendants=False)), courses_grand_child, ) self.assertEqual(list(grand_child_category.get_courses()), courses_grand_child)
def test_signals_categories_no_parent(self, mock_bulk, *_): """ Publishing a category should update its document in the Elasticsearch categories index, and the documents for published courses to which it is related, excluding snapshots. """ category = CategoryFactory() published_course, _unpublished_course = CourseFactory.create_batch( 2, fill_categories=[category]) published_course.extended_object.publish("en") published_course.refresh_from_db() self.run_commit_hooks() mock_bulk.reset_mock() category.extended_object.publish("en") category.refresh_from_db() # Elasticsearch should not be called before the db transaction is successful self.assertFalse(mock_bulk.called) self.run_commit_hooks() self.assertEqual(mock_bulk.call_count, 1) self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 2) actions = list(mock_bulk.call_args[1]["actions"]) self.assertEqual( actions[0]["_id"], str(published_course.public_extension.extended_object_id)) self.assertEqual(actions[0]["_type"], "course") self.assertEqual(actions[1]["_id"], "L-0001") self.assertEqual(actions[1]["_type"], "category")
def test_signals_persons_publish(self, mock_bulk, *_): """ Publishing a person should update its document in the Elasticsearch persons index, and the documents for published courses to which it is related, excluding snapshots. """ person = PersonFactory() published_course, _unpublished_course = CourseFactory.create_batch( 2, fill_team=[person]) self.assertTrue(published_course.extended_object.publish("en")) published_course.refresh_from_db() self.run_commit_hooks() mock_bulk.reset_mock() self.assertTrue(person.extended_object.publish("en")) person.refresh_from_db() # Elasticsearch should not be called before the db transaction is successful self.assertFalse(mock_bulk.called) self.run_commit_hooks() self.assertEqual(mock_bulk.call_count, 1) self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 2) actions = list(mock_bulk.call_args[1]["actions"]) self.assertEqual(actions[0]["_id"], published_course.get_es_id()) self.assertEqual(actions[0]["_op_type"], "index") self.assertEqual(actions[0]["_index"], "test_courses") self.assertEqual(actions[1]["_id"], person.get_es_id()) self.assertEqual(actions[1]["_op_type"], "index") self.assertEqual(actions[1]["_index"], "richie_persons")
def test_signals_categories_publish(self, mock_bulk, *_): """ Publishing a category should update its document in the Elasticsearch categories index, and the documents for published courses to which it is related, excluding snapshots. """ parent = CategoryFactory(should_publish=True) category = CategoryFactory(page_parent=parent.extended_object) published_course, _unpublished_course = CourseFactory.create_batch( 2, fill_categories=[category]) self.assertTrue(published_course.extended_object.publish("en")) published_course.refresh_from_db() self.run_commit_hooks() mock_bulk.reset_mock() self.assertTrue(category.extended_object.publish("en")) category.refresh_from_db() # Elasticsearch should not be called before the db transaction is successful self.assertFalse(mock_bulk.called) self.run_commit_hooks() self.assertEqual(mock_bulk.call_count, 1) self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 3) actions = list(mock_bulk.call_args[1]["actions"]) self.assertEqual(actions[0]["_id"], published_course.get_es_id()) self.assertEqual(actions[0]["_op_type"], "index") self.assertEqual(actions[0]["_index"], "test_courses") self.assertEqual(actions[1]["_id"], category.get_es_id()) self.assertEqual(actions[1]["_op_type"], "index") self.assertEqual(actions[1]["_index"], "richie_categories") self.assertEqual(actions[2]["_id"], parent.get_es_id()) self.assertEqual(actions[2]["_op_type"], "index") self.assertEqual(actions[2]["_index"], "richie_categories")
def test_models_subject_courses_copied_when_publishing(self): """ When publishing an subject, the links courses on the draft version of the subject should be copied. """ # Create draft courses course1, course2 = CourseFactory.create_batch(2) # Create a draft subject draft_subject = SubjectFactory(with_courses=[course1, course2]) # Publish course1 course1.extended_object.publish("en") course1.refresh_from_db() # The draft subject should see all courses self.assertEqual(set(draft_subject.courses.all()), {course1, course2}) self.assertEqual(set(draft_subject.courses.drafts()), {course1, course2}) # Publish the subject and check that the courses are copied draft_subject.extended_object.publish("en") published_subject = Subject.objects.get( extended_object__publisher_is_draft=False) self.assertEqual(set(published_subject.courses.all()), {course1.public_extension})
def test_signals_organizations(self, mock_bulk, *_): """ Publishing an organization should update its document in the Elasticsearch organizations index, and the documents for published courses to which it is related, excluding snapshots. """ parent = OrganizationFactory(should_publish=True) organization = OrganizationFactory(page_parent=parent.extended_object) published_course, _unpublished_course = CourseFactory.create_batch( 2, fill_organizations=[organization]) published_course.extended_object.publish("en") published_course.refresh_from_db() self.run_commit_hooks() mock_bulk.reset_mock() organization.extended_object.publish("en") organization.refresh_from_db() # Elasticsearch should not be called before the db transaction is successful self.assertFalse(mock_bulk.called) self.run_commit_hooks() self.assertEqual(mock_bulk.call_count, 1) self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 3) actions = list(mock_bulk.call_args[1]["actions"]) self.assertEqual( actions[0]["_id"], str(published_course.public_extension.extended_object_id)) self.assertEqual(actions[0]["_type"], "course") self.assertEqual(actions[1]["_id"], "L-00010001") self.assertEqual(actions[1]["_type"], "organization") self.assertEqual(actions[2]["_id"], "P-0001") self.assertEqual(actions[2]["_type"], "organization")
def test_templates_organization_detail_cms_draft_content(self): """ A staff user should see a draft organization including its draft elements with an annotation. """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") courses = CourseFactory.create_batch(4) organization = OrganizationFactory(page_title="La Sorbonne", fill_courses=courses) page = organization.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[2].extended_object.publish("en") courses[2].extended_object.unpublish("en") # The page should be visible as draft to the staff user url = page.get_absolute_url() response = self.client.get(url) self.assertContains(response, "<title>La Sorbonne</title>", html=True, status_code=200) self.assertContains( response, '<h1 class="organization-detail__title">La Sorbonne</h1>', html=True, ) # The published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<p class="course-glimpse__content__title">{:s}</p>'.format( course.extended_object.get_title()), html=True, ) # Draft courses should also be present on the page with an annotation for styling for course in courses[-2:]: self.assertContains( response, ('<a class="{name:s} {name:s}--link {name:s}--draft" ' 'href="{link:s}">').format( name="course-glimpse", link=course.extended_object.get_absolute_url(), ), ) self.assertContains( response, '<p class="course-glimpse__content__title">{title:s}</p>'. format(title=course.extended_object.get_title()), html=True, )
def test_templates_program_detail_cms_draft_content(self): """ A staff user should see a draft program including only its public elements. """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") courses = CourseFactory.create_batch(4) program = ProgramFactory( page_title="Preums", fill_cover=True, fill_excerpt=True, fill_body=True, fill_courses=courses, ) page = program.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[2].extended_object.publish("en") courses[2].extended_object.unpublish("en") # The page should be visible as draft to the staff user url = page.get_absolute_url() response = self.client.get(url) self.assertContains(response, "<title>Preums</title>", html=True, status_code=200) self.assertContains(response, '<h1 class="subheader__title">Preums</h1>', html=True) # The published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<p class="course-glimpse__title">{:s}</p>'.format( course.extended_object.get_title()), html=True, ) # Draft courses should not be present on the page for course in courses[-2:]: self.assertNotIn( course.extended_object.get_absolute_url(), re.sub(" +", " ", str(response.content).replace("\\n", "")), ) self.assertNotContains( response, course.extended_object.get_title(), html=True, )
def test_subject_cms_draft_content(self): """ A staff user should see a draft subject including its draft elements with an annotation """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") courses = CourseFactory.create_batch(4) subject = SubjectFactory(title="Very interesting subject", with_courses=courses) page = subject.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[2].extended_object.publish("en") courses[2].extended_object.unpublish("en") # The page should be visible as draft to the staff user url = page.get_absolute_url() response = self.client.get(url) self.assertContains( response, "<title>Very interesting subject</title>", status_code=200, html=True, ) self.assertContains( response, '<h1 class="subject-detail__title">Very interesting subject</h1>', html=True, ) # The published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<li class="subject-detail__content__courses__item">{:s}</li>'. format(course.extended_object.get_title()), html=True, ) # The draft course should also be present on the page with an annotation for styling for course in courses[-2:]: self.assertContains( response, '<li class="{element:s} {element:s}--draft">{title:s}</li>'. format( element="subject-detail__content__courses__item", title=course.extended_object.get_title(), ), html=True, )
def test_templates_program_detail_cms_published_content(self): """ Validate that the important elements are displayed on a published program page """ courses = CourseFactory.create_batch(4) program = ProgramFactory( page_title="Preums", fill_cover=True, fill_excerpt=True, fill_body=True, fill_courses=courses, ) page = program.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[2].extended_object.publish("en") courses[2].extended_object.unpublish("en") # The page should not be visible before it is published url = page.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 404) # Publish the program and ensure the content is correct page.publish("en") response = self.client.get(url) self.assertContains( response, "<title>Preums - Program - example.com</title>", html=True, status_code=200, ) self.assertContains(response, '<h1 class="subheader__title">Preums</h1>', html=True) # Only published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<span class="course-glimpse__title-text">{0:s}</span>'.format( # noqa pylint: disable=consider-using-f-string,line-too-long course.extended_object.get_title()), html=True, ) for course in courses[-2:]: self.assertNotContains(response, course.extended_object.get_title())
def test_templates_category_detail_cms_published_content_max_courses( self, _mock_page_url): """ Make sure the category detail page does not display too many courses, even when a large number are related to the current category, as this can cause the page to load very slowly and is not a great experience for the user anyway. """ # Create our dummy category and the 3 courses we'll attach to it meta = CategoryFactory( page_parent=create_i18n_page( { "en": "Categories", "fr": "Catégories" }, published=True), page_reverse_id="subjects", page_title={ "en": "Subjects", "fr": "Sujets" }, should_publish=True, ) category = CategoryFactory(page_parent=meta.extended_object, should_publish=True) courses = CourseFactory.create_batch(3, fill_categories=[category], should_publish=True) # Link the 3 courses with our category through the relevant placeholder for course in courses: add_plugin( course.extended_object.placeholders.get( slot="course_categories"), CategoryPlugin, "en", page=category.extended_object, ) # Make sure we do have 3 courses on the category self.assertEqual(category.get_courses().count(), 3) # Only the first two are rendered in the template response = self.client.get(category.extended_object.get_absolute_url()) self.assertContains(response, courses[0].extended_object.get_title()) self.assertContains(response, courses[1].extended_object.get_title()) self.assertNotContains(response, courses[2].extended_object.get_title()) # There is a link to view more related courses directly in the Search view self.assertContains( response, f'href="/the/courses/?subjects={category.get_es_id():s}"') self.assertContains( response, f"See all courses related to {category.extended_object.get_title():s}", )
def test_signals_persons_unpublish(self, mock_bulk, *_): """ Unpublishing a person in a language should update its document in the Elasticsearch persons index or delete it if there is no language published anymore. It should also reindex the documents for published courses to which it is related, excluding snapshots. """ person = PersonFactory(page_languages=["en", "fr"], should_publish=True) published_course, _unpublished_course = CourseFactory.create_batch( 2, fill_team=[person]) self.assertTrue(published_course.extended_object.publish("en")) published_course.refresh_from_db() self.run_commit_hooks() mock_bulk.reset_mock() # - Unpublish the first language self.assertTrue(person.extended_object.unpublish("en")) person.refresh_from_db() # Elasticsearch should not be called before the db transaction is successful self.assertFalse(mock_bulk.called) self.run_commit_hooks() self.assertEqual(mock_bulk.call_count, 1) self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 2) actions = list(mock_bulk.call_args[1]["actions"]) self.assertEqual(actions[0]["_id"], published_course.get_es_id()) self.assertEqual(actions[0]["_op_type"], "index") self.assertEqual(actions[0]["_index"], "test_courses") self.assertEqual(actions[1]["_id"], person.get_es_id()) self.assertEqual(actions[1]["_op_type"], "index") self.assertEqual(actions[1]["_index"], "richie_persons") mock_bulk.reset_mock() # - Unpublish the second language self.assertTrue(person.extended_object.unpublish("fr")) person.refresh_from_db() # Elasticsearch should not be called before the db transaction is successful self.assertFalse(mock_bulk.called) self.run_commit_hooks() self.assertEqual(mock_bulk.call_count, 1) self.assertEqual(len(mock_bulk.call_args[1]["actions"]), 2) actions = list(mock_bulk.call_args[1]["actions"]) self.assertEqual(actions[0]["_id"], published_course.get_es_id()) self.assertEqual(actions[0]["_op_type"], "index") self.assertEqual(actions[0]["_index"], "test_courses") self.assertEqual(actions[1]["_id"], person.get_es_id()) self.assertEqual(actions[1]["_op_type"], "delete") self.assertEqual(actions[1]["_index"], "richie_persons")
def test_organization_cms_published_content(self): """ Validate that the important elements are displayed on a published organization page """ courses = CourseFactory.create_batch(4) organization = OrganizationFactory(title="La Sorbonne", logo="my_logo.jpg", with_courses=courses) page = organization.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[2].extended_object.publish("en") courses[2].extended_object.unpublish("en") # The page should not be visible before it is published url = page.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 404) # Publish and ensure content is correct page.publish("en") response = self.client.get(url) self.assertContains(response, "<title>La Sorbonne</title>", html=True, status_code=200) self.assertContains( response, '<h1 class="organization-detail__title">La Sorbonne</h1>', html=True, ) self.assertContains( response, '<img src="/media/my_logo.jpg" alt="La Sorbonne logo">', html=True) # Only published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<li class="organization-detail__content__courses__item">{:s}</li>' .format(course.extended_object.get_title()), html=True, ) for course in courses[-2:]: self.assertNotContains(response, course.extended_object.get_title())
def test_templates_category_detail_cms_published_content_max_courses_on_meta( self, _mock_page_url): """ Meta categories are a special case: technically, any page linked to one of their children is linked to the meta-category too. This means in a lot of cases we just want a link to *all* courses not just their related courses. The Search view is also not equipped to filter on a meta-category. In this case, we just link to it with a different link text. """ # Create our dummy category and the 3 courses we'll attach to it meta = CategoryFactory( page_parent=create_i18n_page( { "en": "Categories", "fr": "Catégories" }, published=True), page_reverse_id="subjects", page_title={ "en": "Subjects", "fr": "Sujets" }, should_publish=True, ) category = CategoryFactory(page_parent=meta.extended_object, should_publish=True) courses = CourseFactory.create_batch(3, fill_categories=[category], should_publish=True) # Link the 3 courses with our category through the relevant placeholder for course in courses: add_plugin( course.extended_object.placeholders.get( slot="course_categories"), CategoryPlugin, "en", page=category.extended_object, ) # Make sure we do have 3 courses on the category self.assertEqual(category.get_courses().count(), 3) # NB: here we are requesting the meta category's page, not the child category # Only the first two are rendered in the template response = self.client.get(meta.extended_object.get_absolute_url()) self.assertContains(response, courses[0].extended_object.get_title()) self.assertContains(response, courses[1].extended_object.get_title()) self.assertNotContains(response, courses[2].extended_object.get_title()) # There is a link to view all courses self.assertContains(response, 'href="/the/courses/') self.assertContains(response, "See all courses")
def test_templates_category_detail_cms_published_content(self): """ Validate that the important elements are displayed on a published category page """ courses = CourseFactory.create_batch(4) category = CategoryFactory( page_title="Very interesting category", fill_courses=courses ) page = category.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[2].extended_object.publish("en") courses[2].extended_object.unpublish("en") # The page should not be visible before it is published url = page.get_absolute_url() response = self.client.get(url) self.assertEqual(response.status_code, 404) # Publish the category and ensure the content is correct page.publish("en") response = self.client.get(url) self.assertContains( response, "<title>Very interesting category</title>", status_code=200, html=True, ) self.assertContains( response, '<h1 class="category-detail__title">Very interesting category</h1>', html=True, ) # Only published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<p class="course-glimpse__content__title">{:s}</p>'.format( course.extended_object.get_title() ), html=True, ) for course in courses[-2:]: self.assertNotContains(response, course.extended_object.get_title())
def test_models_category_get_courses_ordering(self): """The related courses should be sorted by their position in the pages tree.""" category = CategoryFactory(should_publish=True) course1, course2, course3 = CourseFactory.create_batch( 3, fill_categories=[category], should_publish=True) self.assertEqual(list(category.get_courses()), [course1, course2, course3]) # Move pages in the tree and check that they are returned in the new order course3.extended_object.move_page(course1.extended_object.node, position="left") self.assertEqual(list(category.get_courses()), [course3, course1, course2]) course1.extended_object.move_page(course3.extended_object.node, position="left") self.assertEqual(list(category.get_courses()), [course1, course3, course2])
def test_models_category_get_courses(self): """ It should be possible to retrieve the list of related courses on the category instance. The number of queries should be minimal. """ category = CategoryFactory(should_publish=True) courses = CourseFactory.create_batch( 3, page_title="my title", fill_categories=[category], should_publish=True ) retrieved_courses = category.get_courses() with self.assertNumQueries(2): self.assertEqual(set(retrieved_courses), set(courses)) with self.assertNumQueries(0): for course in retrieved_courses: self.assertEqual( course.extended_object.prefetched_titles[0].title, "my title" )
def test_organization_courses_copied_when_publishing(self): """ When publishing a organization, the links to draft courses on the draft version of the organization should be copied (clear then add) to the published version. Links to published courses should not be copied as they are redundant and not up-to-date. """ # Create draft courses course1, course2 = CourseFactory.create_batch(2) # Create a draft organization draft_organization = OrganizationFactory( with_courses=[course1, course2]) # Publish course1 course1.extended_object.publish("en") course1.refresh_from_db() # The draft organization should see all courses and propose a custom filter to easily # access the draft versions self.assertEqual( set(draft_organization.courses.all()), {course1, course1.public_extension, course2}, ) self.assertEqual(set(draft_organization.courses.drafts()), {course1, course2}) # Publish the organization and check that the courses are copied draft_organization.extended_object.publish("en") published_organization = Organization.objects.get( extended_object__publisher_is_draft=False) self.assertEqual(set(published_organization.courses.all()), {course1, course2}) # When publishing, the courses that are obsolete should be cleared draft_organization.courses.remove(course2) self.assertEqual(set(published_organization.courses.all()), {course1, course2}) # courses on the published organization are only cleared after publishing the draft page draft_organization.extended_object.publish("en") self.assertEqual(set(published_organization.courses.all()), {course1})
def test_templates_organization_detail_cms_published_content_max_courses( self, _mock_page_url): """ Make sure the organization detail page does not display too many courses, even when a large number are related to the current organization, as this can cause the page to load very slowly and is not a great experience for the user anyway. """ # Create our dummy organization and the 3 courses we'll attach to it organization = OrganizationFactory(should_publish=True) courses = CourseFactory.create_batch(3, fill_organizations=[organization], should_publish=True) # Link the 3 courses with our organization through the relevant placeholder for course in courses: add_plugin( course.extended_object.placeholders.get( slot="course_organizations"), OrganizationPlugin, "en", page=organization.extended_object, ) # Make sure we do have 3 courses on the organization self.assertEqual(organization.get_courses().count(), 3) # Only the first two are rendered in the template response = self.client.get( organization.extended_object.get_absolute_url()) self.assertContains(response, courses[0].extended_object.get_title()) self.assertContains(response, courses[1].extended_object.get_title()) self.assertNotContains(response, courses[2].extended_object.get_title()) # There is a link to view more related courses directly in the Search view self.assertContains( response, f'href="/the/courses/?organizations={organization.get_es_id():s}"') self.assertContains( response, f"See all courses related to {organization.extended_object.get_title():s}", )
def test_models_organization_get_courses_language_fallback_published(self): """ Validate that the reverse courses lookup works as expected with language fallback on a published page. """ organization1, organization2, organization3 = OrganizationFactory.create_batch( 3, should_publish=True) public_organization1 = organization1.public_extension public_organization2 = organization2.public_extension public_organization3 = organization3.public_extension course, course_unpublished = CourseFactory.create_batch( 2, page_languages=["en", "fr", "de"], should_publish=True) public_course = course.public_extension public_course_unpublished = course_unpublished.public_extension course_unpublished.extended_object.unpublish("en") course_unpublished.extended_object.unpublish("fr") course_unpublished.extended_object.unpublish("de") placeholder = public_course.extended_object.placeholders.get( slot="course_organizations") placeholder_unpublished = ( public_course_unpublished.extended_object.placeholders.get( slot="course_organizations")) # Reverse plugin lookups should fallback up to the second priority language add_plugin( language="de", placeholder=placeholder, plugin_type="OrganizationPlugin", **{"page": organization1.extended_object}, ) add_plugin( language="de", placeholder=placeholder_unpublished, plugin_type="OrganizationPlugin", **{"page": organization1.extended_object}, ) with translation.override("en"): self.assertEqual(list(public_organization1.get_courses()), [public_course]) self.assertEqual(list(public_organization2.get_courses()), []) self.assertEqual(list(public_organization3.get_courses()), []) with translation.override("fr"): self.assertEqual(list(public_organization1.get_courses()), [public_course]) self.assertEqual(list(public_organization2.get_courses()), []) self.assertEqual(list(public_organization3.get_courses()), []) with translation.override("de"): self.assertEqual(list(public_organization1.get_courses()), [public_course]) self.assertEqual(list(public_organization2.get_courses()), []) self.assertEqual(list(public_organization3.get_courses()), []) # Reverse plugin lookups should fallback to the first priority language if available # and ignore the second priority language unless it is the current language add_plugin( language="fr", placeholder=placeholder, plugin_type="OrganizationPlugin", **{"page": organization2.extended_object}, ) add_plugin( language="fr", placeholder=placeholder_unpublished, plugin_type="OrganizationPlugin", **{"page": organization2.extended_object}, ) with translation.override("en"): self.assertEqual(list(public_organization1.get_courses()), []) self.assertEqual(list(public_organization2.get_courses()), [public_course]) self.assertEqual(list(public_organization3.get_courses()), []) with translation.override("fr"): self.assertEqual(list(public_organization1.get_courses()), []) self.assertEqual(list(public_organization2.get_courses()), [public_course]) self.assertEqual(list(public_organization3.get_courses()), []) with translation.override("de"): self.assertEqual(list(public_organization1.get_courses()), [public_course]) self.assertEqual(list(public_organization2.get_courses()), []) self.assertEqual(list(public_organization3.get_courses()), []) # Reverse plugin lookups should stick to the current language if available and # ignore plugins on fallback languages add_plugin( language="en", placeholder=placeholder, plugin_type="OrganizationPlugin", **{"page": organization3.extended_object}, ) add_plugin( language="en", placeholder=placeholder_unpublished, plugin_type="OrganizationPlugin", **{"page": organization3.extended_object}, ) with translation.override("en"): self.assertEqual(list(public_organization1.get_courses()), []) self.assertEqual(list(public_organization2.get_courses()), []) self.assertEqual(list(public_organization3.get_courses()), [public_course]) with translation.override("fr"): self.assertEqual(list(public_organization1.get_courses()), []) self.assertEqual(list(public_organization2.get_courses()), [public_course]) self.assertEqual(list(public_organization3.get_courses()), []) with translation.override("de"): self.assertEqual(list(public_organization1.get_courses()), [public_course]) self.assertEqual(list(public_organization2.get_courses()), []) self.assertEqual(list(public_organization3.get_courses()), [])
def test_templates_program_detail_cms_draft_content(self): """ A staff user should see a draft program including draft elements. """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") courses = CourseFactory.create_batch(4) program = ProgramFactory( page_title="Preums", fill_cover=True, fill_excerpt=True, fill_body=True, fill_courses=courses, ) page = program.extended_object # Publish only 2 out of 4 courses courses[0].extended_object.publish("en") courses[1].extended_object.publish("en") # The unpublished objects may have been published and unpublished which puts them in a # status different from objects that have never been published. # We want to test both cases. courses[3].extended_object.publish("en") courses[3].extended_object.unpublish("en") # The page should be visible as draft to the staff user url = page.get_absolute_url() response = self.client.get(url) self.assertContains( response, "<title>Preums - Program - example.com</title>", html=True, status_code=200, ) self.assertContains(response, '<h1 class="subheader__title">Preums</h1>', html=True) # Draft and published courses should be present on the page for course in courses[:2]: self.assertContains( response, '<a class="course-glimpse__link" ' f'href="{course.extended_object.get_absolute_url():s}"', ) self.assertContains( response, '<span class="course-glimpse__title-text">{0:s}</span>'.format( # noqa pylint: disable=consider-using-f-string,line-too-long course.extended_object.get_title()), html=True, ) self.assertContains( response, '<div class="course-glimpse course-glimpse--draft">' '<div aria-hidden="true" class="course-glimpse__media">' f'<a tabindex="-1" href="{courses[2].extended_object.get_absolute_url():s}"', ) self.assertContains( response, '<span class="course-glimpse__title-text">{0:s}</span>'.format( # noqa pylint: disable=consider-using-f-string,line-too-long courses[2].extended_object.get_title()), html=True, ) # The unpublished course should not be present on the page self.assertNotContains(response, courses[3].extended_object.get_title())