Beispiel #1
0
    def setUp(self):

        # don't build PDF to speed up the tests
        settings.ZDS_APP['content']['build_pdf_when_published'] = False

        self.staff = StaffProfileFactory().user

        settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
        self.mas = ProfileFactory().user
        settings.ZDS_APP['member']['bot_account'] = self.mas.username

        bot = Group(name=settings.ZDS_APP["member"]["bot_group"])
        bot.save()
        self.external = UserFactory(
            username=settings.ZDS_APP["member"]["external_account"],
            password="******")

        self.beta_forum = ForumFactory(
            pk=settings.ZDS_APP['forum']['beta_forum_id'],
            category=CategoryFactory(position=1),
            position_in_category=1
        )  # ensure that the forum, for the beta versions, is created

        self.licence = LicenceFactory()
        self.subcategory = SubCategoryFactory()

        self.user_author = ProfileFactory().user
        self.user_staff = StaffProfileFactory().user
        self.user_guest = ProfileFactory().user

        # create an article
        self.article = PublishableContentFactory(type='ARTICLE')
        self.article.authors.add(self.user_author)
        UserGalleryFactory(gallery=self.article.gallery,
                           user=self.user_author,
                           mode='W')
        self.article.licence = self.licence
        self.article.subcategory.add(self.subcategory)
        self.article.save()

        # fill it with one extract
        self.article_draft = self.article.load_version()
        self.extract1 = ExtractFactory(container=self.article_draft,
                                       db_object=self.article)

        # then, publish it !
        version = self.article_draft.current_version
        self.published = publish_content(self.article,
                                         self.article_draft,
                                         is_major_update=True)

        self.article.sha_public = version
        self.article.sha_draft = version
        self.article.public_version = self.published
        self.article.save()

        self.articlefeed = LastArticlesFeedRSS()
Beispiel #2
0
    def _prepare(cls, create, **kwargs):
        """create a new PublishableContent and then publish it.
        """

        content = super(PublishedContentFactory,
                        cls)._prepare(create, **kwargs)
        published = publish_content(content, content.load_version(), True)
        content.sha_public = content.sha_draft
        content.public_version = published
        content.save()

        return content
Beispiel #3
0
 def test_publication_and_attributes_consistency(self):
     pubdate = datetime.now() - timedelta(days=1)
     article = PublishedContentFactory(type="ARTILCE",
                                       author_list=[self.user_author])
     public_version = article.public_version
     public_version.publication_date = pubdate
     public_version.save()
     # everything must come from database to have good datetime comparison
     article = PublishableContent.objects.get(pk=article.pk)
     article.public_version.load_public_version()
     old_date = article.public_version.publication_date
     old_title = article.public_version.title()
     old_description = article.public_version.description()
     article.licence = LicenceFactory()
     article.save()
     self.assertEqual(
         self.client.login(username=self.user_author.username,
                           password='******'), True)
     self.client.post(
         reverse("content:edit", args=[article.pk, article.slug]), {
             "title": old_title + "bla",
             "description": old_description + "bla",
             "type": "ARTICLE",
             "licence": article.licence.pk,
             "subcategory": SubCategoryFactory().pk,
             "last_hash": article.sha_draft
         })
     article = PublishableContent.objects.prefetch_related(
         "public_version").get(pk=article.pk)
     article.public_version.load_public_version()
     self.assertEqual(old_title, article.public_version.title())
     self.assertEqual(old_description, article.public_version.description())
     self.assertEqual(old_date, article.public_version.publication_date)
     publish_content(article, article.load_version(), False)
     article = PublishableContent.objects.get(pk=article.pk)
     article.public_version.load_public_version()
     self.assertEqual(old_date, article.public_version.publication_date)
     self.assertNotEqual(old_date, article.public_version.update_date)
