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
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
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()
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