Ejemplo n.º 1
0
    def load_version(self, sha=None, public=None):
        """Using git, load a specific version of the content. if ``sha`` is ``None``,
        the draft/public version is used (if ``public`` is ``True``).

        .. attention::

            for practical reason, the returned object is filled with information from DB.

        :param sha: version
        :param public: if set with the right object, return the public version
        :type public: PublishedContent
        :raise BadObject: if sha is not None and related version could not be found
        :raise IOError: if the path to the repository is wrong
        :raise NotAPublicVersion: if the sha does not correspond to a public version
        :return: the versioned content
        :rtype: zds.tutorialv2.models.models_versioned.VersionedContent
        """

        # load the good manifest.json
        if sha is None:
            if not public:
                sha = self.sha_draft
            else:
                sha = self.sha_public
        max_title_length = PublishableContent._meta.get_field('title').max_length
        if public and isinstance(public, PublishedContent):  # use the public (altered and not versioned) repository
            path = public.get_prod_path()
            slug = public.content_public_slug

            if not os.path.isdir(path):
                raise IOError(path)

            if sha != public.sha_public:
                raise NotAPublicVersion

            manifest = open(os.path.join(path, 'manifest.json'), 'r')
            json = json_reader.loads(manifest.read())
            versioned = get_content_from_json(json, public.sha_public,
                                              slug, public=True, max_title_len=max_title_length)

        else:  # draft version, use the repository (slower, but allows manipulation)
            path = self.get_repo_path()
            slug = self.slug

            if not os.path.isdir(path):
                raise IOError(path)

            repo = Repo(path)
            data = get_blob(repo.commit(sha).tree, 'manifest.json')
            try:
                json = json_reader.loads(data)
            except ValueError:
                raise BadManifestError(
                    _(u'Une erreur est survenue lors de la lecture du manifest.json, est-ce du JSON ?'))

            versioned = get_content_from_json(json, sha, self.slug, max_title_len=max_title_length)

        self.insert_data_in_versioned(versioned)
        return versioned
Ejemplo n.º 2
0
    def extract_content_from_zip(zip_archive):
        """Check if the data in the zip file are coherent

        :param zip_archive: the zip archive to analyze
        :type zip_archive: zipfile.ZipFile
        :raise BadArchiveError: if something is wrong in the archive
        :return: the content in the archive
        :rtype: VersionedContent
        """

        try:
            manifest = str(zip_archive.read("manifest.json"), "utf-8")
        except KeyError:
            raise BadArchiveError(
                _("Cette archive ne contient pas de fichier manifest.json."))
        except UnicodeDecodeError:
            raise BadArchiveError(
                _("L'encodage du manifest.json n'est pas de l'UTF-8."))

        # is the manifest ok ?
        try:
            json_ = json_handler.loads(manifest)
        except ValueError:
            raise BadArchiveError(
                _("Une erreur est survenue durant la lecture du manifest, "
                  "vérifiez qu'il s'agit de JSON correctement formaté."))
        try:
            versioned = get_content_from_json(
                json_,
                None,
                "",
                max_title_len=PublishableContent._meta.get_field(
                    "title").max_length)
        except BadManifestError as e:
            raise BadArchiveError(e.message)
        except InvalidSlugError as e:
            e1 = _('Le slug "{}" est invalide').format(e)
            e2 = ""
            if e.had_source:
                e2 = _(' (slug généré à partir de "{}")').format(e.source)
            raise BadArchiveError(_("{}{} !").format(e1, e2))
        except Exception as e:
            raise BadArchiveError(
                _("Une erreur est survenue lors de la lecture de l'archive : {}."
                  ).format(e))

        # is there everything in the archive ?
        for f in UpdateContentWithArchive.walk_content(versioned):
            try:
                zip_archive.getinfo(f)
            except KeyError:
                raise BadArchiveError(
                    _("Le fichier '{}' n'existe pas dans l'archive.").format(
                        f))

        return versioned