Beispiel #4
0
def migrate_tuto(tutos, title="Exporting mini tuto"):

    if len(tutos) == 0:
        return

    for i in progressbar(xrange(len(tutos)), title, 100):
        current = tutos[i]
        if not os.path.exists(current.get_path(False)):
            sys.stderr.write(
                'Invalid physical path to repository « {} », skipping\n'.
                format(current.get_path(False)))
            continue
        exported = PublishableContent()
        exported.slug = current.slug
        exported.type = "TUTORIAL"
        exported.title = current.title
        exported.sha_draft = current.sha_draft
        exported.sha_beta = current.sha_beta
        exported.sha_validation = current.sha_validation
        exported.licence = current.licence
        exported.update_date = current.update
        exported.creation_date = current.create_at
        exported.description = current.description
        exported.js_support = current.js_support
        exported.source = current.source
        exported.pubdate = current.pubdate
        exported.save()

        try:
            clean_commit = copy_and_clean_repo(current.get_path(False),
                                               exported.get_repo_path(False))
        except InvalidGitRepositoryError as e:
            exported.delete()
            sys.stderr.write(
                'Repository in « {} » is invalid, skipping\n'.format(e))
            continue

        if clean_commit:
            exported.sha_draft = clean_commit

            # save clean up in old module to avoid any trouble
            current.sha_draft = clean_commit
            current.save()

        exported.gallery = current.gallery
        exported.image = current.image
        [
            exported.subcategory.add(category)
            for category in current.subcategory.all()
        ]
        [exported.helps.add(help) for help in current.helps.all()]
        [exported.authors.add(author) for author in current.authors.all()]
        exported.save()

        # now, re create the manifest.json
        versioned = exported.load_version()

        # this loop is there because of old .tuto import that failed with their chapter intros
        for container in versioned.traverse(True):
            if container.parent is None:
                continue
            # in old .tuto file chapter intro are represented as chapter_slug/introduction.md
            # instead of part_slug/chapter_slug/introduction.md
            corrected_intro_path = file_join(
                container.get_path(relative=False), "introduction.md")
            corrected_ccl_path = file_join(container.get_path(relative=False),
                                           "conclusion.md")
            if container.get_path(True) not in container.introduction:
                if file_exists(corrected_intro_path):
                    container.introduction = file_join(
                        container.get_path(relative=True), "introduction.md")
                else:
                    container.introduction = None
            if container.get_path(True) not in container.conclusion:
                if file_exists(corrected_ccl_path):
                    container.conclusion = file_join(
                        container.get_path(relative=True), "conclusion.md")
                else:
                    container.conclusion = None

        versioned.licence = exported.licence
        versioned.type = "TUTORIAL"
        versioned.dump_json()
        versioned.repository.index.add(['manifest.json'
                                        ])  # index new manifest before commit
        exported.sha_draft = versioned.commit_changes(u"Migration version 2")

        exported.old_pk = current.pk
        exported.save()
        # export beta forum post
        former_topic = Topic.objects.filter(key=current.pk).first()
        if former_topic is not None:
            former_topic.related_publishable_content = exported

            former_topic.save()
            former_first_post = former_topic.first_post()
            text = former_first_post.text
            text = text.replace(current.get_absolute_url_beta(),
                                exported.get_absolute_url_beta())
            former_first_post.update_content(text)
            former_first_post.save()
            exported.beta_topic = former_topic
            exported.save()
        # extract notes
        reacts = Note.objects.filter(tutorial__pk=current.pk)\
                             .select_related("author")\
                             .order_by("pubdate")\
                             .all()
        migrate_validation(
            exported,
            TutorialValidation.objects.filter(tutorial__pk=current.pk))
        if current.last_note:
            export_comments(reacts, exported, TutorialRead,
                            current.last_note.pk)
        if current.sha_public is not None and current.sha_public != "":
            published = publish_content(
                exported, exported.load_version(current.sha_public), False)
            exported.pubdate = current.pubdate
            exported.sha_public = current.sha_public
            exported.public_version = published
            exported.save()
            published.content_public_slug = exported.slug
            published.publication_date = current.pubdate

            published.save()
            # set mapping
            map_previous = PublishedContent()
            map_previous.content_public_slug = current.slug
            map_previous.content_pk = current.pk
            map_previous.content_type = 'TUTORIAL'
            map_previous.must_redirect = True  # will send HTTP 301 if visited !
            map_previous.content = exported
            map_previous.save()
        # fix strange notification bug
        authors = list(exported.authors.all())
        reads_to_delete = ContentRead.objects\
                                     .filter(content=exported)\
                                     .exclude(user__pk__in=ContentReaction.objects
                                                                          .filter(related_content=exported)
                                                                          .exclude(author__in=authors)
                                                                          .values_list("author__pk", flat=True))
        for read in reads_to_delete.all():
            read.delete()
