def test_list_course_runs_by_anonymous_user(self): """ The course run API does not support list requests. """ CourseRunFactory.create_batch(2) response = self.client.get("/api/v1.0/course-runs/") self.assertEqual(response.status_code, 403)
def test_list_course_runs_by_admin_user(self): """ The course run API does not support list requests. """ CourseRunFactory.create_batch(2) self.client.force_login(UserFactory(is_staff=True, is_superuser=True)) response = self.client.get("/api/v1.0/course-runs/") self.assertEqual(response.status_code, 403)
def test_models_course_attribute_course_runs(self): """ The "course_runs" property should return all descendants ranked by path, not only children and should respect publication status for the active language. """ # Create a course with draft and published course runs course = CourseFactory(should_publish=True) # Create draft and published course runs for this course # We want to test 3 situations: # - a draft course run # - a published course run # - a course run that was published and unpublished course_runs = CourseRunFactory.create_batch( 3, page_parent=course.extended_object) course_runs[0].extended_object.publish("en") course_runs[1].extended_object.publish("en") course_runs[1].extended_object.unpublish("en") # Create a child course with draft and published course runs (what results from # snapshotting a course) child_course = CourseFactory(page_parent=course.extended_object, should_publish=True) child_course_runs = CourseRunFactory.create_batch( 3, page_parent=child_course.extended_object) child_course_runs[0].extended_object.publish("en") child_course_runs[1].extended_object.publish("en") child_course_runs[1].extended_object.unpublish("en") # Create another course, not related to the first one, with draft and published course runs other_course = CourseFactory(should_publish=True) other_course_runs = CourseRunFactory.create_batch( 3, page_parent=other_course.extended_object) other_course_runs[0].extended_object.publish("en") other_course_runs[1].extended_object.publish("en") other_course_runs[1].extended_object.unpublish("en") # Check that the draft course retrieves all its descendant course runs # 3 draft course runs and 2 published course runs per course self.assertEqual(CourseRun.objects.count(), 3 * (3 + 2)) with self.assertNumQueries(2): self.assertEqual(list(course.course_runs), course_runs + child_course_runs) # Check that the published course retrieves only the published descendant course runs course_runs[0].refresh_from_db() child_course_runs[0].refresh_from_db() public_course = course.public_extension with self.assertNumQueries(3): result = list(public_course.course_runs) self.assertEqual( result, [ course_runs[0].public_extension, child_course_runs[0].public_extension ], )
def test_models_course_run_fields_course_runs(self): """ The "course_runs" field should always return the course runs linked to the draft version of the course. """ # Create a draft course with course runs course = CourseFactory() course_runs = set(CourseRunFactory.create_batch(2, course=course)) # The course runs should be accessible from the course self.assertEqual(set(course.course_runs.all()), course_runs) # The published course should point to the same course runs course.extended_object.publish("en") course.refresh_from_db() self.assertEqual(set(course.public_extension.course_runs.all()), course_runs)
def test_models_course_get_course_runs(self): """ The `get_course_runs` and `get_course_runs_for_language` methods should return all descendants ranked by path, not only children and should respect publication status. """ course = CourseFactory(page_languages=["en", "fr"], should_publish=True) # Create draft and published course runs for this course # We want to test 4 situations: # - a draft course run # - a course run published in the current language # - a course run published in another language # - a course run published in the current language that was then unpublished course_runs = CourseRunFactory.create_batch( 3, page_parent=course.extended_object, page_languages=["en"]) self.assertTrue(course_runs[0].extended_object.publish("en")) self.assertTrue(course_runs[1].extended_object.publish("en")) self.assertTrue(course_runs[1].extended_object.unpublish("en")) course_run_fr = CourseRunFactory( page_parent=course.extended_object, page_languages=["fr"], should_publish=True, ) # Create a child course with draft and published course runs (what results from # snapshotting a course) child_course = CourseFactory( page_languages=["en", "fr"], page_parent=course.extended_object, should_publish=True, ) child_course_runs = CourseRunFactory.create_batch( 3, page_parent=child_course.extended_object, page_languages=["en"]) self.assertTrue(child_course_runs[0].extended_object.publish("en")) self.assertTrue(child_course_runs[1].extended_object.publish("en")) self.assertTrue(child_course_runs[1].extended_object.unpublish("en")) child_course_run_fr = CourseRunFactory( page_parent=child_course.extended_object, page_languages=["fr"], should_publish=True, ) # Create another course, not related to the first one, with draft and published course runs other_course = CourseFactory(page_languages=["en", "fr"], should_publish=True) other_course_runs = CourseRunFactory.create_batch( 3, page_parent=other_course.extended_object, page_languages=["en"]) self.assertTrue(other_course_runs[0].extended_object.publish("en")) self.assertTrue(other_course_runs[1].extended_object.publish("en")) self.assertTrue(other_course_runs[1].extended_object.unpublish("en")) CourseRunFactory( page_parent=other_course.extended_object, page_languages=["fr"], should_publish=True, ) # Check that the draft course retrieves all its descendant course runs # 3 draft course runs and 2 published course runs per course self.assertEqual(CourseRun.objects.count(), 3 * (4 + 3)) with self.assertNumQueries(2): self.assertEqual( list(course.get_course_runs()), course_runs + [course_run_fr] + child_course_runs + [child_course_run_fr], ) with self.assertNumQueries(1): self.assertEqual( list(course.get_course_runs_for_language(language="en")), course_runs + child_course_runs, ) # Check that the published course retrieves only the published descendant course runs course_runs[0].refresh_from_db() child_course_runs[0].refresh_from_db() public_course = course.public_extension with self.assertNumQueries(3): result = list(public_course.get_course_runs()) self.assertEqual( result, [ course_runs[0].public_extension, course_run_fr.public_extension, child_course_runs[0].public_extension, child_course_run_fr.public_extension, ], ) with self.assertNumQueries(1): result = list( public_course.get_course_runs_for_language(language="en")) self.assertEqual( result, [ course_runs[0].public_extension, child_course_runs[0].public_extension ], )
def test_indexers_courses_get_es_documents_from_models(self, _mock_picture): """ Happy path: the data is retrieved from the models properly formatted """ # Create a course with a page in both english and french published_categories = [ CategoryFactory( # L-0001 fill_icon=True, page_title={"en": "Title L-0001", "fr": "Titre L-0001"}, should_publish=True, ), CategoryFactory( # L-0002 fill_icon=True, page_title={"en": "Title L-0002", "fr": "Titre L-0002"}, should_publish=True, ), ] draft_category = CategoryFactory(fill_icon=True) # L-0003 main_organization = OrganizationFactory( # L-0004 page_title={ "en": "english main organization title", "fr": "titre organisation principale français", }, should_publish=True, ) other_draft_organization = OrganizationFactory( # L-0005 page_title={ "en": "english other organization title", "fr": "titre autre organisation français", } ) other_published_organization = OrganizationFactory( # L-0006 page_title={ "en": "english other organization title", "fr": "titre autre organisation français", }, should_publish=True, ) person1 = PersonFactory( page_title={"en": "Eugène Delacroix", "fr": "Eugène Delacroix"}, should_publish=True, ) person2 = PersonFactory( page_title={"en": "Comte de Saint-Germain", "fr": "Earl of Saint-Germain"}, should_publish=True, ) person_draft = PersonFactory( page_title={"en": "Jules de Polignac", "fr": "Jules de Polignac"} ) course = CourseFactory( duration=[3, WEEK], effort=[2, HOUR, WEEK], fill_categories=published_categories + [draft_category], fill_cover=True, fill_icons=published_categories + [draft_category], fill_organizations=[ main_organization, other_draft_organization, other_published_organization, ], fill_team=[person1, person_draft, person2], page_title={ "en": "an english course title", "fr": "un titre cours français", }, ) CourseRunFactory.create_batch(2, direct_course=course) course.extended_object.publish("en") course.extended_object.publish("fr") course.refresh_from_db() # Add a description in several languages placeholder = course.public_extension.extended_object.placeholders.get( slot="course_description" ) plugin_params = {"placeholder": placeholder, "plugin_type": "CKEditorPlugin"} add_plugin(body="english description line 1.", language="en", **plugin_params) add_plugin(body="english description line 2.", language="en", **plugin_params) add_plugin(body="a propos français ligne 1.", language="fr", **plugin_params) add_plugin(body="a propos français ligne 2.", language="fr", **plugin_params) # The results were properly formatted and passed to the consumer expected_course = { "_id": str(course.public_extension.extended_object_id), "_index": "some_index", "_op_type": "some_action", "_type": "course", "absolute_url": { "en": "/en/an-english-course-title/", "fr": "/fr/un-titre-cours-francais/", }, "categories": ["L-0001", "L-0002"], "categories_names": { "en": ["Title L-0001", "Title L-0002"], "fr": ["Titre L-0001", "Titre L-0002"], }, "complete": { "en": [ "an english course title", "english course title", "course title", "title", ], "fr": [ "un titre cours français", "titre cours français", "cours français", "français", ], }, "course_runs": [ { "start": course_run.public_course_run.start, "end": course_run.public_course_run.end, "enrollment_start": course_run.public_course_run.enrollment_start, "enrollment_end": course_run.public_course_run.enrollment_end, "languages": course_run.public_course_run.languages, } for course_run in course.get_course_runs().order_by("-end") ], "cover_image": { "en": {"info": "picture info"}, "fr": {"info": "picture info"}, }, "description": { "en": "english description line 1. english description line 2.", "fr": "a propos français ligne 1. a propos français ligne 2.", }, "duration": {"en": "3 weeks", "fr": "3 semaines"}, "effort": {"en": "2 hours/week", "fr": "2 heures/semaine"}, "icon": { "en": { "color": published_categories[0].color, "info": "picture info", "title": "Title L-0001", }, "fr": { "color": published_categories[0].color, "info": "picture info", "title": "Titre L-0001", }, }, "is_new": False, "is_listed": True, "organization_highlighted": { "en": "english main organization title", "fr": "titre organisation principale français", }, "organizations": ["L-0004", "L-0006"], "organizations_names": { "en": [ "english main organization title", "english other organization title", ], "fr": [ "titre organisation principale français", "titre autre organisation français", ], }, "persons": [ str(person1.public_extension.extended_object_id), str(person2.public_extension.extended_object_id), ], "persons_names": { "en": ["Eugène Delacroix", "Comte de Saint-Germain"], "fr": ["Eugène Delacroix", "Earl of Saint-Germain"], }, "title": {"fr": "un titre cours français", "en": "an english course title"}, } indexed_courses = list( CoursesIndexer.get_es_documents(index="some_index", action="some_action") ) self.assertEqual(len(indexed_courses), 1) self.assertEqual(indexed_courses[0], expected_course)
def test_templates_course_detail_cms_published_content(self, _): """ Validate that the important elements are displayed on a published course page """ subjects = SubjectFactory.create_batch(4) organizations = OrganizationFactory.create_batch(4) course = CourseFactory( organization_main=organizations[0], title="Very interesting course", with_organizations=organizations, with_subjects=subjects, ) page = course.extended_object CourseRunFactory.create_batch(2, course=course) # Publish only 2 out of 4 subjects and 2 out of 4 organizations subjects[0].extended_object.publish("en") subjects[1].extended_object.publish("en") organizations[0].extended_object.publish("en") organizations[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. subjects[2].extended_object.publish("en") subjects[2].extended_object.unpublish("en") organizations[2].extended_object.publish("en") organizations[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) # Publish and ensure content is correct page.publish("en") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "<title>Very interesting course en</title>", html=True) self.assertContains( response, '<h1 class="course-detail__title">Very interesting course en</h1>', html=True, ) # Only published subjects should be present on the page for subject in subjects[:2]: self.assertContains( response, '<a class="course-detail__content__subjects__item" href="{:s}">{:s}</a>' .format( subject.extended_object.get_absolute_url(), subject.extended_object.get_title(), ), html=True, ) for subject in subjects[-2:]: self.assertNotContains(response, subject.extended_object.get_title()) # organization 1 is marked as main organization self.assertContains( response, '<li class="{element:s} {element:s}--main">{title:s}</li>'.format( element="course-detail__content__organizations__item", title=organizations[0].extended_object.get_title(), ), html=True, ) # organization 2 is the only "common" org in listing self.assertContains( response, '<li class="course-detail__content__organizations__item">{:s}</li>' .format(organizations[1].extended_object.get_title()), html=True, ) # Draft organization should not be in response content for organization in organizations[-2:]: self.assertNotContains(response, organization.extended_object.get_title(), html=True) # Course runs should be in the page self.assertContains(response, "Enroll now", count=2)
def test_templates_course_detail_cms_draft_content(self, _): """ A staff user should see a draft course including its draft elements with an annotation """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") subjects = SubjectFactory.create_batch(4) organizations = OrganizationFactory.create_batch(4) course = CourseFactory( organization_main=organizations[0], title="Very interesting course", with_organizations=organizations, with_subjects=subjects, ) page = course.extended_object CourseRunFactory.create_batch(2, course=course) # Publish only 2 out of 4 subjects and 2 out of 4 organizations subjects[0].extended_object.publish("en") subjects[1].extended_object.publish("en") organizations[0].extended_object.publish("en") organizations[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. subjects[2].extended_object.publish("en") subjects[2].extended_object.unpublish("en") organizations[2].extended_object.publish("en") organizations[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.assertEqual(response.status_code, 200) self.assertContains(response, "<title>Very interesting course en</title>", html=True) self.assertContains( response, '<h1 class="course-detail__title">Very interesting course en</h1>', html=True, ) # organization 1 is marked as main and not duplicated self.assertContains( response, '<li class="{element:s} {element:s}--main">{title:s}</li>'.format( element="course-detail__content__organizations__item", title=organizations[0].extended_object.get_title(), ), html=True, ) self.assertNotContains( response, ('<li class="course-detail__content__organizations__item">{:s}</li>' ).format(organizations[0].extended_object.get_title()), html=True, ) # organization 2 is not marked as a draft since it has been published self.assertContains( response, '<li class="course-detail__content__organizations__item">{:s}</li>' .format(organizations[1].extended_object.get_title()), html=True, ) # Draft organizations should be present on the page with an annotation for styling for organization in organizations[:2]: self.assertNotContains( response, '<li class="{element:s} {element:s}--draft">{title:s}</li>'. format( element="course-detail__content__organizations__item", title=organization.extended_object.get_title(), ), html=True, ) # The published subjects should be present on the page for subject in subjects[:2]: self.assertContains( response, '<a class="course-detail__content__subjects__item" href="{:s}">{:s}</a>' .format( subject.extended_object.get_absolute_url(), subject.extended_object.get_title(), ), html=True, ) # Draft subjects should also be present on the page with an annotation for styling for subject in subjects[-2:]: self.assertContains( response, '<a class="{element:s} {element:s}--draft" href="{url:s}">{title:s}</a>' .format( url=subject.extended_object.get_absolute_url(), element="course-detail__content__subjects__item", title=subject.extended_object.get_title(), ), html=True, ) # Course runs should be in the page self.assertContains(response, "Enroll now", count=2)
def create_demo_site(): """ Create a simple site tree structure for developpers to work in realistic environment. We create multilingual pages, add organizations under the related page and add plugins to each page. """ site = Site.objects.get(id=1) # Create pages as described in PAGES_INFOS pages_created = recursive_page_creation(site, PAGE_INFOS) # Create some licences licences = LicenceFactory.create_batch(NB_LICENCES) # Create organizations under the `Organizations` page organizations = OrganizationFactory.create_batch( NB_ORGANIZATIONS, languages=[l[0] for l in settings.LANGUAGES], parent=pages_created["organizations"], fill_banner=True, fill_description=True, fill_logo=True, should_publish=True, in_navigation=True, ) # Create subjects under the `Subjects` page subjects = SubjectFactory.create_batch( NB_SUBJECTS, languages=[l[0] for l in settings.LANGUAGES], parent=pages_created["subjects"], fill_banner=True, fill_description=True, fill_logo=True, should_publish=True, in_navigation=True, ) # Django parler require a language to be manually set when working out of # request/response flow and PersonTitle use 'parler' translation.activate(settings.LANGUAGE_CODE) # Create persons under the `persons` page persons = PersonFactory.create_batch( NB_PERSONS, languages=[l[0] for l in settings.LANGUAGES], parent=pages_created["persons"], fill_portrait=True, fill_resume=True, should_publish=True, in_navigation=True, ) # Create courses under the `Course` page with subjects and organizations # relations for _ in range(NB_COURSES): course_organizations = random.sample( organizations, NB_COURSES_ORGANIZATION_RELATIONS) video_sample = random.choice(VIDEO_SAMPLE_LINKS) course = CourseFactory( languages=[l[0] for l in settings.LANGUAGES], parent=pages_created["courses"], organization_main=random.choice(course_organizations), fill_licences=[ ("course_license_content", random.choice(licences)), ("course_license_participation", random.choice(licences)), ], fill_team=random.sample(persons, NB_COURSES_PERSONS_PLUGINS), fill_teaser=video_sample, fill_cover=video_sample.image, fill_texts=[ "course_syllabus", "course_format", "course_prerequisites", "course_plan", # "course_license_content", # "course_license_participation", ], with_organizations=course_organizations, with_subjects=random.sample(subjects, NB_COURSES_SUBJECT_RELATIONS), should_publish=True, in_navigation=True, ) # Add a random number of course runs to the course nb_course_runs = get_number_of_course_runs() if nb_course_runs > 0: CourseRunFactory.create_batch(nb_course_runs, course=course)
def test_templates_course_detail_cms_published_content(self): """ Validate that the important elements are displayed on a published course page """ categories = CategoryFactory.create_batch(4) icons = CategoryFactory.create_batch(4, fill_icon=True) organizations = OrganizationFactory.create_batch(4) course = CourseFactory( page_title="Very interesting course", fill_organizations=organizations, fill_categories=categories, fill_icons=icons, ) page = course.extended_object # Create 2 ongoing open course runs now = timezone.now() course_run1, _course_run2 = CourseRunFactory.create_batch( 2, page_parent=course.extended_object, start=now - timedelta(hours=1), end=now + timedelta(hours=2), enrollment_end=now + timedelta(hours=1), languages=["en", "fr"], ) self.assertFalse(course_run1.extended_object.publish("en")) # Publish only 2 out of 4 categories, icons and organizations categories[0].extended_object.publish("en") categories[1].extended_object.publish("en") icons[0].extended_object.publish("en") icons[1].extended_object.publish("en") organizations[0].extended_object.publish("en") organizations[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. categories[2].extended_object.publish("en") categories[2].extended_object.unpublish("en") icons[2].extended_object.publish("en") icons[2].extended_object.unpublish("en") organizations[2].extended_object.publish("en") organizations[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") # Now we can publish children course runs: publish only 1 of the 2 course_run1.extended_object.parent_page.refresh_from_db() self.assertTrue(course_run1.extended_object.publish("en")) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains( response, "<title>Very interesting course</title>", html=True ) self.assertContains( response, '<h1 class="subheader__title">Very interesting course</h1>', html=True, ) # Only published categories should be present on the page for category in categories[:2]: self.assertContains( response, ( '<a class="category-badge" href="{:s}">' '<span class="category-badge__title">{:s}</span></a>' ).format( category.extended_object.get_absolute_url(), category.extended_object.get_title(), ), html=True, ) for category in categories[-2:]: self.assertNotContains(response, category.extended_object.get_title()) # Only published icons should be present on the page pattern = ( r'<a.*class="category-badge".*href="{link:s}".*>' r'<img src="/media/filer_public_thumbnails/filer_public/.*icon\.jpg.*alt="{title:s}">' r'<span class="category-badge__title">' r".*{title:s}.*</span>" ) for icon in icons[:2]: self.assertIsNotNone( re.search( pattern.format( link=icon.extended_object.get_absolute_url(), title=icon.extended_object.get_title(), ), str(response.content), ) ) for icon in icons[-2:]: self.assertNotContains(response, icon.extended_object.get_title()) # Public organizations should be in response content for organization in organizations[:2]: self.assertContains( response, '<div class="organization-glimpse__title">{title:s}</div>'.format( title=organization.extended_object.get_title() ), html=True, ) # Draft organizations should not be in response content for organization in organizations[-2:]: self.assertNotContains( response, organization.extended_object.get_title(), html=True ) # Only the published course run should be in response content self.assertContains(response, "<dd>English and french</dd>", html=True, count=1)
def test_templates_course_detail_cms_draft_content(self): """ A staff user should see a draft course including its draft elements with an annotation """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") categories = CategoryFactory.create_batch(4) organizations = OrganizationFactory.create_batch(4) course = CourseFactory( page_title="Very interesting course", fill_organizations=organizations, fill_categories=categories, ) page = course.extended_object now = timezone.now() course_run1, _course_run2 = CourseRunFactory.create_batch( 2, page_parent=course.extended_object, start=now - timedelta(hours=1), end=now + timedelta(hours=2), enrollment_end=now + timedelta(hours=1), languages=["en", "fr"], ) # Publish only 1 of the course runs course_run1.extended_object.publish("en") # Publish only 2 out of 4 categories and 2 out of 4 organizations categories[0].extended_object.publish("en") categories[1].extended_object.publish("en") organizations[0].extended_object.publish("en") organizations[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. categories[2].extended_object.publish("en") categories[2].extended_object.unpublish("en") organizations[2].extended_object.publish("en") organizations[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.assertEqual(response.status_code, 200) self.assertContains( response, "<title>Very interesting course</title>", html=True ) self.assertContains( response, '<h1 class="subheader__title">Very interesting course</h1>', html=True, ) # Draft and public organizations should all be present on the page for organization in organizations: self.assertContains( response, '<div class="organization-glimpse__title">{title:s}</div>'.format( title=organization.extended_object.get_title() ), html=True, ) # Draft organizations should be annotated for styling self.assertContains(response, "organization-glimpse--draft", count=2) # The published categories should be present on the page for category in categories[:2]: self.assertContains( response, ( '<a class="category-badge" href="{:s}">' '<span class="category-badge__title">{:s}</span></a>' ).format( category.extended_object.get_absolute_url(), category.extended_object.get_title(), ), html=True, ) # Draft categories should also be present on the page with an annotation for styling for category in categories[-2:]: self.assertContains( response, ( '<a class="{element:s} {element:s}--draft" href="{url:s}">' '<span class="category-badge__title">{title:s}</span></a>' ).format( url=category.extended_object.get_absolute_url(), element="category-badge", title=category.extended_object.get_title(), ), html=True, ) # The draft and the published course runs should both be in the page self.assertContains(response, "<dd>English and french</dd>", html=True, count=2)
def test_templates_course_detail_cms_published_content(self): """ Validate that the important elements are displayed on a published course page """ categories = CategoryFactory.create_batch(4) organizations = OrganizationFactory.create_batch(4) course = CourseFactory( page_title="Very interesting course", fill_organizations=organizations, fill_categories=categories, ) page = course.extended_object course_run1, _course_run2 = CourseRunFactory.create_batch( 2, page_parent=course.extended_object, languages=["en", "fr"] ) self.assertFalse(course_run1.extended_object.publish("en")) # Publish only 2 out of 4 categories and 2 out of 4 organizations categories[0].extended_object.publish("en") categories[1].extended_object.publish("en") organizations[0].extended_object.publish("en") organizations[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. categories[2].extended_object.publish("en") categories[2].extended_object.unpublish("en") organizations[2].extended_object.publish("en") organizations[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") # Now we can publish children course runs: publish only 1 of the 2 course_run1.extended_object.parent_page.refresh_from_db() self.assertTrue(course_run1.extended_object.publish("en")) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains( response, "<title>Very interesting course</title>", html=True ) self.assertContains( response, '<h1 class="course-detail__content__title">Very interesting course</h1>', html=True, ) # Only published categories should be present on the page for category in categories[:2]: self.assertContains( response, '<a class="category-plugin-tag" href="{:s}">{:s}</a>'.format( category.extended_object.get_absolute_url(), category.extended_object.get_title(), ), html=True, ) for category in categories[-2:]: self.assertNotContains(response, category.extended_object.get_title()) # Public organizations should be in response content for organization in organizations[:2]: self.assertContains( response, '<div class="organization-plugin__title">{title:s}</div>'.format( title=organization.extended_object.get_title() ), html=True, ) # Draft organizations should not be in response content for organization in organizations[-2:]: self.assertNotContains( response, organization.extended_object.get_title(), html=True ) # Only the published course run should be in response content self.assertContains(response, "<dd>English and french</dd>", html=True, count=1)
def test_templates_course_detail_cms_draft_content(self, _): """ A staff user should see a draft course including its draft elements with an annotation """ user = UserFactory(is_staff=True, is_superuser=True) self.client.login(username=user.username, password="******") subjects = SubjectFactory.create_batch(4) organizations = OrganizationFactory.create_batch(4) course = CourseFactory( page_title="Very interesting course", fill_organizations=organizations, fill_subjects=subjects, ) page = course.extended_object course_run1, _course_run2 = CourseRunFactory.create_batch( 2, page_parent=course.extended_object, languages=["en", "fr"] ) # Publish only 1 of the course runs course_run1.extended_object.publish("en") # Publish only 2 out of 4 subjects and 2 out of 4 organizations subjects[0].extended_object.publish("en") subjects[1].extended_object.publish("en") organizations[0].extended_object.publish("en") organizations[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. subjects[2].extended_object.publish("en") subjects[2].extended_object.unpublish("en") organizations[2].extended_object.publish("en") organizations[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.assertEqual(response.status_code, 200) self.assertContains( response, "<title>Very interesting course</title>", html=True ) self.assertContains( response, '<h1 class="course-detail__content__title">Very interesting course</h1>', html=True, ) # Draft and public organizations should all be present on the page for organization in organizations: self.assertContains( response, '<div class="organization-plugin__title">{title:s}</div>'.format( title=organization.extended_object.get_title() ), html=True, ) # Draft organizations should be annotated for styling self.assertContains(response, "organization-plugin-container--draft", count=2) # The published subjects should be present on the page for subject in subjects[:2]: self.assertContains( response, '<a class="subject-plugin-tag" href="{:s}">{:s}</a>'.format( subject.extended_object.get_absolute_url(), subject.extended_object.get_title(), ), html=True, ) # Draft subjects should also be present on the page with an annotation for styling for subject in subjects[-2:]: self.assertContains( response, '<a class="{element:s} {element:s}--draft" href="{url:s}">{title:s}</a>'.format( url=subject.extended_object.get_absolute_url(), element="subject-plugin-tag", title=subject.extended_object.get_title(), ), html=True, ) # The draft and the published course runs should both be in the page self.assertContains(response, "Enroll now", count=2) self.assertContains(response, "<dd>English, French</dd>", html=True, count=2)