Les tutoriels v2 (ZEP12) (tutorialv2/)

Module situé dans zds/tutorialv2/.

Modèles (models/)

Modèles de la base de donnée (database.py)

class zds.tutorialv2.models.database.ContentReaction(*args, **kwargs)

A comment written by any user about a PublishableContent they just read.

exception DoesNotExist
exception MultipleObjectsReturned
get_absolute_url()

Find the url to the reaction

Returns:the url of the comment
Return type:str
class zds.tutorialv2.models.database.ContentRead(*args, **kwargs)

Small model which keeps track of the user viewing tutorials.

It remembers the PublishableContent they read and what was the last Note at that time.

exception DoesNotExist
exception MultipleObjectsReturned
save(force_insert=False, force_update=False, using=None, update_fields=None)

Save this model but check that if we have not a related note it is because the user is content author.

class zds.tutorialv2.models.database.FakeChapter(chapter, main_container, parent_id)

A simple class that is used by ES to index chapters, constructed from the containers.

In mapping, this class defines PublishedContent as its parent. Also, indexing is done by the parent.

Note that this class is only indexable, not updatable, since it does not maintain value of es_already_indexed

get_es_document_as_bulk_action(index, action='index')

Overridden to handle parenting between chapter and PublishedContent

classmethod get_es_document_type()

value of the _type field in the index

classmethod get_es_mapping()

Define mapping and parenting

parent_model

alias of PublishedContent

class zds.tutorialv2.models.database.PickListOperation(id, content, operation, operation_date, version, staff_user, canceler_user, is_effective)
exception DoesNotExist
exception MultipleObjectsReturned
cancel(canceler, autosave=True)

Cancel a decision :param canceler: staff user :param autosave: if True saves the modification

save(**kwargs)

Saves the current instance. Override this in a subclass if you want to control the saving process.

The ‘force_insert’ and ‘force_update’ parameters can be used to insist that the “save” must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set.

class zds.tutorialv2.models.database.PublishableContent(*args, **kwargs)

A publishable content.

A PublishableContent retains metadata about a content in database, such as

  • authors, description, source (if the content comes from another website), subcategory, tags and licence ;
  • Thumbnail and gallery ;
  • Creation, publication and update date ;
  • Public, beta, validation and draft sha, for versioning ;
  • Comment support ;
  • Type, which is either “ARTICLE” “TUTORIAL” or “OPINION”
exception DoesNotExist
exception MultipleObjectsReturned
add_tags(tag_collection)

Add all tags contained in tag_collection to this content. If a tag is unknown, it is added to the system. :param tag_collection: A collection of tags. :type tag_collection: list

antispam(user=None)

Check if the user is allowed to post in an tutorial according to the SPAM_LIMIT_SECONDS value.

Parameters:user – the user to check antispam. If None, current user is used.
Returns:True if the user is not able to note (the elapsed time is not enough), False otherwise.
Return type:bool

ensure all authors subscribe to gallery

first_note()
Returns:the first post of a topic, written by topic’s author, if any.
Return type:ContentReaction
first_unread_note(user=None)
Returns:Return the first note the user has unread.
Return type:ContentReaction
get_absolute_contact_url(title='Collaboration')

Get url to send a new PM for collaboration

Parameters:title (str) – what is going to be in the title of the PM before the name of the content
Returns:url to the PM creation form
Return type:str
get_absolute_url_beta()

NOTE: it’s better to use the version contained in VersionedContent, if possible !

Returns:absolute URL to the beta version the content
Return type:str
get_absolute_url_online()

NOTE: it’s better to use the version contained in VersionedContent, if possible !

Returns:absolute URL to the public version the content, if self.public_version is defined
Return type:str
get_last_note()
Returns:the last answer in the thread, if any.
Return type:ContentReaction|None
get_note_count()

Count all the reactions to this content. Warning, if you did not pre process this number, a query will be sent

Returns:number of notes in the tutorial.
Return type:int
get_repo_path(relative=False)

Get the path to the tutorial repository

Parameters:relative – if True, the path will be relative, absolute otherwise.
Returns:physical path
Return type:str
in_beta()

A tutorial is not in beta if sha_beta is None or empty

Returns:True if the tutorial is in beta, False otherwise
Return type:bool
in_drafting()

A tutorial is not in draft if sha_draft is None or empty

Returns:True if the tutorial is in draft, False otherwise
Return type:bool
in_public()

A tutorial is not in on line if sha_public is None or empty

Returns:True if the tutorial is on line, False otherwise
Return type:bool
in_validation()

A tutorial is not in validation if sha_validation is None or empty

Returns:True if the tutorial is in validation, False otherwise
Return type:bool
insert_data_in_versioned(versioned)

Insert some additional data from database in a VersionedContent

Parameters:versioned – the VersionedContent to fill
is_beta(sha)

Is this version of the content the beta version ?

Parameters:sha – version
Returns:True if the tutorial is in beta, False otherwise
Return type:bool
is_permanently_unpublished()

Is this content permanently unpublished by a moderator ?

is_public(sha)

Is this version of the content the published version ?

Parameters:sha – version
Returns:True if the tutorial is in public, False otherwise
Return type:bool
is_validation(sha)

Is this version of the content the validation version ?