Beispiel #5
0
def migrate_articles():
    articles = Article.objects.all()

    if len(articles) == 0:
        return
    for i in progressbar(xrange(len(articles)), "Exporting articles", 100):
        current = articles[i]
        if not os.path.exists(current.get_path(False)):
            sys.stderr.write(
                'Invalid physical path to repository « {} », skipping\n'.
                format(current.get_path(False)))
            continue

        exported = PublishableContent()
        exported.slug = current.slug
        exported.type = "ARTICLE"
        exported.title = current.title
        exported.creation_date = current.create_at
        exported.description = current.description
        exported.sha_draft = current.sha_draft
        exported.sha_validation = current.sha_validation
        exported.licence = current.licence
        exported.js_support = current.js_support
        exported.pubdate = current.pubdate
        exported.save(
        )  # before updating `ManyToMany` relation, we need to save !

        try:
            clean_commit = copy_and_clean_repo(current.get_path(False),
                                               exported.get_repo_path(False))
        except InvalidGitRepositoryError as e:
            exported.delete()
            sys.stderr.write(
                'Repository in « {} » is invalid, skipping\n'.format(e))
            continue

        if clean_commit:
            exported.sha_draft = clean_commit

            # save clean up in old module to avoid any trouble
            current.sha_draft = clean_commit
            current.save()

        [exported.authors.add(author) for author in current.authors.all()]
        [
            exported.subcategory.add(category)
            for category in current.subcategory.all()
        ]
        new_gallery = create_gallery_for_article(exported)

        if current.image:
            # migrate image using `Image()`
            try:
                path_to_image = current.image['article_illu'].url
            except InvalidImageFormatError:
                pass
            else:
                img = Image()

                # Create a new name for our image
                filename = os.path.basename(current.image['article_illu'].url)

                # Find original name
                split = filename.split('.')
                original_filename = split[0] + '.' + split[1]

                if "None" in path_to_image:

                    # Move image in the gallery folder
                    shutil.copyfile(
                        os.path.join(MEDIA_ROOT, 'articles', 'None',
                                     original_filename),
                        os.path.join(new_gallery.get_gallery_path(),
                                     original_filename))

                    # Update image information
                    img.physical = os.path.join('galleries',
                                                str(new_gallery.pk),
                                                original_filename)
                else:
                    # Move image in the gallery folder
                    shutil.copyfile(
                        os.path.join(MEDIA_ROOT, 'articles', str(current.id),
                                     original_filename),
                        os.path.join(new_gallery.get_gallery_path(),
                                     original_filename))

                    # Update image information
                    img.physical = os.path.join('galleries',
                                                str(new_gallery.pk),
                                                original_filename)

                img.title = 'icone de l\'article'
                img.slug = slugify(filename)
                img.pubdate = datetime.now()
                img.gallery = new_gallery
                img.save()
                exported.image = img

        # now, re create the manifest.json
        versioned = exported.load_version()
        versioned.type = "ARTICLE"

        if exported.licence:
            versioned.licence = exported.licence

        split_article_in_extracts(versioned)  # create extracts from text
        exported.sha_draft = versioned.commit_changes(u'Migration version 2')
        exported.old_pk = current.pk
        exported.save()

        reacts = Reaction.objects.filter(article__pk=current.pk)\
                                 .select_related("author")\
                                 .order_by("pubdate")\
                                 .all()
        if current.last_reaction:
            export_comments(reacts, exported, ArticleRead,
                            current.last_reaction.pk)
        migrate_validation(
            exported, ArticleValidation.objects.filter(article__pk=current.pk))

        if current.sha_public is not None and current.sha_public != "":
            # set mapping
            map_previous = PublishedContent()
            map_previous.content_public_slug = current.slug
            map_previous.content_pk = current.pk
            map_previous.content_type = 'ARTICLE'
            map_previous.must_redirect = True  # will send HTTP 301 if visited !
            map_previous.content = exported
            map_previous.save()

            # publish the article !
            published = publish_content(
                exported, exported.load_version(exported.sha_draft), False)
            exported.pubdate = current.pubdate
            exported.update_date = current.update
            exported.sha_public = exported.sha_draft
            exported.public_version = published
            exported.save()
            published.content_public_slug = exported.slug
            published.publication_date = exported.pubdate
            published.save()
            # as we changed the structure we have to update the validation history. Yes, it's ugly.
            last_validation = Validation.objects.filter(
                content__pk=exported.pk).last()
            structure_validation = Validation(
                content=exported,
                version=exported.sha_public,
                comment_authors="Migration v2",
                comment_validator="yeah",
                status="ACCEPT",
                validator=last_validation.validator,
                date_proposition=datetime.now(),
                date_validation=datetime.now(),
                date_reserve=datetime.now())
            structure_validation.save()
        # fix strange notification bug
        authors = list(exported.authors.all())
        reads_to_delete = ContentRead.objects\
                                     .filter(content=exported)\
                                     .exclude(user__pk__in=ContentReaction.objects
                                                                          .filter(related_content=exported)
                                                                          .exclude(author__in=authors)
                                                                          .values_list("author__pk", flat=True))
        for read in reads_to_delete.all():
            read.delete()
