def form_valid(self, form): old_validation = Validation.objects.filter( content__pk=self.object.pk, status__in=['PENDING', 'PENDING_V']).first() if old_validation: # if an old validation exists, cancel it ! old_validator = old_validation.validator old_validation.status = 'CANCEL' old_validation.date_validation = datetime.now() old_validation.save() else: old_validator = None # create a "validation" object validation = Validation() validation.content = self.object validation.date_proposition = datetime.now() validation.comment_authors = form.cleaned_data['text'] validation.version = form.cleaned_data['version'] if old_validator: validation.validator = old_validator validation.status = 'PENDING_V' validation.save() # warn the former validator that an update has been made, if any if old_validator: bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) msg = render_to_string( 'tutorialv2/messages/validation_change.md', { 'content': self.versioned_object, 'validator': validation.validator.username, 'url': self.versioned_object.get_absolute_url() + '?version=' + form.cleaned_data['version'], 'url_history': reverse('content:history', args=[self.object.pk, self.object.slug]) }) send_mp( bot, [old_validator], _(u"Une nouvelle version a été envoyée en validation."), self.versioned_object.title, msg, False, ) # update the content with the source and the version of the validation self.object.source = form.cleaned_data["source"] self.object.sha_validation = validation.version self.object.save() messages.success(self.request, _(u"Votre demande de validation a été transmise à l'équipe.")) self.success_url = self.versioned_object.get_absolute_url(version=self.sha) return super(AskValidationForContent, self).form_valid(form)
def migrate_validation(exported_content, validation_queryset): for old_validation in validation_queryset.all(): exported_validation = Validation(content=exported_content, version=old_validation.version, comment_authors=old_validation.comment_authors, comment_validator=old_validation.comment_validator, status=old_validation.status, validator=old_validation.validator, date_proposition=old_validation.date_proposition, date_validation=old_validation.date_validation, date_reserve=old_validation.date_reserve) exported_validation.save()
def setUp(self): self.licence = LicenceFactory() self.subcategory = SubCategoryFactory() self.author = ProfileFactory() self.user = ProfileFactory() self.staff = StaffProfileFactory() self.tuto = PublishableContentFactory(type='TUTORIAL') self.tuto.authors.add(self.author.user) self.tuto.licence = self.licence self.tuto.subcategory.add(self.subcategory) self.tuto.save() self.validation = Validation( content=self.tuto, version=self.tuto.sha_draft, comment_authors='bla', date_proposition=datetime.now(), ) self.validation.save() self.topic = send_mp(author=self.author.user, users=[], title='Title', text='Testing', subtitle='', leave=False) self.topic.participants.add(self.user.user) send_message_mp(self.user.user, self.topic, 'Testing') # humane_delta test periods = ((1, 0), (2, 1), (3, 7), (4, 30), (5, 360)) cont = dict() cont['date_today'] = periods[0][0] cont['date_yesterday'] = periods[1][0] cont['date_last_week'] = periods[2][0] cont['date_last_month'] = periods[3][0] cont['date_last_year'] = periods[4][0] self.context = Context(cont)
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()
class InterventionsTest(TestCase): """ This test uses quite complicated paths to check number of notifications: 1. Create private topics and do stuff with them 2. User signs in 3. Render the home page 4. Check the number of unread private messages on home page source code This because a correct test of this function requires a complete context (or it behaves strangely) """ def setUp(self): self.licence = LicenceFactory() self.subcategory = SubCategoryFactory() self.author = ProfileFactory() self.user = ProfileFactory() self.staff = StaffProfileFactory() self.tuto = PublishableContentFactory(type='TUTORIAL') self.tuto.authors.add(self.author.user) self.tuto.licence = self.licence self.tuto.subcategory.add(self.subcategory) self.tuto.save() self.validation = Validation( content=self.tuto, version=self.tuto.sha_draft, comment_authors='bla', date_proposition=datetime.now(), ) self.validation.save() self.topic = send_mp(author=self.author.user, users=[], title='Title', text='Testing', subtitle='', leave=False) self.topic.participants.add(self.user.user) send_message_mp(self.user.user, self.topic, 'Testing') # humane_delta test periods = ((1, 0), (2, 1), (3, 7), (4, 30), (5, 360)) cont = dict() cont['date_today'] = periods[0][0] cont['date_yesterday'] = periods[1][0] cont['date_last_week'] = periods[2][0] cont['date_last_month'] = periods[3][0] cont['date_last_year'] = periods[4][0] self.context = Context(cont) def test_interventions_privatetopics(self): self.assertTrue( self.client.login(username=self.author.user.username, password='******')) response = self.client.post(reverse('homepage')) self.assertEqual(200, response.status_code) self.assertContains(response, '<span class="notif-count">1</span>', html=True) self.client.logout() self.assertTrue( self.client.login(username=self.user.user.username, password='******')) response = self.client.post(reverse('homepage')) self.assertEqual(200, response.status_code) self.assertContains(response, '<span class="notif-count">1</span>', html=True) def test_interventions_privatetopics_author_leave(self): # profile1 (author) leave topic move = self.topic.participants.first() self.topic.author = move self.topic.participants.remove(move) self.topic.save() self.assertTrue( self.client.login(username=self.user.user.username, password='******')) response = self.client.post(reverse('homepage')) self.assertEqual(200, response.status_code) self.assertContains(response, '<span class="notif-count">1</span>', html=True) def test_interventions_waiting_contents(self): # Login as staff self.assertTrue( self.client.login(username=self.staff.user.username, password='******')) # check that the number of waiting tutorials is correct response = self.client.post(reverse('homepage')) self.assertEqual(200, response.status_code) self.assertContains(response, '(1)') # Mark the content as reserved self.validation.status = 'PENDING_V' self.validation.save() # and check that the count was removed response = self.client.post(reverse('homepage')) self.assertEqual(200, response.status_code) self.assertNotContains(response, '(1)') def test_interventions_humane_delta(self): tr = Template('{% load interventions %}' '{{ date_today|humane_delta }}').render(self.context) self.assertEqual(u'Aujourd'hui', tr) tr = Template('{% load interventions %}' '{{ date_yesterday|humane_delta }}').render(self.context) self.assertEqual(u'Hier', tr) tr = Template('{% load interventions %}' '{{ date_last_week|humane_delta }}').render(self.context) self.assertEqual(u'Les 7 derniers jours', tr) tr = Template('{% load interventions %}' '{{ date_last_month|humane_delta }}').render( self.context) self.assertEqual(u'Les 30 derniers jours', tr) tr = Template('{% load interventions %}' '{{ date_last_year|humane_delta }}').render(self.context) self.assertEqual(u'Plus ancien', tr)
def form_valid(self, form): # get database representation and validated version db_object = self.object versioned = self.versioned_object # get initial git path old_git_path = db_object.get_repo_path() # store data for later authors = db_object.authors.all() subcats = db_object.subcategory.all() tags = db_object.tags.all() article = PublishableContent(title=db_object.title, type='ARTICLE', creation_date=datetime.now(), sha_public=db_object.sha_public, public_version=None, licence=db_object.licence, sha_validation=db_object.sha_public, sha_draft=db_object.sha_public, image=db_object.image, source=db_object.source ) opinion_url = db_object.get_absolute_url_online() article.save() # add M2M objects for author in authors: article.authors.add(author) for subcat in subcats: article.subcategory.add(subcat) for tag in tags: article.tags.add(tag) article.save() # add information about the conversion to the original opinion db_object.converted_to = article db_object.save() # clone the repo clone_repo(old_git_path, article.get_repo_path()) versionned_article = article.load_version(sha=article.sha_validation) # mandatory to avoid path collision versionned_article.slug = article.slug article.sha_validation = versionned_article.repo_update(versionned_article.title, versionned_article.get_introduction(), versionned_article.get_conclusion()) article.sha_draft = article.sha_validation article.save() # ask for validation validation = Validation() validation.content = article validation.date_proposition = datetime.now() validation.comment_authors = _('Promotion du billet « [{0}]({1}) » en article par [{2}]({3}).'.format( article.title, article.get_absolute_url_online(), self.request.user.username, self.request.user.profile.get_absolute_url() )) validation.version = article.sha_validation validation.save() # creating the gallery gal = Gallery() gal.title = db_object.gallery.title gal.slug = db_object.gallery.slug gal.pubdate = datetime.now() gal.save() article.gallery = gal # save updates article.save() article.ensure_author_gallery() # send message to user msg = render_to_string( 'tutorialv2/messages/opinion_promotion.md', { 'content': versioned, 'url': opinion_url, }) bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, article.authors.all(), _('Billet promu en article'), versionned_article.title, msg, True, direct=False, hat=get_hat_from_settings('validation'), ) self.success_url = db_object.get_absolute_url() messages.success(self.request, _('Le billet a bien été promu en article et est en attente de validation.')) return super(PromoteOpinionToArticle, self).form_valid(form)