Ejemplo n.º 3
0
def reindex_content(published_content):
    """Index the new published version.

    .. attention::
        Note that lots of IO, memory and CPU will be used when you use this function.
        Only loop on it if you know what you are doing !

    This function looks for the archive generated in any publication and containing the content in a version that
    correspond to the public version, and then use it to create ``SearchIndex*`` objects by reading the archive.

    IO complexity is ``2 + 2 * number of containers + number of extracts`` (through a ZIP archive).

    Database query complexity is

    * on deletion : ``1 + number of containers + number of extracts`` ;
    * on addition : ``1 + number of containers + number of extracts``.

    :param published_content: Database representation of the public version of the content
    :type published_content: PublishedContent
    """

    # We just delete all index that correspond to the content
    SearchIndexContent.objects.filter(
        publishable_content__pk=published_content.content_pk).delete()

    # Load the manifest:
    if not published_content.have_zip():
        raise Exception(
            'Unable to index content due to the absence of ZIP file')

    zip_path = os.path.join(published_content.get_extra_contents_directory(),
                            published_content.content_public_slug + '.zip')

    archive = zipfile.ZipFile(zip_path)
    try:
        manifest = get_file_content_in_zip(archive, 'manifest.json')
    except KeyError:
        raise Exception(
            'Unable to index content due to the absence of manifest in ZIP file'
        )

    json_ = json_reader.loads(manifest)
    try:
        versioned = get_content_from_json(json_, None, '')
    except BadManifestError as e:
        raise Exception(e.message)
    except Exception:
        raise Exception(
            'Unable to index content due to an error while opening manifest')

    published_content.content.insert_data_in_versioned(versioned)

    # Index the content:
    search_index_content = SearchIndexContent()
    search_index_content.publishable_content = published_content.content
    search_index_content.pubdate = published_content.publication_date or datetime.now(
    )
    search_index_content.update_date = published_content.content.update_date or datetime.now(
    )

    if published_content.content.licence:
        search_index_content.licence = published_content.content.licence.title
    else:
        search_index_content.licence = ''

    if published_content.content.image:
        search_index_content.url_image = published_content.content.image.get_absolute_url(
        )
    else:
        search_index_content.url_image = ''

    search_index_content.title = versioned.title
    search_index_content.description = versioned.description

    search_index_content.save()

    # Subcategory
    for subcategory in published_content.content.subcategory.all():
        search_index_tag = SearchIndexTag()
        search_index_tag.title = subcategory.title
        search_index_tag.save()

        search_index_content.tags.add(search_index_tag)

    # Authors
    for author in published_content.content.authors.all():
        search_index_authors = SearchIndexAuthors()
        search_index_authors.username = author.username
        search_index_authors.save()

        search_index_content.authors.add(search_index_authors)

    search_index_content.url_to_redirect = published_content.get_absolute_url_online(
    )

    # Save introduction and conclusion:
    all_html = u''

    if versioned.introduction:
        try:
            introduction_html = emarkdown(
                get_file_content_in_zip(archive, versioned.introduction))
            all_html = introduction_html
            search_index_content.introduction = filter_text(introduction_html)
        except KeyError:
            pass

    if versioned.conclusion:
        try:
            conclusion_html = emarkdown(
                get_file_content_in_zip(archive, versioned.conclusion))
            all_html = u'{}{}'.format(all_html, conclusion_html)
            search_index_content.conclusion = filter_text(conclusion_html)
        except KeyError:
            pass

    if all_html != u'':
        search_index_content.keywords = filter_keyword(all_html)

    search_index_content.type = published_content.content_type.lower()
    search_index_content.save()

    # Also index children
    index_content(versioned, search_index_content, archive)

    # no need to index the next time
    published_content.content.must_reindex = False
    published_content.content.save()
Ejemplo n.º 4
0
    def load_version(self, sha=None, public=None):
        """Using git, load a specific version of the content. if ``sha`` is ``None``,
        the draft/public version is used (if ``public`` is ``True``).

        .. attention::

            for practical reason, the returned object is filled with information from DB.

        :param sha: version
        :param public: if set with the right object, return the public version
        :type public: PublishedContent
        :raise BadObject: if sha is not None and related version could not be found
        :raise OSError: if the path to the repository is wrong
        :raise NotAPublicVersion: if the sha does not correspond to a public version
        :return: the versioned content
        :rtype: zds.tutorialv2.models.versioned.VersionedContent
        """

        # load the good manifest.json
        if sha is None:
            if not public:
                sha = self.sha_draft
            else:
                sha = self.sha_public
        max_title_length = PublishableContent._meta.get_field('title').max_length
        if public and isinstance(public, PublishedContent):  # use the public (altered and not versioned) repository
            path = public.get_prod_path()
            slug = public.content_public_slug

            if not os.path.isdir(path):
                raise OSError(path)

            if sha != public.sha_public:
                raise NotAPublicVersion

            with open(os.path.join(path, 'manifest.json'), 'r', encoding='utf-8') as manifest:
                json = json_handler.loads(manifest.read())
                versioned = get_content_from_json(
                    json,
                    public.sha_public,
                    slug,
                    public=True,
                    max_title_len=max_title_length,
                    hint_licence=self.licence,
                )

        else:  # draft version, use the repository (slower, but allows manipulation)
            path = self.get_repo_path()

            if not os.path.isdir(path):
                raise OSError(path)

            repo = Repo(path)
            data = get_blob(repo.commit(sha).tree, 'manifest.json')
            try:
                json = json_handler.loads(data)
            except ValueError:
                raise BadManifestError(
                    _('Une erreur est survenue lors de la lecture du manifest.json, est-ce du JSON ?'))

            versioned = get_content_from_json(json, sha, self.slug, max_title_len=max_title_length)

        self.insert_data_in_versioned(versioned)
        return versioned