Beispiel #6
0
    def test_publish_content(self):
        """test and ensure the behavior of ``publish_content()`` and ``unpublish_content()``"""

        # 1. Article:
        article = PublishableContentFactory(type='ARTICLE')

        article.authors.add(self.user_author)
        UserGalleryFactory(gallery=article.gallery,
                           user=self.user_author,
                           mode='W')
        article.licence = self.licence
        article.save()

        # populate the article
        article_draft = article.load_version()
        ExtractFactory(container=article_draft, db_object=article)
        ExtractFactory(container=article_draft, db_object=article)

        self.assertEqual(len(article_draft.children), 2)

        # publish !
        article = PublishableContent.objects.get(pk=article.pk)
        published = publish_content(article, article_draft)

        self.assertEqual(published.content, article)
        self.assertEqual(published.content_pk, article.pk)
        self.assertEqual(published.content_type, article.type)
        self.assertEqual(published.content_public_slug, article_draft.slug)
        self.assertEqual(published.sha_public, article.sha_draft)

        public = article.load_version(sha=published.sha_public,
                                      public=published)
        self.assertIsNotNone(public)
        self.assertTrue(public.PUBLIC)  # its a PublicContent object !
        self.assertEqual(public.type, published.content_type)
        self.assertEqual(public.current_version, published.sha_public)

        # test object created in database
        self.assertEqual(
            PublishedContent.objects.filter(content=article).count(), 1)
        published = PublishedContent.objects.filter(content=article).last()

        self.assertEqual(published.content_pk, article.pk)
        self.assertEqual(published.content_public_slug, article_draft.slug)
        self.assertEqual(published.content_type, article.type)
        self.assertEqual(published.sha_public, public.current_version)

        # test creation of files:
        self.assertTrue(os.path.isdir(published.get_prod_path()))
        self.assertTrue(
            os.path.isfile(
                os.path.join(published.get_prod_path(), 'manifest.json')))
        self.assertTrue(os.path.isfile(
            public.get_prod_path()))  # normally, an HTML file should exists
        self.assertIsNone(
            public.introduction
        )  # since all is in the HTML file, introduction does not exists anymore
        self.assertIsNone(public.conclusion)
        article.public_version = published
        article.save()
        # depublish it !
        unpublish_content(article)
        self.assertEqual(
            PublishedContent.objects.filter(content=article).count(),
            0)  # published object disappear
        self.assertFalse(os.path.exists(
            public.get_prod_path()))  # article was removed
        # ... For the next tests, I will assume that the unpublication works.

        # 2. Mini-tutorial → Not tested, because at this point, it's the same as an article (with a different metadata)
        # 3. Medium-size tutorial
        midsize_tuto = PublishableContentFactory(type='TUTORIAL')

        midsize_tuto.authors.add(self.user_author)
        UserGalleryFactory(gallery=midsize_tuto.gallery,
                           user=self.user_author,
                           mode='W')
        midsize_tuto.licence = self.licence
        midsize_tuto.save()

        # populate with 2 chapters (1 extract each)
        midsize_tuto_draft = midsize_tuto.load_version()
        chapter1 = ContainerFactory(parent=midsize_tuto_draft,
                                    db_objet=midsize_tuto)
        ExtractFactory(container=chapter1, db_object=midsize_tuto)
        chapter2 = ContainerFactory(parent=midsize_tuto_draft,
                                    db_objet=midsize_tuto)
        ExtractFactory(container=chapter2, db_object=midsize_tuto)

        # publish it
        midsize_tuto = PublishableContent.objects.get(pk=midsize_tuto.pk)
        published = publish_content(midsize_tuto, midsize_tuto_draft)

        self.assertEqual(published.content, midsize_tuto)
        self.assertEqual(published.content_pk, midsize_tuto.pk)
        self.assertEqual(published.content_type, midsize_tuto.type)
        self.assertEqual(published.content_public_slug,
                         midsize_tuto_draft.slug)
        self.assertEqual(published.sha_public, midsize_tuto.sha_draft)

        public = midsize_tuto.load_version(sha=published.sha_public,
                                           public=published)
        self.assertIsNotNone(public)
        self.assertTrue(public.PUBLIC)  # its a PublicContent object
        self.assertEqual(public.type, published.content_type)
        self.assertEqual(public.current_version, published.sha_public)

        # test creation of files:
        self.assertTrue(os.path.isdir(published.get_prod_path()))
        self.assertTrue(
            os.path.isfile(
                os.path.join(published.get_prod_path(), 'manifest.json')))

        self.assertTrue(
            os.path.isfile(
                os.path.join(public.get_prod_path(), public.introduction)))
        self.assertTrue(
            os.path.isfile(
                os.path.join(public.get_prod_path(), public.conclusion)))

        self.assertEqual(len(public.children), 2)
        for child in public.children:
            self.assertTrue(os.path.isfile(
                child.get_prod_path()))  # an HTML file for each chapter
            self.assertIsNone(child.introduction)
            self.assertIsNone(child.conclusion)

        # 4. Big tutorial:
        bigtuto = PublishableContentFactory(type='TUTORIAL')

        bigtuto.authors.add(self.user_author)
        UserGalleryFactory(gallery=bigtuto.gallery,
                           user=self.user_author,
                           mode='W')
        bigtuto.licence = self.licence
        bigtuto.save()

        # populate with 2 part (1 chapter with 1 extract each)
        bigtuto_draft = bigtuto.load_version()
        part1 = ContainerFactory(parent=bigtuto_draft, db_objet=bigtuto)
        chapter1 = ContainerFactory(parent=part1, db_objet=bigtuto)
        ExtractFactory(container=chapter1, db_object=bigtuto)
        part2 = ContainerFactory(parent=bigtuto_draft, db_objet=bigtuto)
        chapter2 = ContainerFactory(parent=part2, db_objet=bigtuto)
        ExtractFactory(container=chapter2, db_object=bigtuto)

        # publish it
        bigtuto = PublishableContent.objects.get(pk=bigtuto.pk)
        published = publish_content(bigtuto, bigtuto_draft)

        self.assertEqual(published.content, bigtuto)
        self.assertEqual(published.content_pk, bigtuto.pk)
        self.assertEqual(published.content_type, bigtuto.type)
        self.assertEqual(published.content_public_slug, bigtuto_draft.slug)
        self.assertEqual(published.sha_public, bigtuto.sha_draft)

        public = bigtuto.load_version(sha=published.sha_public,
                                      public=published)
        self.assertIsNotNone(public)
        self.assertTrue(public.PUBLIC)  # its a PublicContent object
        self.assertEqual(public.type, published.content_type)
        self.assertEqual(public.current_version, published.sha_public)

        # test creation of files:
        self.assertTrue(os.path.isdir(published.get_prod_path()))
        self.assertTrue(
            os.path.isfile(
                os.path.join(published.get_prod_path(), 'manifest.json')))

        self.assertTrue(
            os.path.isfile(
                os.path.join(public.get_prod_path(), public.introduction)))
        self.assertTrue(
            os.path.isfile(
                os.path.join(public.get_prod_path(), public.conclusion)))

        self.assertEqual(len(public.children), 2)
        for part in public.children:
            self.assertTrue(os.path.isdir(
                part.get_prod_path()))  # a directory for each part
            # ... and an HTML file for introduction and conclusion
            self.assertTrue(
                os.path.isfile(
                    os.path.join(public.get_prod_path(), part.introduction)))
            self.assertTrue(
                os.path.isfile(
                    os.path.join(public.get_prod_path(), part.conclusion)))

            self.assertEqual(len(part.children), 1)

            for chapter in part.children:
                # the HTML file is located in the good directory:
                self.assertEqual(part.get_prod_path(),
                                 os.path.dirname(chapter.get_prod_path()))
                self.assertTrue(os.path.isfile(
                    chapter.get_prod_path()))  # an HTML file for each chapter
                self.assertIsNone(chapter.introduction)
                self.assertIsNone(chapter.conclusion)
    def form_valid(self, form):

        user = self.request.user
        validation = Validation.objects.filter(pk=self.kwargs['pk']).last()

        if not validation:
            raise PermissionDenied

        if validation.validator != user:
            raise PermissionDenied

        if validation.status != 'PENDING_V':
            raise PermissionDenied

        # get database representation and validated version
        db_object = validation.content
        versioned = db_object.load_version(sha=validation.version)
        self.success_url = versioned.get_absolute_url(
            version=validation.version)

        try:
            published = publish_content(
                db_object,
                versioned,
                is_major_update=form.cleaned_data['is_major'])
        except FailureDuringPublication as e:
            messages.error(self.request, e.message)
        else:
            # save in database
            is_update = db_object.sha_public and db_object.sha_public != ''
            db_object.sha_public = validation.version
            db_object.source = form.cleaned_data['source']
            db_object.sha_validation = None

            db_object.public_version = published

            if form.cleaned_data[
                    'is_major'] or not is_update or db_object.pubdate is None:
                db_object.pubdate = datetime.now()

            db_object.save()

            # save validation object
            validation.comment_validator = form.cleaned_data['text']
            validation.status = "ACCEPT"
            validation.date_validation = datetime.now()
            validation.save()
            for user in db_object.authors.all():
                read = ContentRead.objects.filter(content__pk=db_object.pk,
                                                  user__pk=user.pk).first()
                if read is None:
                    read = ContentRead()
                    read.user = user
                    read.content = db_object
                    read.save()

            if is_update:
                msg = render_to_string(
                    'tutorialv2/messages/validation_accept_update.md', {
                        'content': versioned,
                        'url': published.get_absolute_url_online(),
                        'validator': validation.validator
                    })
            else:
                msg = render_to_string(
                    'tutorialv2/messages/validation_accept_content.md', {
                        'content': versioned,
                        'url': published.get_absolute_url_online(),
                        'validator': validation.validator
                    })

            bot = get_object_or_404(
                User, username=settings.ZDS_APP['member']['bot_account'])
            send_mp(bot,
                    db_object.authors.all(),
                    _(u"Publication acceptée"),
                    versioned.title,
                    msg,
                    True,
                    direct=False)

            messages.success(self.request, _(u'Le contenu a bien été validé.'))
            self.success_url = published.get_absolute_url_online()

        return super(AcceptValidation, self).form_valid(form)
