Ejemplo n.º 1
0
 def test_helpers_simplepicture_get_picture_info_no_picture(self):
     """
     The `get_picture_info` method should not fail and raise an error if it encounters
     a picture without an image.
     """
     simple_picture = PictureFactory(picture=None)
     info = get_picture_info(simple_picture, "my-preset")
     self.assertEqual(info, None)
Ejemplo n.º 2
0
    def get_es_document_for_organization(cls,
                                         organization,
                                         index=None,
                                         action="index"):
        """Build an Elasticsearch document from the category instance."""
        index = index or cls.index_name

        # Get published titles
        titles = {
            t.language: t.title
            for t in Title.objects.filter(page=organization.extended_object,
                                          published=True)
        }

        # Prepare logo images
        logo_images = {}
        for logo in Picture.objects.filter(
                cmsplugin_ptr__placeholder__page=organization.extended_object,
                cmsplugin_ptr__placeholder__slot="logo",
        ):
            language = logo.cmsplugin_ptr.language
            with translation.override(language):
                logo_images[language] = get_picture_info(logo, "logo")

        # Get description texts
        description = defaultdict(list)
        for simple_text in SimpleText.objects.filter(
                cmsplugin_ptr__placeholder__page=organization.extended_object,
                cmsplugin_ptr__placeholder__slot="description",
        ):
            description[simple_text.cmsplugin_ptr.language].append(
                simple_text.body)

        return {
            "_id": organization.get_es_id(),
            "_index": index,
            "_op_type": action,
            "_type": cls.document_type,
            "absolute_url": {
                language:
                organization.extended_object.get_absolute_url(language)
                for language in titles.keys()
            },
            "complete": {
                language: slice_string_for_completion(title)
                for language, title in titles.items()
            },
            "logo": logo_images,
            "description":
            {language: " ".join(st)
             for language, st in description.items()},
            "title": titles,
        }
Ejemplo n.º 3
0
 def get_logo_images(cls, organization):
     """
     Prepare logo images for an organization.
     """
     logo_images = {}
     for logo in Picture.objects.filter(
             cmsplugin_ptr__placeholder__page=organization.extended_object,
             cmsplugin_ptr__placeholder__slot="logo",
     ):
         language = logo.cmsplugin_ptr.language
         with translation.override(language):
             logo_images[language] = get_picture_info(logo, "logo")
     return logo_images
Ejemplo n.º 4
0
    def get_es_document_for_person(cls, person, index=None, action="index"):
        """Build an Elasticsearch document from the person instance."""
        index = index or cls.index_name

        # Get published titles
        titles = {
            t.language: t.title
            for t in Title.objects.filter(page=person.extended_object,
                                          published=True)
        }

        # Prepare portrait images
        portrait_images = {}
        for portrait in Picture.objects.filter(
                cmsplugin_ptr__placeholder__page=person.extended_object,
                cmsplugin_ptr__placeholder__slot="portrait",
        ):
            language = portrait.cmsplugin_ptr.language
            with translation.override(language):
                portrait_images[language] = get_picture_info(
                    portrait, "portrait")

        # Get bio texts
        bio = defaultdict(list)
        for simple_text in SimpleText.objects.filter(
                cmsplugin_ptr__placeholder__page=person.extended_object,
                cmsplugin_ptr__placeholder__slot="bio",
        ):
            bio[simple_text.cmsplugin_ptr.language].append(simple_text.body)

        return {
            "_id": str(person.extended_object_id),
            "_index": index,
            "_op_type": action,
            "_type": cls.document_type,
            "absolute_url": {
                language: person.extended_object.get_absolute_url(language)
                for language in titles.keys()
            },
            "bio": {l: " ".join(st)
                    for l, st in bio.items()},
            "complete": {
                language: slice_string_for_completion(title)
                for language, title in titles.items()
            },
            "portrait": portrait_images,
            "title": titles,
        }
Ejemplo n.º 5
0
    def test_helpers_simplepicture_get_picture_info_minimal(
            self, mock_thumbnail):
        """srcset and sizes are optional attributes in settings."""
        simple_picture = PictureFactory()
        info = get_picture_info(simple_picture, "my-preset")

        self.assertEqual(info, {
            "sizes": None,
            "src": "/dummy-url",
            "srcset": None
        })
        self.assertEqual(mock_thumbnail.call_count, 1)
        location = simple_picture.picture.subject_location
        self.assertEqual(
            mock_thumbnail.call_args_list,
            [mock.call({
                "size": (500, 500),
                "subject_location": location
            })],
        )