Parameters:sha – version
Returns:True if the tutorial is in validation, False otherwise
Return type:bool
last_read_note()
Returns:the last post the user has read.
Return type:ContentReaction
load_version(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.

Parameters:
  • sha – version
  • public (PublishedContent) – if set with the right object, return the public version
Raises:
  • BadObject – if sha is not None and related version could not be found
  • OSError – if the path to the repository is wrong
  • NotAPublicVersion – if the sha does not correspond to a public version
Returns:

the versioned content

Return type:

zds.tutorialv2.models.versioned.VersionedContent

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

Parameters:
  • sha – version
  • public (PublishedContent) – if set with the right object, return the public version
Raises:

Http404 – if sha is not None and related version could not be found

Returns:

the versioned content

Return type:

zds.tutorialv2.models.versioned.ViersionedContent

repo_delete()

Delete the entities and their filesystem counterparts

requires_validation()

Check if content required a validation before publication. Used to check if JsFiddle is available too.

Returns:Whether validation is required before publication.
Return type:bool
save(*args, **kwargs)

Rewrite the save() function to handle slug uniqueness

update(**fields)

wrapper arround self.objects.update

Parameters:fields – Fields to update
Returns:modified self
class zds.tutorialv2.models.database.PublishedContent(*args, **kwargs)

A class that contains information on the published version of a content.

Used for quick url resolution, quick listing, and to know where the public version of the files are.

Linked to a PublishableContent for the rest. Don’t forget to add a .prefetch_related('content') !!

exception DoesNotExist
exception MultipleObjectsReturned
get_absolute_url_epub()

wrapper around self.get_absolute_url_to_extra_content('epub')

Returns:URL to the epub version of the published content
Return type:str
get_absolute_url_html()

wrapper around self.get_absolute_url_to_extra_content('html')

Returns:URL to the HTML version of the published content
Return type:str
get_absolute_url_md()

wrapper around self.get_absolute_url_to_extra_content('md')

Returns:URL to the full markdown version of the published content
Return type:str
get_absolute_url_pdf()

wrapper around self.get_absolute_url_to_extra_content('pdf')

Returns:URL to the PDF version of the published content
Return type:str
get_absolute_url_to_extra_content(type_)

Get the url that point to the extra content the user may want to download

Parameters:type (str) – the type inside allowed_type
Returns:URL to a given extra content (note that no check for existence is done)
Return type:str
get_absolute_url_zip()

wrapper around self.get_absolute_url_to_extra_content('zip')

Returns:URL to the zip archive of the published content
Return type:str
get_char_count(md_file_path=None)

Compute the number of letters for a given content

Parameters:md_file_path (str) – use another file to compute the number of letter rather than the default one.
Returns:Number of letters in the md file
Return type:int
classmethod get_es_django_indexable(force_reindexing=False)

Overridden to remove must_redirect=True (and prefetch stuffs).

get_es_document_source(excluded_fields=None)

Overridden to handle the fact that most information are versioned

classmethod get_es_indexable(force_reindexing=False)

Overridden to also include chapters

classmethod get_es_mapping()

Overridden to add pk into mapping.

Returns:mapping object
Return type:elasticsearch_dsl.Mapping
get_extra_contents_directory()
Returns:path to all the ‘extra contents’
Return type:str
get_size_epub()

Get the size of epub

Returns:size of file
Return type:int
get_size_file_type(type_)

Get the size of a given extra content. Is the size is not in database we get it and store it for next time.

Returns:size of file
Return type:int
get_size_html()

Get the size of html

Returns:size of file
Return type:int
get_size_md()

Get the size of md

Returns:size of file
Return type:int
get_size_pdf()

Get the size of pdf

Returns:size of file
Return type:int
get_size_zip()

Get the size of zip

Returns:size of file
Return type:int
has_epub()

Check if the standard epub version of the content is available

Returns:True if available, False otherwise
Return type:bool
has_html()

Check if the html version of the content is available

Returns:True if available, False otherwise
Return type:bool
has_md()

Check if the flat markdown version of the content is available

Returns:True if available, False otherwise
Return type:bool
has_pdf()

Check if the pdf version of the content is available

Returns:True if available, False otherwise
Return type:bool
has_type(type_)

check if a given extra content exists

Returns:True if the file exists, False otherwhise
Return type:bool
has_zip()

Check if the standard zip version of the content is available

Returns:True if available, False otherwise
Return type:bool
load_public_version()
Return type:zds.tutorialv2.models.database.PublicContent
Returns:the public content
load_public_version_or_404()
Returns:the public content
Return type:zds.tutorialv2.models.database.PublicContent
Raises:Http404 – if the version is not available
class zds.tutorialv2.models.database.Validation(*args, **kwargs)

Content validation.

exception DoesNotExist
exception MultipleObjectsReturned
is_accept()

Check if the content is accepted

Returns:True if status is accepted, False otherwise
Return type:bool
is_cancel()

Check if the content is canceled

Returns:True if status is canceled, False otherwise
Return type:bool
is_pending()

Check if the validation is pending

Returns:True if status is pending, False otherwise
Return type:bool
is_pending_valid()

Check if the validation is pending (but there is a validator)

Returns:True if status is pending/valid, False otherwise
Return type:bool
is_reject()

Check if the content is rejected

Returns:True if status is rejected, False otherwise
Return type:bool

catch the post_delete signal to ensure the deletion of the gallery (otherwise, you generate a loop)

zds.tutorialv2.models.database.delete_published_content_in_elasticsearch(sender, instance, **kwargs)

Catch the pre_delete signal to ensure the deletion in ES. Also, handle the deletion of the corresponding chapters.

zds.tutorialv2.models.database.delete_published_content_in_elasticsearch_if_set_to_redirect(sender, instance, **kwargs)

If the slug of the content changes, the must_redirect field is set to True and a new PublishedContnent is created. To avoid duplicates, the previous ones must be removed from ES.

zds.tutorialv2.models.database.delete_repo(sender, instance, **kwargs)

catch the pre_delete signal to ensure the deletion of the repository if a PublishableContent is deleted

zds.tutorialv2.models.database.transfer_paternity_receiver(sender, instance, **kwargs)

transfer paternity to external user on user deletion

Modèles “versionnés” (versioned.py)

class zds.tutorialv2.models.versioned.Container(title, slug='', parent=None, position_in_parent=1)

A container, which can have sub-Containers or Extracts.

A Container has a title, a introduction and a conclusion, a parent (which can be None) and a position into this parent (which is 1 by default).

It also has a tree depth.

A container could be either a tutorial/article/opinion, a part or a chapter.

add_container(container, generate_slug=False)

Add a child Container, but only if no extract were previously added and tree depth is lower than 2.

Attention

This function will raise an Exception if the publication is an article

Parameters:
  • container – the new container
  • generate_slug – if True, asks the top container a unique slug for this object
Raises:

InvalidOperationError – if the new container cannot be added. Please use can_add_container first to make sure you can use add_container.

add_extract(extract, generate_slug=False)

Add a child container, but only if no container were previously added

Parameters:
  • extract – the new extract
  • generate_slug – if True, ask the top container a unique slug for this object
Raises:

InvalidOperationError – if the extract can’t be added to this container.

can_add_container()
Returns:True if this container accepts child containers, False otherwise
Return type:bool
can_add_extract()

Return True if this container can contain extracts, i.e doesn’t contain any container (only zero or more extracts) and is not too deeply nested.

Returns:True if this container accept child extract, False otherwise
Return type:bool
can_be_in_beta()

Check if content can be in beta.

Returns:Whether content is in beta.
Return type:bool
compute_hash()

Compute an MD5 hash from the introduction and conclusion, for comparison purpose

Returns:MD5 hash
Return type:str
get_absolute_url()
Returns:url to access the container
Return type:str
get_absolute_url_beta()
Returns:url to access the container in beta
Return type:str
get_absolute_url_online()
Returns:the ‘online version’ of the url
Return type:str
get_conclusion()
Returns:the conclusion from the file in self.conclusion
Return type:str
get_conclusion_online()

The conclusion content for online version.

Returns:the full text if introduction exists None otherwise
Return type:str
get_delete_url()
Returns:url to edit the container
Return type:str
get_edit_url()
Returns:url to edit the container
Return type:str
get_introduction()
Returns:the introduction from the file in self.introduction
Return type:str
get_introduction_online()

The introduction content for online version.

Returns:the full text if introduction exists None otherwise
Return type:str
get_last_child_position()
Returns:the position of the last child
Type:int
get_level_as_string()

Get a word (Part/Chapter/Section) for the container level

Attention

this deals with internationalized string

Returns:The string representation of this level
Return type:str
get_next_level_as_string()

Same as self.get_level_as_string() but try to guess the level of this container’s children

Returns:The string representation of next level (upper)
Return type:str
get_path(relative=False)

Get the physical path to the draft version of the container. Note: this function rely on the fact that the top container is VersionedContainer.

Parameters:relative (bool) – if True, the path will be relative, absolute otherwise.
Returns:physical path
Return type:str
get_prod_path(relative=False, file_ext='html')

Get the physical path to the public version of the container. If the container have extracts, then it returns the final HTML file.

Parameters:
  • file_ext – the dumped file extension
  • relative (bool) – return a relative path instead of an absolute one
Returns:

Returns:

physical path

Return type:

str

get_tree_depth()

Return the depth where this container is found.

The tree depth of a container is the number of parents of that container. It is always lower that 3 because a nested container can have at most two parents.

Keep in mind that extracts can reach a depth of 3 in the document tree since there are leaves. Containers are not leaves.

Returns:Tree depth
Return type:int
get_tree_level()

Return the level in the tree of this container, i.e the depth of its deepest child.

Returns:tree level
Return type:int
get_unique_slug(title)

Generate a slug from the title and check if it is already in slug pool. If true, add a “-x” to the end, where “x” is a number starting from 1. When generated, it is added to the slug pool.

Note that the slug cannot be larger than settings.ZDS_APP['content']['max_slug_size'], due to maximum file size limitation.

Parameters:title – title from which the slug is generated (with slugify())
Returns:the unique slug
Return type:str
has_child_with_path(child_path)

Return True if this container has a child matching the given full path.

Parameters:child_path – the full path (/maincontainer/subc1/subc2/childslug) we want to check
Returns:True if the child is found, False otherwise
Return type:bool
has_extracts()

Note: This function relies on the fact that every child has the same type.

Returns:True if the container contains extracts, False

otherwise. :rtype: bool

has_sub_containers()

Note: this function relies on the fact that every child has the same type.

Returns:True if the container contains other containers, False otherwise.
Return type:bool
long_slug()
Returns:a long slug which embeds parent slugs
Return type:str
move_child_after(child_slug, refer_slug)

Change the child’s ordering by moving the child to be below the reference child. This method does not automaticaly update the repo

Parameters:
  • child_slug – the child’s slug
  • refer_slug – the referent child’s slug.
Raises:

ValueError – if one slug does not refer to an existing child

move_child_before(child_slug, refer_slug)

Change the child’s ordering by moving the child to be just above the reference child. This method does not automaticaly update the repo.

Parameters:
  • child_slug – the child’s slug
  • refer_slug – the referent child’s slug.
Raises:

ValueError – if one slug does not refer to an existing child

move_child_down(child_slug)

Change the child’s ordering by moving down the child whose slug equals child_slug. This method does not automaticaly update the repo.

Parameters:

child_slug – the child’s slug

Raises:
  • ValueError – if the slug does not refer to an existing child
  • IndexError – if the extract is already the last child
move_child_up(child_slug)

Change the child’s ordering by moving up the child whose slug equals child_slug. This method does not automaticaly update the repo.

Parameters:

child_slug – the child’s slug

Raises:
  • ValueError – if the slug does not refer to an existing child
  • IndexError – if the extract is already the first child
publish_extracts(base_dir, is_js, template, failure_exception)

Publish the current element thanks to a templated view.

Parameters:
  • base_dir – directory into which we will put the result
  • is_js – jsfiddle activation flag
  • template – templated view name
  • failure_exception – the exception to throw when we fail
Returns:

repo_add_container(title, introduction, conclusion, commit_message='', do_commit=True, slug=None)
Parameters:
  • title – title of the new container
  • introduction – text of its introduction
  • conclusion – text of its conclusion
  • commit_message – commit message that will be used instead of the default one
  • do_commit – perform the commit in repository if True
Returns:

commit sha

Return type:

str

repo_add_extract(title, text, commit_message='', do_commit=True, slug=None)
Parameters:
  • title – title of the new extract
  • text – text of the new extract
  • commit_message – commit message that will be used instead of the default one
  • do_commit – perform the commit in repository if True
  • generate_slug – indicates that is must generate slug
Returns:

commit sha

Return type:

str

repo_delete(commit_message='', do_commit=True)
Parameters:
  • commit_message – commit message used instead of default one if provided
  • do_commit – tells if we have to commit the change now or let the outer program do it
Returns:

commit sha

Return type:

str

repo_update(title, introduction, conclusion, commit_message='', do_commit=True, update_slug=True)

Update the container information and commit them into the repository

Parameters:
  • title – the new title
  • introduction – the new introduction text
  • conclusion – the new conclusion text
  • commit_message – commit message that will be used instead of the default one
  • do_commit – perform the commit in repository if True
Returns:

commit sha

Return type:

str

requires_validation()

Check if content required a validation before publication. Used to check if JsFiddle is available too.

Returns:Whether validation is required before publication.
Return type:bool
top_container()
Returns:Top container (for which parent is None)
Return type:VersionedContent
traverse(only_container=True)

Traverse the container.

Parameters:only_container – if we only want container’s paths, not extract
Returns:a generator that traverse all the container recursively (depth traversal)
Return type:collections.Iterable[Container|Extract]
update_children()

Update the path for introduction and conclusion for the container and all its children. If the children is an extract, update the path to the text instead. This function is useful when self.slug has changed.

Note: this function does not account for a different arrangement of the files.

class zds.tutorialv2.models.versioned.Extract(title, slug='', container=None, position_in_parent=1)

A content extract from a Container.

It has a title, a position in the parent container and a text.

compute_hash()

Compute an MD5 hash from the text, for comparison purpose

Returns:MD5 hash of the text
Return type:str
get_absolute_url()

Find the url that point to the offline version of this extract

Returns:the url to access the tutorial offline
Return type:str
get_absolute_url_beta()
Returns:the url to access the tutorial when in beta
Return type:str
get_absolute_url_online()
Returns:the url to access the tutorial when online
Return type:str
get_delete_url()
Returns:URL to delete the extract
Return type:str
get_edit_url()
Returns:url to edit the extract
Return type:str
get_first_level_slug()
Returns:the first_level_slug, if (and only if) the parent container is a chapter
Return type:str
get_full_slug()

Get the slug of curent extract with its full path (part1/chapter1/slug_of_extract).

This method is an alias to extract.get_path(True)[:-3] (removes the .md file extension).

Return type:str
get_path(relative=False)

Get the physical path to the draft version of the extract. :param relative: if True, the path will be relative, absolute otherwise. :return: physical path :rtype: str

get_text()
Returns:versioned text
Return type:str
get_tree_depth()

Return the depth where this extract is found.

The tree depth of an extract is the number of parents of that extract. It is always lower that 4 because an extract can have at most three parents.

Keep in mind that containers can’t reach a depth of 3 in the document tree since there are not leaves.

Returns:Tree depth
Return type:int
repo_delete(commit_message='', do_commit=True)
Parameters:
  • commit_message – commit message used instead of default one if provided
  • do_commit – tells if we have to commit the change now or let the outer program do it
Returns:

commit sha, None if no commit is done

Return type:

str

repo_update(title, text, commit_message='', do_commit=True)
Parameters:
  • title – new title of the extract
  • text – new text of the extract
  • commit_message – commit message that will be used instead of the default one
Returns:

commit sha

Return type:

str

exception zds.tutorialv2.models.versioned.NotAPublicVersion(*args, **kwargs)

Exception raised when a given version is not a public version as it should be

class zds.tutorialv2.models.versioned.PublicContent(current_version, _type, title, slug)

This is the public version of a VersionedContent, created from public repository

class zds.tutorialv2.models.versioned.VersionedContent(current_version, _type, title, slug, slug_repository='')

This class is used to handle a specific version of a tutorial.tutorial

It is created from the ‘manifest.json’ file, and could dump information in it.

For simplicity, it also contains DB information (but cannot modified them!), filled at the creation.

change_child_directory(child, adoptive_parent)

Move an element of this content to a new location. This method changes the repository index and stage every change but does not commit.

Parameters:
  • child – the child we want to move, can be either an Extract or a Container object
  • adoptive_parent – the container where the child will be moved, must be a Container object
commit_changes(commit_message)

Commit change made to the repository

Parameters:commit_message – The message that will appear in content history
Returns:commit sha
Return type:str
dump_json(path=None)

Write the JSON into file

Parameters:path – path to the file. If None, write in ‘manifest.json’
get_absolute_url(version=None)
Returns:url to access the container
Return type:str
get_absolute_url_beta()
Returns:the url to access the tutorial when in beta
Return type:str
get_absolute_url_online()
Returns:the url to access the content when online
Return type:str
get_json()
Returns:raw JSON file
Return type:str
get_list_of_chapters()
Returns:a list of chapters (Container which contains Extracts) in the reading order
Return type:list[Container]
get_path(relative=False, use_current_slug=False)

Get the physical path to the draft version of the Content.

Parameters:
  • relative – if True, the path will be relative, absolute otherwise.
  • use_current_slug – if True, use self.slug instead of self.slug_last_draft
Returns:

physical path

Return type:

str

get_prod_path(relative=False, file_ext='html')

Get the physical path to the public version of the content. If it has one or more extracts (if it is a mini-tutorial or an article), return the path of the HTML file.

Parameters:relative – return the relative path instead of the absolute one
Returns:physical path
Return type:str
repo_update_top_container(title, slug, introduction, conclusion, commit_message='', do_commit=True)

Update the top container information and commit them into the repository. Note that this is slightly different from the repo_update() function, because slug is generated using DB

Parameters:
  • title – the new title
  • slug – the new slug, according to title (choose using DB!!)
  • introduction – the new introduction text
  • conclusion – the new conclusion text
  • commit_message – commit message that will be used instead of the default one
  • do_commit – if True, also commit change
Returns:

commit sha

Return type:

str

textual_type()

Create a internationalized string with the human readable type of this content e.g “The Article”

Returns:internationalized string
Return type:str

Les managers (managers.py)

class zds.tutorialv2.managers.PublishableContentManager

get_last_articles(number=0)
..attention:
this one uses a raw subquery for historical reasons. It will hopefully be replaced one day by an ORM primitive.
Returns:list of last articles expanded with ‘count_note’ property that prefetches number of comments
Return type:list
get_last_opinions()

This depends on settings.ZDS_APP[‘opinions’][‘home_number’] parameter.

Returns:list of last opinions
Return type:list
get_last_tutorials(number=0)

get list of last published tutorial

Parameters:number – number of tutorial you want. By default it is interpreted as settings.ZDS_APP['tutorial']['home_number']
Returns:list of last published content
Return type:list
transfer_paternity(unregistered_user, replacement_author, gallery_class)

Erases or transfers the paternity of all publishable content owned by a user. If a content has more than one author, the unregistering author simply leaves its author list, otherwise their published content are sent to replacement_author, unpublished content are deleted and their beta topics closed.

Parameters:
  • unregistered_user – the user to be unregistered
  • replacement_author – the new author
  • gallery_class – the class to link tutorial with gallery (perhaps overkill :p)

Mixins (mixins.py)

class zds.tutorialv2.mixins.ContentTypeMixin

This class deals with the type of contents and fill context according to that

class zds.tutorialv2.mixins.DoesNotRequireValidationFormViewMixin(**kwargs)

Ensure the content do not require validation before publication.

get_form_kwargs()

Returns the keyword arguments for instantiating the form.

class zds.tutorialv2.mixins.DownloadViewMixin(**kwargs)

Basic View to return a file to download

(inspired from https://djangosnippets.org/snippets/2549/ and http://stackoverflow.com/questions/16286666/send-a-file-through-django-class-based-views)

You just need to override get_contents() to make it works

get(context, **response_kwargs)

Access to a file with only get method then write the file content in response stream. Properly sets Content-Type and Content-Disposition headers

class zds.tutorialv2.mixins.FormWithPreview(**kwargs)
post(request, *args, **kwargs)

Handles POST requests, instantiating a form instance with the passed POST variables and then checked for validity.

class zds.tutorialv2.mixins.ModalFormView(**kwargs)

If self.modal_form is set True, this class will ensure that the redirection is made to the previous page if an error appear

form_invalid(form)

If self.modal_form is set True, this function is rewritten to send back to the previous page with an error message, instead of using the form template which is normally provided.

The redirection is made to form.previous_page_url, if exists, content:view otherwise.

exception zds.tutorialv2.mixins.MustRedirect(*args, **kwargs)

Exception raised when this is not the last version of the content which is called

class zds.tutorialv2.mixins.RequiresValidationViewMixin(**kwargs)

Ensure the content require validation before publication.

class zds.tutorialv2.mixins.SingleContentDetailViewMixin(**kwargs)

This enhanced DetailView ensure,

  • by rewriting get(), that:
    • self.object contains the result of get_object() (as it must be if get() is not rewritten)
    • self.sha is set according to self.request.GET[‘version’] (if any) and self.object.sha_draft otherwise
    • self.versioned_object contains the results of get_versioned_object()
  • by surcharging get_context_data(), that
    • context[‘content’] contains self.versioned_object
    • context[‘can_edit’] is set
    • context[‘version’] is set (if different from self.object.sha_draft)
    • context[‘beta_topic’] is set (if any)
get_context_data(**kwargs)

Insert the single object into the context dict.

class zds.tutorialv2.mixins.SingleContentDownloadViewMixin(**kwargs)

Ensure, by rewritring get(), that - self.object contains the result of get_object() (as it must be if get() is not rewritten) - self.sha is set according to self.request.GET[‘version’] (if any) and self.object.sha_draft otherwise - self.versioned_object contains the results of get_versioned_object()

get(context, **response_kwargs)

Access to a file with only get method then write the file content in response stream. Properly sets Content-Type and Content-Disposition headers

class zds.tutorialv2.mixins.SingleContentFormViewMixin(**kwargs)

This enhanced FormView ensure,

  • by surcharging dispatch(), that:
    • self.object contains the result of get_object() (as for DetailView)
    • self.versioned_object contains the results of get_versioned_object()
  • by surcharging get_context_data(), that
    • context[‘content’] contains self.versioned_object
get_context_data(**kwargs)

Insert the form into the context dict.

class zds.tutorialv2.mixins.SingleContentPostMixin

Base mixin used to get content from post query

get_object(queryset=None)

Get database representation of the content by its pk, then check permissions

class zds.tutorialv2.mixins.SingleContentViewMixin

Base mixin to get only one content, and its corresponding versioned content

Deals with URL resolution in the following way:

  1. In get_object():
    • Fetch the PublishableContent according to self.kwargs['pk'], self.request.GET['pk'] or self.request.POST['pk'] (one of these have to be defined). Raise Http404 if any.
    • Then, check permissions with respect to self.must_be_author and self.authorized_for_staff (and define self.is_staff and self.is_author). Raise PermissionDenied if any.
  2. In get_versioned_object():
    • Deal with sha : assume self.object.sha_draft by default, but reset according to self.request.GET['version'], if exists. Then, check self.only_draft_version and raise PermissionDenied if any
    • Fetch the VersionedContent. Due to the use of self.object.load_version_or_404(sha), raise Http404.
    • Check if its the beta or public version, and allow access if it’s the case. Raise PermissionDenied.
    • Check slug if self.kwargs['slug'] is defined. Raise Http404 if any.
  3. In get_public_object(), fetch the last published version, if any

Any redefinition of any of these two functions should take care of those points.

get_object(queryset=None)

Get database representation of the content by its pk, then check permissions

get_public_object()

Get the published version, if any

get_versioned_object()

Gets the asked version of current content.

class zds.tutorialv2.mixins.SingleOnlineContentDetailViewMixin(**kwargs)

This enhanced DetailView ensures,

  • by rewriting get(), that:
    • self.object contains the result of get_object() (as it must be if get() was not rewritten)
    • Redirection is made if we catch MustRedirect
    • self.versioned_object contains a PublicContent object
    • self.public_content_object contains a PublishedContent object
  • by surcharging get_context_data(), that
    • context[‘content’] is set
    • context[‘is_staff’] is set
    • context[‘can_edit’] is set
    • context[‘public_object’] is set
    • context[‘is_antispam’] is set
get_context_data(**kwargs)

Insert the single object into the context dict.

class zds.tutorialv2.mixins.SingleOnlineContentFormViewMixin(**kwargs)

This enhanced FormView ensure,

  • by surcharging dispatch(), that:
    • self.public_content_object contains a PublishedContent object
    • self.object contains the result of get_object() (as for DetailView)
    • self.versioned_object contains the results of get_versioned_object()
  • by surcharging get_context_data(), that
    • context[‘content’] is set
    • context[‘public_object’] is set

Note: does not catch MustRedirect, so you should not use a slug with POST request

get_context_data(**kwargs)

Insert the form into the context dict.

class zds.tutorialv2.mixins.SingleOnlineContentViewMixin

Base mixin to get only one content online content

Deals with URL resolution in the following way:

  1. In get_object():
    • Fetch the PublicContent according to self.kwargs['pk'], self.request.GET['pk'] or self.request.POST['pk'] 0(one of these have to be defined). Raise Http404 if any.
    • Check if self.current_content_type if defined, and use it if it’s the case
    • Check if slug is defined, also check object it if it’s the case
    • Then, define self.is_staff and self.is_author.
  2. In get_versioned_object(): Fetch the VersionedContent. Due to the use of
    self.public_content_object.load_public_version_or_404(), raise Http404 if any.

Any redefinition of any of these two functions should take care of those points.

get_redirect_url(public_version)

Return the most recent url, based on the current public version

Les formulaires (forms.py)

class zds.tutorialv2.forms.AcceptValidationForm(validation, *args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.AskValidationForm(content, *args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.AuthorForm(*args, **kwargs)
clean_username()

Check every username and send it to the cleaned_data[‘user’] list

Returns:a dictionary of all treated data with the users key added
is_valid()

Returns True if the form has no errors. Otherwise, False. If errors are being ignored, returns False.

class zds.tutorialv2.forms.BetaForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None)
class zds.tutorialv2.forms.CancelValidationForm(validation, *args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.ContainerForm(*args, **kwargs)
class zds.tutorialv2.forms.ContentForm(*args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.DoNotPickOpinionForm(content, *args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

is_valid()

Returns True if the form has no errors. Otherwise, False. If errors are being ignored, returns False.

class zds.tutorialv2.forms.ExtractForm(*args, **kwargs)
class zds.tutorialv2.forms.FormWithTitle(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.ImportContentForm(*args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.ImportForm(*args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.ImportNewContentForm(*args, **kwargs)
class zds.tutorialv2.forms.JsFiddleActivationForm(*args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.MoveElementForm(*args, **kwargs)
class zds.tutorialv2.forms.NoteEditForm(*args, **kwargs)
class zds.tutorialv2.forms.NoteForm(content, reaction, *args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.PickOpinionForm(content, *args, **kwargs)
class zds.tutorialv2.forms.PromoteOpinionToArticleForm(content, *args, **kwargs)
class zds.tutorialv2.forms.PublicationForm(content, *args, **kwargs)

The publication form (used only for content without preliminary validation).

class zds.tutorialv2.forms.RejectValidationForm(validation, *args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.RemoveAuthorForm(*args, **kwargs)
clean_username()

Check every username and send it to the cleaned_data[‘user’] list

Returns:a dictionary of all treated data with the users key added
class zds.tutorialv2.forms.RevokeValidationForm(content, *args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

class zds.tutorialv2.forms.UnpickOpinionForm(content, *args, **kwargs)
class zds.tutorialv2.forms.UnpublicationForm(content, *args, **kwargs)
class zds.tutorialv2.forms.WarnTypoForm(content, targeted, public=True, *args, **kwargs)
clean()

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

Les utilitaires (utils.py)

exception zds.tutorialv2.utils.BadArchiveError(reason)

The exception that is raised when a bad archive is sent

exception zds.tutorialv2.utils.BadManifestError(*args, **kwargs)

The exception that is raised when the manifest.json contains errors

exception zds.tutorialv2.utils.FailureDuringPublication(*args, **kwargs)

Exception raised if something goes wrong during the publication process

exception zds.tutorialv2.utils.InvalidOperationError
exception zds.tutorialv2.utils.InvalidSlugError(*args, **kwargs)

Error raised when a slug is invalid. Argument is the slug that cause the error.

source can also be provided, being the sentence from witch the slug was generated, if any. had_source is set to True if the source is provided.

exception zds.tutorialv2.utils.TooDeepContainerError(*args, **kwargs)

Exception used to represent the fact you can’t add a container to a level greater than two

zds.tutorialv2.utils.all_is_string_appart_from_given_keys(dict_representation, keys=('children', ))

check all keys are string appart from the children key :param dict_representation: the json decoded dictionary :param keys: keys that do not need to be string :type dict_representation: dict :return: :rtype: bool

zds.tutorialv2.utils.check_slug(slug)

If the title is incorrect (only special chars so slug is empty).

Parameters:slug (str) – slug to test
Returns:True if slug is valid, false otherwise
Return type:bool
zds.tutorialv2.utils.clone_repo(old_path, new_path)

Proxy to git clone command. Ensure directory are properly created

Parameters:
  • old_path – path of the repo to be cloned
  • new_path – path of the target repo
Returns:

the target repository encapsulated in a GitPython object.

Return type:

Repo

zds.tutorialv2.utils.default_slug_pool()

initialize a slug pool with all forbidden name. basically introduction and conclusion

Returns:the forbidden slugs in the edition system
Return type:dict
zds.tutorialv2.utils.export_container(container)

Export a container to a dictionary

Parameters:container (zds.tutorialv2.models.models_versioned.Container) – the container
Returns:dictionary containing the information
Return type:dict
zds.tutorialv2.utils.export_content(content)

Export a content to dictionary in order to store them in a JSON file

Parameters:content – content to be exported
Returns:dictionary containing the information
Return type:dict
zds.tutorialv2.utils.export_extract(extract)

Export an extract to a dictionary

Parameters:extract – extract to export
Returns:dictionary containing the information
Return type:dict
zds.tutorialv2.utils.fill_containers_from_json(json_sub, parent)

Function which call itself to fill container

Parameters:
  • json_sub – dictionary from ‘manifest.json’
  • parent – the container to fill
Raises:
  • BadManifestError – if the manifest is not well formed or the content’s type is not correct
  • KeyError – if one mandatory key is missing
zds.tutorialv2.utils.get_blob(tree, path)

Return the data contained into a given file

Parameters:
  • tree (git.objects.tree.Tree) – Git Tree object
  • path (str) – Path to file
Returns:

contains

Return type:

bytearray

zds.tutorialv2.utils.get_commit_author()

get a dictionary that represent the commit author with author and comitter key. If there is no users, bot account pk is used.

Returns:correctly formatted commit author for repo.index.commit()
Return type:dict
zds.tutorialv2.utils.get_content_from_json(json, sha, slug_last_draft, public=False, max_title_len=80, hint_licence=None)

Transform the JSON formated data into VersionedContent

Parameters:
  • json – JSON data from a manifest.json file
  • sha – version
  • slug_last_draft – the slug for draft marked version
  • max_title_len – max str length for title
  • public – the function will fill a PublicContent instead of a VersionedContent if True
  • hint_licence – avoid loading the licence if it is already the same as the one loaded
Returns:

a Public/VersionedContent with all the information retrieved from JSON

Return type:

zds.tutorialv2.models.versioned.VersionedContent|zds.tutorialv2.models.database.PublishedContent

zds.tutorialv2.utils.get_target_tagged_tree(movable_child, root)

Gets the tagged tree with deplacement availability

Parameters:
  • movable_child – the extract we want to move
  • root – the VersionedContent we use as root
Return type:

tuple

Returns:

an array of tuples that represent the capacity of movable_child to be moved near another child check get_target_tagged_tree_for_extract and get_target_tagged_tree_for_container for format

zds.tutorialv2.utils.get_target_tagged_tree_for_container(movable_child, root, bias=-1)

Gets the tagged tree with displacement availability when movable_child is an extract

Parameters:
  • movable_child – the container we want to move
  • root – the VersionedContent we use as root
  • bias – a negative or zero integer that represent the level bias. A value of -1 (default) represent the fact that we want to make the movable_child a sibling of the tagged child, a value of 0 that we want to make it a sub child.
Return type:

tuple

Returns:

an array of tuples that represent the capacity of movable_child to be moved near another child extracts are not included

zds.tutorialv2.utils.get_target_tagged_tree_for_extract(movable_child, root)

Gets the tagged tree with displacement availability when movable_child is an extract

Parameters:
  • movable_child – the extract we want to move
  • root – the VersionedContent we use as root
Return type:

tuple

Returns:

an array of tuples that represent the capacity of movable_child to be moved near another child tuples are (relative_path, title, level, can_be_a_target)

zds.tutorialv2.utils.init_new_repo(db_object, introduction_text, conclusion_text, commit_message='', do_commit=True)

Create a new repository in settings.ZDS_APP['contents']['private_repo'] to store the files for a new content. Note that db_object.sha_draft will be set to the good value

Parameters:
  • db_objectPublishableContent (WARNING: should have a valid slug, so previously saved)
  • introduction_text – introduction from form
  • conclusion_text – conclusion from form
  • commit_message – set a commit message instead of the default one
  • do_commit – perform commit if True
Returns:

VersionedContent object

Return type:

zds.tutorialv2.models.versioned.VersionedContent

zds.tutorialv2.utils.mark_read(content, user=None)

Mark the last tutorial note as read for the user.

Parameters:
  • content – the content to mark
  • user – user that read the content, if None will use currrent user
zds.tutorialv2.utils.never_read(content, user=None)

Check if a content note feed has been read by a user since its last post was added.

Parameters:
Returns:

True if the user never read this content’s reactions, False otherwise

Return type:

bool

zds.tutorialv2.utils.normalize_unicode_url(unicode_url)

Sometimes you get an URL by a user that just isn’t a real URL because it contains unsafe characters like ‘β’ and so on. This function can fix some of the problems in a similar way browsers handle data entered by the user:

normalize_unicode_url(u'http://de.wikipedia.org/wiki/Elf (Begriffsklärung)')
# 'http://de.wikipedia.org/wiki/Elf%20%28Begriffskl%C3%A4rung%29'
Parameters:charset – The target charset for the URL if the url was given as unicode string.
zds.tutorialv2.utils.search_container_or_404(base_content, kwargs_array)
Parameters:
  • base_content – the base Publishable content we will use to retrieve the container
  • kwargs_array – an array that may contain parent_container_slug and container_slug keys or the string representation
Returns:

the Container object we were searching for

Return type:

zds.tutorialv2.models.versioned.Container

Raises:

Http404 – if no suitable container is found

zds.tutorialv2.utils.search_extract_or_404(base_content, kwargs_array)
Parameters:
  • base_content – the base Publishable content we will use to retrieve the container
  • kwargs_array – an array that may contain parent_container_slug and container_slug and MUST contains extract_slug
Returns:

the Extract object

Return type:

zds.tutorialv2.models.versioned.Extract

Raise:

Http404 if not found

zds.tutorialv2.utils.slugify_raise_on_invalid(title, use_old_slugify=False)

use uuslug to generate a slug but if the title is incorrect (only special chars or slug is empty), an exception is raised.

Parameters:
  • title (str) – to be slugified title
  • use_old_slugify (bool) – use the function slugify() defined in zds.utils instead of the one in uuslug. Usefull for retro-compatibility with the old article/tutorial module, SHOULD NOT be used for the new one !
Raises:

InvalidSlugError – on incorrect slug

Returns:

the slugified title

Return type:

str

zds.tutorialv2.utils.try_adopt_new_child(adoptive_parent, child)

Try the adoptive parent to take the responsability of the child :param adoptive_parent: the new parent for child if all check pass :param child: content child to be moved :raise Http404: if adoptive_parent_full_path is not found on root hierarchy :raise TypeError: if the adoptive parent is not allowed to adopt the child due to its type :raise TooDeepContainerError: if the child is a container that is too deep to be adopted by the proposed parent

Les utilitaires de publication (publication_utils.py)

exception zds.tutorialv2.publication_utils.FailureDuringPublication(*args, **kwargs)

Exception raised if something goes wrong during publication process

class zds.tutorialv2.publication_utils.Publicator

Publicator base object, all methods must be overridden

get_published_content_entity(md_file_path)

Retrieve the db entity from mdfile path

Parameters:md_file_path (str) – mdfile path as string
Returns:the db entity
Return type:zds.tutorialv2.models.models_database.PublishedContent
publish(md_file_path, base_name, **kwargs)

Function called to generate a content export

Parameters:
  • md_file_path – base markdown file path
  • base_name – file name without extension
  • kwargs – other publicator dependent options
class zds.tutorialv2.publication_utils.PublicatorRegistry

Register all publicator as a ‘human-readable name/publicator’ instance key/value list

classmethod get(name)

Get publicator named ‘name’.

Parameters:name
Returns:the wanted publicator
Return type:Publicator
Raises:KeyError – if publicator is not registered
classmethod get_all_registered(exclude=None)
Args:
exclude: A list of excluded publicator

Returns:

classmethod unregister(name)

Remove registered Publicator named ‘name’ if present

Parameters:name – publicator name.
class zds.tutorialv2.publication_utils.WatchdogFilePublicator(watched_dir)

Just create a meta data file for watchdog

publish(md_file_path, base_name, silently_pass=True, **kwargs)

Function called to generate a content export

Parameters:
  • md_file_path – base markdown file path
  • base_name – file name without extension
  • kwargs – other publicator dependent options
class zds.tutorialv2.publication_utils.ZMarkdownEpubPublicator
publish(md_file_path, base_name, **kwargs)

Function called to generate a content export

Parameters:
  • md_file_path – base markdown file path
  • base_name – file name without extension
  • kwargs – other publicator dependent options
class zds.tutorialv2.publication_utils.ZMarkdownRebberLatexPublicator(extension='.pdf', latex_classes='')

Use zmarkdown and rebber stringifier to produce latex & pdf output.

publish(md_file_path, base_name, **kwargs)

Function called to generate a content export

Parameters:
  • md_file_path – base markdown file path
  • base_name – file name without extension
  • kwargs – other publicator dependent options
class zds.tutorialv2.publication_utils.ZipPublicator
publish(md_file_path, base_name, **kwargs)

Function called to generate a content export

Parameters:
  • md_file_path – base markdown file path
  • base_name – file name without extension
  • kwargs – other publicator dependent options
class zds.tutorialv2.publication_utils.ZmarkdownHtmlPublicator
publish(md_file_path, base_name, **kwargs)

Function called to generate a content export

Parameters:
  • md_file_path – base markdown file path
  • base_name – file name without extension
  • kwargs – other publicator dependent options
zds.tutorialv2.publication_utils.generate_external_content(base_name, extra_contents_path, md_file_path, overload_settings=False, excluded=None)

generate all static file that allow offline access to content

Parameters:
  • base_name – base nae of file (without extension)
  • extra_contents_path – internal directory where all files will be pushed
  • md_file_path – bundled markdown file path
  • pandoc_debug_strspecific to pandoc publication : avoid subprocess to be errored
  • overload_settings – this option force the function to generate all registered formats even when settings ask for PDF not to be published
Returns:

zds.tutorialv2.publication_utils.make_zip_file(published_content)

Create the zip archive extra content from the published content

Parameters:published_content – a PublishedContent object
Returns:
zds.tutorialv2.publication_utils.publish_content(db_object, versioned, is_major_update=True)

Publish a given content.

Note

create a manifest.json without the introduction and conclusion if not needed. Also remove the ‘text’ field of extracts.

Parameters:
Raises:

FailureDuringPublication – if something goes wrong

Returns:

the published representation

Return type:

zds.tutorialv2.models.database.PublishedContent

zds.tutorialv2.publication_utils.unpublish_content(db_object, moderator=None)

Remove the given content from the public view.

Note

This will send content_unpublished event.

Parameters:
  • db_object (PublishableContent) – Database representation of the content
  • moderator (django.contrib.auth.models.User) – the staff user who triggered the unpublish action.
Returns:

True if unpublished, False otherwise

Return type:

bool

Les receveurs d’évènement bdd (receivers.py)

zds.tutorialv2.receivers.cleanup_validation_alerts(sender, instance, *, moderator=None, **__)

When opinions are unpublished (probably permanently), we must be sure all alerts are handled. For now we just resolve them.

Parameters:
  • sender – sender class
  • instance – object instance
  • moderator – staff member or author that generated depublication
zds.tutorialv2.receivers.log_content_deletion(sender, instance, **__)

When a content or gallery is deleted, this action is logged.