Beispiel #8
0
def load_contents(cli, _type, size, fake):
    """Create v2 contents"""

    nb_contents = size * 10
    percent_contents_in_validation = 0.4
    percent_contents_with_validator = 0.2
    percent_contents_public = 0.3
    percent_mini = 0.5
    percent_medium = 0.3
    percent_big = 0.2
    nb_avg_containers_in_content = size
    nb_avg_extracts_in_content = size

    is_articles = _type == "ARTICLE"
    is_tutorials = not is_articles

    textual_type = u"article"
    if is_tutorials:
        textual_type = u"tutoriel"

    # small introduction
    cli.stdout.write(u'À créer: {:d} {}s'.format(nb_contents, textual_type),
                     ending='')

    if is_tutorials:
        cli.stdout.write(u' ({:g} petits, {:g} moyens et {:g} grands)'.format(
            nb_contents * percent_mini, nb_contents * percent_medium,
            nb_contents * percent_big))
    else:
        cli.stdout.write('')

    cli.stdout.write(u' - {:g} en brouillon'.format(
        nb_contents *
        (1 - percent_contents_public - percent_contents_in_validation -
         percent_contents_with_validator)))
    cli.stdout.write(u' - {:g} en validation (dont {:g} réservés)'.format(
        nb_contents *
        (percent_contents_in_validation + percent_contents_with_validator),
        nb_contents * percent_contents_with_validator))
    cli.stdout.write(u' - {:g} publiés'.format(nb_contents *
                                               percent_contents_public))

    tps1 = time.time()

    # create tables with 0=draft, 1=in validation, 2=reserved, 3=published
    what_to_do = []
    for i in range(nb_contents):
        what = 0  # in draft
        if i < percent_contents_public * nb_contents:
            what = 3
        elif i < (percent_contents_public +
                  percent_contents_with_validator) * nb_contents:
            what = 2
        elif i >= (1 - percent_contents_in_validation) * nb_contents:
            what = 1
        what_to_do.append(what)

    # create a table with 0=mini, 1=medium, 2=big
    content_sizes = []
    for i in range(nb_contents):
        sz = 0
        if i < percent_big * nb_contents:
            sz = 2
        elif i >= (1 - percent_medium) * nb_contents:
            sz = 1
        content_sizes.append(sz)

    # shuffle the whole thing
    random.shuffle(what_to_do)
    random.shuffle(content_sizes)

    # checks that everything is ok
    users = list(Profile.objects.all())
    nb_users = len(users)
    sub_categories = list(SubCategory.objects.all())
    nb_sub_categories = len(sub_categories)
    if nb_users == 0:
        cli.stdout.write(
            u"Il n'y a aucun membre actuellement. "
            u"Vous devez rajouter les membre dans vos fixtures (member)")
        return

    if nb_sub_categories == 0:
        cli.stdout.write(
            u"Il n'y a aucune catégories actuellement."
            u"Vous devez rajouter les catégories dans vos fixtures (category_content)"
        )
        return

    perms = list(
        Permission.objects.filter(codename__startswith='change_').all())
    staffs = list(User.objects.filter(groups__permissions__in=perms).all())
    nb_staffs = len(staffs)

    if nb_staffs == 0:
        cli.stdout.write(
            u"Il n'y a aucun staff actuellement."
            u"Vous devez rajouter les staffs dans vos fixtures (staff)")
        return

    licenses = list(Licence.objects.all())
    nb_licenses = len(licenses)

    if nb_licenses == 0:
        cli.stdout.write(
            u"Il n'y a aucune licence actuellement."
            u"Vous devez rajouter les licences dans vos fixtures (category_content)"
        )
        return

    # create and so all:
    for i in range(nb_contents):
        sys.stdout.write("Création {} : {}/{}  \r".format(
            textual_type, i + 1, nb_contents))

        current_size = content_sizes[i]
        to_do = what_to_do[i]

        # creation:
        content = PublishableContentFactory(type=_type,
                                            title=fake.text(max_nb_chars=60),
                                            description=fake.sentence(
                                                nb_words=15,
                                                variable_nb_words=True))

        versioned = content.load_version()

        if current_size == 0 or is_articles:
            for j in range(random.randint(1, nb_avg_extracts_in_content * 2)):
                ExtractFactory(container=versioned,
                               title=fake.text(max_nb_chars=60),
                               light=False)
        else:
            for j in range(random.randint(1,
                                          nb_avg_containers_in_content * 2)):
                container = ContainerFactory(parent=versioned,
                                             title=fake.text(max_nb_chars=60))

                if current_size == 1:  # medium size tutorial
                    for k in range(
                            random.randint(1, nb_avg_extracts_in_content * 2)):
                        ExtractFactory(container=container,
                                       title=fake.text(max_nb_chars=60),
                                       light=False)
                else:  # big-size tutorial
                    for k in range(
                            random.randint(1,
                                           nb_avg_containers_in_content * 2)):
                        subcontainer = ContainerFactory(
                            parent=container, title=fake.text(max_nb_chars=60))

                        for l in range(
                                random.randint(1, nb_avg_extracts_in_content *
                                               2)):
                            ExtractFactory(container=subcontainer,
                                           title=fake.text(max_nb_chars=60),
                                           light=False)

        # add some informations:
        author = users[random.randint(0, nb_users - 1)].user
        content.authors.add(author)
        UserGalleryFactory(gallery=content.gallery, mode="W", user=author)
        content.licence = licenses[random.randint(0, nb_licenses - 1)]
        content.sha_draft = versioned.sha_draft
        content.subcategory.add(sub_categories[random.randint(
            0, nb_sub_categories - 1)])
        content.save()

        # then, validation if needed:
        if to_do > 0:
            valid = CValidation(content=content,
                                version=content.sha_draft,
                                date_proposition=datetime.now(),
                                status="PENDING")
            valid.comment_validator = fake.text(max_nb_chars=200)

            content.sha_validation = content.sha_draft

            if to_do > 1:  # reserve validation
                valid.date_reserve = datetime.now()
                valid.validator = staffs[random.randint(0, nb_staffs - 1)]
                valid.status = "PENDING_V"
            if to_do > 2:  # publish content
                valid.comment_validator = fake.text(max_nb_chars=80)
                valid.status = "ACCEPT"
                valid.date_validation = datetime.now()
                content.sha_public = content.sha_draft

                published = publish_content(content, versioned)
                content.public_version = published

            valid.save()
            content.save()

        sys.stdout.flush()

    tps2 = time.time()
    cli.stdout.write(u"\nFait en {:.3f} sec".format(tps2 - tps1))