Ejemplo n.º 6
0
    def test_helpers_simplepicture_get_picture_info_success(
            self, mock_thumbnail, *_):
        """
        The `get_picture_info` method should compute and return thumbnails urls and other
        attributes.
        """
        simple_picture = PictureFactory()
        info = get_picture_info(simple_picture, "my-preset")

        self.assertEqual(
            info,
            {
                "sizes": "100vw",
                "src": "/dummy-url",
                "srcset": "/dummy-url 1000w, /dummy-url 2000w",
            },
        )
        self.assertEqual(mock_thumbnail.call_count, 3)
        location = simple_picture.picture.subject_location
        self.assertEqual(
            mock_thumbnail.call_args_list,
            [
                mock.call({
                    "size": (500, 500),
                    "crop": "smart",
                    "subject_location": location
                }),
                mock.call({
                    "crop": "smart",
                    "size": (1000, 1000),
                    "subject_location": location,
                }),
                mock.call({
                    "crop": "smart",
                    "size": (2000, 2000),
                    "subject_location": location,
                }),
            ],
        )
Ejemplo n.º 7
0
    def get_es_document_for_course(cls, course, index=None, action="index"):
        """
        Build an Elasticsearch document from the course instance.
        """
        index = index or cls.index_name

        # Prepare published titles
        titles = {
            t.language: t.title
            for t in Title.objects.filter(page=course.extended_object, published=True)
        }

        # Prepare cover images
        cover_images = {}
        for cover in Picture.objects.filter(
            cmsplugin_ptr__placeholder__page=course.extended_object,
            cmsplugin_ptr__placeholder__slot="course_cover",
        ):
            language = cover.cmsplugin_ptr.language
            with translation.override(language):
                picture_info = get_picture_info(cover, "cover")
                if picture_info:
                    cover_images[language] = picture_info

        # Prepare the related category icon
        icon_images = {}
        for plugin_model in CategoryPluginModel.objects.filter(
            cmsplugin_ptr__placeholder__page=course.extended_object_id,
            cmsplugin_ptr__placeholder__slot="course_icons",
            cmsplugin_ptr__position=0,
        ):
            language = plugin_model.language
            for icon in Picture.objects.filter(
                cmsplugin_ptr__language=language,
                cmsplugin_ptr__placeholder__page=plugin_model.page_id,
                cmsplugin_ptr__placeholder__slot="icon",
                cmsplugin_ptr__position=0,
            ):
                with translation.override(language):
                    picture_info = get_picture_info(icon, "icon") or {}
                    icon_images[language] = {
                        **picture_info,
                        "color": plugin_model.page.category.color,
                        "title": plugin_model.page.get_title(),
                    }

        # Prepare description texts
        descriptions = defaultdict(list)
        for simple_text in SimpleText.objects.filter(
            cmsplugin_ptr__placeholder__page=course.extended_object,
            cmsplugin_ptr__placeholder__slot="course_description",
        ):
            descriptions[simple_text.cmsplugin_ptr.language].append(simple_text.body)

        # Prepare localized duration texts
        duration = {}
        for language, _ in settings.LANGUAGES:
            with translation.override(language):
                duration[language] = course.get_duration_display()

        # Prepare localized effort texts
        effort = {}
        for language, _ in settings.LANGUAGES:
            with translation.override(language):
                effort[language] = course.get_effort_display()

        # Prepare categories, making sure we get title information for categories
        # in the same query
        category_pages = (
            course.get_root_to_leaf_category_pages()
            .select_related("node")
            .prefetch_related(
                Prefetch(
                    "title_set",
                    to_attr="published_titles",
                    queryset=Title.objects.filter(published=True),
                )
            )
            .only("node", "pk")
            .distinct()
        )

        # Prepare organizations, making sure we get title information for organizations
        # in the same query
        organizations = (
            course.get_organizations()
            .prefetch_related(
                Prefetch(
                    "extended_object__title_set",
                    to_attr="published_titles",
                    queryset=Title.objects.filter(published=True),
                )
            )
            .only("extended_object__node")
            .distinct()
        )
        organization_main = course.get_main_organization()
        organization_highlighted = (
            organizations.get(id=organization_main.id) if organization_main else None
        )

        # Prepare persons, making sure we get title information for persons
        # in the same query
        persons = (
            course.get_persons()
            .prefetch_related(
                Prefetch(
                    "extended_object__title_set",
                    to_attr="published_titles",
                    queryset=Title.objects.filter(published=True),
                )
            )
            .distinct()
        )

        # Prepare course runs
        # Ordering them by their `end` date is important to optimize sorting and other
        # computations that require looping on the course runs
        # Course runs with no start date or no start of enrollment date are ignored as
        # they are still to be scheduled.
        course_runs = [
            {
                "start": cr["start"],
                "end": cr["end"] or MAX_DATE,
                "enrollment_start": cr["enrollment_start"],
                "enrollment_end": cr["enrollment_end"] or cr["end"] or MAX_DATE,
                "languages": cr["languages"],
            }
            for cr in course.get_course_runs()
            .filter(start__isnull=False, enrollment_start__isnull=False)
            .order_by("-end")
            .values("start", "end", "enrollment_start", "enrollment_end", "languages")
        ]

        return {
            "_id": str(course.extended_object_id),
            "_index": index,
            "_op_type": action,
            "_type": cls.document_type,
            "absolute_url": {
                lang: course.extended_object.get_absolute_url(lang)
                for lang, _ in settings.LANGUAGES
            },
            "categories": [page.category.get_es_id() for page in category_pages],
            # Index the names of categories to surface them in full text searches
            "categories_names": reduce(
                lambda acc, title: {
                    **acc,
                    title.language: acc[title.language] + [title.title]
                    if acc.get(title.language)
                    else [title.title],
                },
                [title for page in category_pages for title in page.published_titles],
                {},
            ),
            "complete": {
                language: slice_string_for_completion(title)
                for language, title in titles.items()
            }
            if course.is_listed
            else None,
            "course_runs": course_runs,
            "cover_image": cover_images,
            "description": {
                language: " ".join(st) for language, st in descriptions.items()
            },
            "duration": duration,
            "effort": effort,
            "icon": icon_images,
            "is_new": len(course_runs) == 1,
            "is_listed": course.is_listed,
            # Pick the highlighted organization from the organizations QuerySet to benefit from
            # the prefetch of related title sets
            "organization_highlighted": {
                title.language: title.title
                for title in organization_highlighted.extended_object.published_titles
            }
            if organization_highlighted
            else None,
            "organizations": [
                organization.get_es_id() for organization in organizations
            ],
            # Index the names of organizations to surface them in full text searches
            "organizations_names": reduce(
                lambda acc, title: {
                    **acc,
                    title.language: acc[title.language] + [title.title]
                    if acc.get(title.language)
                    else [title.title],
                },
                [
                    title
                    for organization in organizations
                    for title in organization.extended_object.published_titles
                ],
                {},
            ),
            "persons": [
                str(person.public_extension.extended_object_id) for person in persons
            ],
            "persons_names": reduce(
                lambda acc, title: {
                    **acc,
                    title.language: acc[title.language] + [title.title]
                    if acc.get(title.language)
                    else [title.title],
                },
                [
                    title
                    for person in persons
                    for title in person.extended_object.published_titles
                ],
                {},
            ),
            "title": titles,
        }
Ejemplo n.º 8
0
    def get_es_document_for_category(cls, category, index=None, action="index"):
        """Build an Elasticsearch document from the category instance."""
        index = index or cls.index_name

        # Prepare published titles
        titles = {
            t.language: t.title
            for t in Title.objects.filter(page=category.extended_object, published=True)
        }

        # Prepare logo images
        logo_images = {}
        for logo in Picture.objects.filter(
            cmsplugin_ptr__placeholder__page=category.extended_object,
            cmsplugin_ptr__placeholder__slot="logo",
        ):
            language = logo.cmsplugin_ptr.language
            with translation.override(language):
                logo_images[language] = get_picture_info(logo, "logo")

        # Prepare icon images
        icon_images = {}
        for icon in Picture.objects.filter(
            cmsplugin_ptr__placeholder__page=category.extended_object,
            cmsplugin_ptr__placeholder__slot="icon",
        ):
            language = icon.cmsplugin_ptr.language
            with translation.override(language):
                icon_images[language] = get_picture_info(icon, "icon")

        # Prepare description texts
        description = defaultdict(list)
        for simple_text in SimpleText.objects.filter(
            cmsplugin_ptr__placeholder__page=category.extended_object,
            cmsplugin_ptr__placeholder__slot="description",
        ):
            description[simple_text.cmsplugin_ptr.language].append(simple_text.body)

        # Shorcut to the category's page node
        node = category.extended_object.node

        # Find the meta category the current category falls under
        try:
            kind = category.get_meta_category().extended_object.reverse_id
        except Category.DoesNotExist:
            # Meta categories do not have a meta category themselves
            kind = None

        return {
            "_id": cls.get_es_id(category.extended_object),
            "_index": index,
            "_op_type": action,
            "_type": cls.document_type,
            "absolute_url": {
                language: category.extended_object.get_absolute_url(language)
                for language in titles.keys()
            },
            "complete": {
                language: slice_string_for_completion(title)
                for language, title in titles.items()
            },
            "description": {l: " ".join(st) for l, st in description.items()},
            "icon": icon_images,
            "is_meta": bool(
                node.parent is None
                or node.parent.cms_pages.filter(category__isnull=True).exists()
            ),
            "kind": kind,
            "logo": logo_images,
            "nb_children": node.numchild,
            "path": node.path,
            "title": titles,
        }