def solve_alert(request): # only staff can move topic if not request.user.has_perm('article.change_reaction'): raise PermissionDenied alert = get_object_or_404(Alert, pk=request.POST['alert_pk']) reaction = Reaction.objects.get(pk=alert.comment.id) bot = get_object_or_404(User, username=settings.BOT_ACCOUNT) msg = u'Bonjour {0},\n\nVous recevez ce message car vous avez ' u'signalé le message de *{1}*, dans l\'article [{2}]({3}). ' u'Votre alerte a été traitée par **{4}** et il vous a laissé ' u'le message suivant :\n\n`{5}`\n\n\nToute l\'équipe de ' u'la modération vous remercie'.format( alert.author.username, reaction.author.username, reaction.article.title, settings.SITE_URL + reaction.get_absolute_url(), request.user.username, request.POST['text']) send_mp( bot, [ alert.author], u"Résolution d'alerte : {0}".format( reaction.article.title), "", msg, False) alert.delete() messages.success( request, u'L\'alerte a bien été résolue') return redirect(reaction.get_absolute_url())
def solve_alert(request): # only staff can move topic if not request.user.has_perm("forum.change_post"): raise PermissionDenied alert = get_object_or_404(Alert, pk=request.POST["alert_pk"]) post = Post.objects.get(pk=alert.comment.id) bot = get_object_or_404(User, username=settings.BOT_ACCOUNT) msg = \ (u'Bonjour {0},' u'Vous recevez ce message car vous avez signalé le message de *{1}*, ' u'dans le sujet [{2}]({3}). Votre alerte a été traitée par **{4}** ' u'et il vous a laissé le message suivant :' u'\n\n`{5}`\n\nToute l\'équipe de la modération vous remercie'.format( alert.author.username, post.author.username, post.topic.title, settings.SITE_URL + post.get_absolute_url(), request.user.username, request.POST["text"],)) send_mp( bot, [alert.author], u"Résolution d'alerte : {0}".format(post.topic.title), "", msg, False, ) alert.delete() messages.success(request, u"L'alerte a bien été résolue") return redirect(post.get_absolute_url())
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.date_reserve = old_validation.date_reserve 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], _('Une nouvelle version a été envoyée en validation.'), self.versioned_object.title, msg, False, hat=get_hat_from_settings('validation'), ) # 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, _("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 activate_account(request): """Activate an account with a token.""" try: token = request.GET['token'] except KeyError: return redirect(reverse('homepage')) token = get_object_or_404(TokenRegister, token=token) usr = token.user # User can't confirm their request if their account is already active if usr.is_active: return render(request, 'member/register/token_already_used.html') # User can't confirm their request if it is too late if datetime.now() > token.date_end: return render(request, 'member/register/token_failed.html', {'token': token}) usr.is_active = True usr.save() # Send welcome message bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) msg = render_to_string( 'member/messages/account_activated.md', { 'username': usr.username, 'site_name': settings.ZDS_APP['site']['literal_name'], 'library_url': settings.ZDS_APP['site']['url'] + reverse('publication:list'), 'opinions_url': settings.ZDS_APP['site']['url'] + reverse('opinion:list'), 'forums_url': settings.ZDS_APP['site']['url'] + reverse('cats-forums-list') } ) send_mp(bot, [usr], _('Bienvenue sur {}').format(settings.ZDS_APP['site']['literal_name']), _('Le manuel du nouveau membre'), msg, False, True, False, hat=get_hat_from_settings('moderation')) token.delete() # Create an alert for the staff if it's a new provider if usr.email: provider = usr.email.split('@')[-1].lower() if not NewEmailProvider.objects.filter(provider=provider).exists() \ and not User.objects.filter(email__iendswith='@{}'.format(provider)) \ .exclude(pk=usr.pk).exists(): NewEmailProvider.objects.create(user=usr, provider=provider, use=NEW_ACCOUNT) form = LoginForm(initial={'username': usr.username}) return render(request, 'member/register/token_success.html', {'usr': usr, 'form': form})
def form_valid(self, form): versioned = self.versioned_object if form.cleaned_data['version'] != self.object.sha_public: raise PermissionDenied validation = Validation.objects.filter( content=self.object, version=self.object.sha_public, status='ACCEPT').prefetch_related('content__authors').last() if not validation: raise PermissionDenied unpublish_content(self.object) validation.status = 'PENDING' validation.validator = None # remove previous validator validation.date_validation = None validation.save() self.object.sha_public = None self.object.sha_validation = validation.version self.object.pubdate = None self.object.save() # send PM msg = render_to_string( 'tutorialv2/messages/validation_revoke.md', { 'content': versioned, 'url': versioned.get_absolute_url() + '?version=' + validation.version, 'admin': self.request.user, 'message_reject': '\n'.join(['> ' + a for a in form.cleaned_data['text'].split('\n')]) }) bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, validation.content.authors.all(), _('Dépublication'), validation.content.title, msg, True, direct=False, hat=get_hat_from_settings('validation'), ) messages.success(self.request, _('Le contenu a bien été dépublié.')) self.success_url = self.versioned_object.get_absolute_url() + '?version=' + validation.version return super(RevokeValidation, self).form_valid(form)
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 # reject validation: validation.comment_validator = form.cleaned_data['text'] validation.status = 'REJECT' validation.date_validation = datetime.now() validation.save() validation.content.sha_validation = None validation.content.save() # send PM versioned = validation.content.load_version(sha=validation.version) msg = render_to_string( 'tutorialv2/messages/validation_reject.md', { 'content': versioned, 'url': versioned.get_absolute_url() + '?version=' + validation.version, 'validator': validation.validator, 'message_reject': '\n'.join(['> ' + a for a in form.cleaned_data['text'].split('\n')]) }) bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, validation.content.authors.all(), _('Rejet de la demande de publication').format(), validation.content.title, msg, True, direct=False, hat=get_hat_from_settings('validation'), ) messages.info(self.request, _('Le contenu a bien été refusé.')) self.success_url = reverse('validation:list') return super(RejectValidation, self).form_valid(form)
def form_valid(self, form): # get database representation and validated version db_object = self.object versioned = self.versioned_object self.success_url = versioned.get_absolute_url_online() if not db_object.in_public(): raise Http404('This opinion is not published.') elif PickListOperation.objects.filter(content=self.object, is_effective=True).exists() \ and form.cleaned_data['operation'] != 'REMOVE_PUB': raise PermissionDenied('There is already an effective operation for this content.') try: PickListOperation.objects.filter(content=self.object).update(is_effective=False, canceler_user=self.request.user) PickListOperation.objects.create(content=self.object, operation=form.cleaned_data['operation'], staff_user=self.request.user, operation_date=datetime.now(), version=db_object.sha_public) if form.cleaned_data['operation'] == 'REMOVE_PUB': unpublish_content(self.object, moderator=self.request.user) # send PM msg = render_to_string( 'tutorialv2/messages/validation_unpublish_opinion.md', { 'content': versioned, 'url': versioned.get_absolute_url(), 'moderator': self.request.user, }) bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, versioned.authors.all(), _('Billet modéré'), versioned.title, msg, True, direct=False, hat=get_hat_from_settings('moderation'), ) except ValueError: logger.exception('Could not %s the opinion %s', form.cleaned_data['operation'], str(self.object)) return HttpResponse(json.dumps({'result': 'FAIL', 'reason': str(_('Mauvaise opération'))}), status=400) if not form.cleaned_data['redirect']: return HttpResponse(json.dumps({'result': 'OK'})) else: self.success_url = reverse('opinion:list') messages.success(self.request, _('Le billet a bien été modéré.')) return super().form_valid(form)
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_send_an_email_when_we_specify_it(self): """ When the user asked to be notified via email, we actually send the email when a topic is created. """ settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' self.assertEqual(0, len(mail.outbox)) topic = send_mp(author=self.user1, users=[self.user2, self.user3], title='Testing', subtitle='', text='', send_by_mail=True, leave=False) self.assertEqual(1, len(mail.outbox)) self.user1.profile.email_for_answer = True self.user1.profile.save() self.user2.profile.email_for_answer = True self.user2.profile.save() self.user3.profile.email_for_answer = False self.user3.profile.save() send_message_mp(self.user2, topic, '', send_by_mail=True) subscriptions = PrivateTopicAnswerSubscription.objects.filter(user=self.user2) self.assertTrue(subscriptions.last().by_email) self.assertEqual(2, len(mail.outbox)) self.user1.profile.email_for_answer = False self.user1.profile.save() send_message_mp(self.user2, topic, '', send_by_mail=True) self.assertEqual(2, len(mail.outbox))
def test_generate_a_notification_after_new_post(self): """ When a user posts on a private topic, we generate a notification for all participants. """ topic = send_mp(author=self.user1, users=[self.user2, self.user3], title="Testing", subtitle="", text="", leave=False) notifications = Notification.objects.get_unread_notifications_of( self.user2) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first()) self.assertEqual(topic.last_message, notifications.first().content_object) mark_read(topic, self.user2) notifications = Notification.objects.get_unread_notifications_of( self.user2) self.assertEqual(0, len(notifications)) send_message_mp(self.user3, topic, "") notifications = Notification.objects.get_unread_notifications_of( self.user2) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first()) self.assertEqual(topic.last_message, notifications.first().content_object)
def test_generate_a_notification_for_all_participants(self): """ When we create a topic, all participants have a notification for the last message. """ subscriptions = PrivateTopicAnswerSubscription.objects.filter(user=self.user2) self.assertEqual(0, len(subscriptions)) subscriptions = PrivateTopicAnswerSubscription.objects.filter(user=self.user3) self.assertEqual(0, len(subscriptions)) topic = send_mp(author=self.user1, users=[self.user2, self.user3], title='Testing', subtitle='', text='', leave=False) subscriptions = PrivateTopicAnswerSubscription.objects.filter(user=self.user2) self.assertEqual(1, len(subscriptions)) self.assertEqual(topic, subscriptions.first().content_object) subscriptions = PrivateTopicAnswerSubscription.objects.filter(user=self.user3) self.assertEqual(1, len(subscriptions)) self.assertEqual(topic, subscriptions.first().content_object) notification = Notification.objects.get_unread_notifications_of(self.user2).first() self.assertIsNotNone(notification) self.assertEqual(topic.last_message, notification.content_object) notification = Notification.objects.get_unread_notifications_of(self.user3).first() self.assertIsNotNone(notification) self.assertEqual(topic.last_message, notification.content_object)
def test_remove_notifications_when_a_user_leave_private_topic(self): """ When a user leaves a private topic, we mark the current notification as read if it exists. """ topic = send_mp(author=self.user1, users=[self.user2], title='Testing', subtitle='', text='', leave=False) notifications = Notification.objects.get_unread_notifications_of(self.user2) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first()) self.assertEqual(topic.last_message, notifications.first().content_object) self.assertIsNotNone(PrivateTopicAnswerSubscription.objects.get_existing(self.user2, topic, is_active=True)) send_message_mp(self.user2, topic, 'Test') topic.participants.remove(self.user2) topic.save() self.assertEqual(0, len(Notification.objects.get_unread_notifications_of(self.user2))) self.assertIsNotNone(PrivateTopicAnswerSubscription.objects.get_existing(self.user2, topic, is_active=False)) self.assertEqual(1, len(Notification.objects.get_unread_notifications_of(self.user1))) response = self.client.post(reverse('mp-delete', args=[topic.pk, topic.slug]), follow=True) self.assertEqual(200, response.status_code) self.assertEqual(0, len(Notification.objects.get_unread_notifications_of(self.user1)))
def form_valid(self, form): _type = _("de l'article") if self.object.is_tutorial: _type = _("du tutoriel") elif self.object.is_opinion: _type = _("du billet") bot = get_object_or_404( User, username=settings.ZDS_APP["member"]["bot_account"]) all_authors_pk = [author.pk for author in self.object.authors.all()] for user in form.cleaned_data["users"]: if user.pk not in all_authors_pk: self.object.authors.add(user) if self.object.validation_private_message: self.object.validation_private_message.add_participant( user) all_authors_pk.append(user.pk) if user != self.request.user: url_index = reverse(self.object.type.lower() + ":find-" + self.object.type.lower(), args=[user.pk]) send_mp( bot, [user], format_lazy("{}{}", _("Ajout à la rédaction "), _type), self.versioned_object.title, render_to_string( "tutorialv2/messages/add_author_pm.md", { "content": self.object, "type": _type, "url": self.object.get_absolute_url(), "index": url_index, "user": user.username, }, ), hat=get_hat_from_settings("validation"), ) UserGallery(gallery=self.object.gallery, user=user, mode=GALLERY_WRITE).save() self.object.save() self.success_url = self.object.get_absolute_url() return super().form_valid(form)
def form_valid(self, form): db_object = self.object versioned = self.versioned_object self.success_url = versioned.get_absolute_url_online() if not db_object.sha_picked: raise PermissionDenied( 'Impossible de retirer des billets choisis un billet pas choisi.' ) if db_object.sha_picked != form.cleaned_data['version']: raise PermissionDenied( 'Impossible de retirer des billets choisis un billet pas choisi.' ) db_object.sha_picked = None db_object.save() PickListOperation.objects\ .filter(operation='PICK', is_effective=True, content=self.object)\ .first().cancel(self.request.user) # mark to reindex to boost correctly in the search self.public_content_object.es_flagged = True self.public_content_object.save() msg = render_to_string( 'tutorialv2/messages/validation_invalid_opinion.md', { 'content': versioned, 'url': versioned.get_absolute_url(), 'admin': self.request.user, 'message_reject': '\n'.join( ['> ' + a for a in form.cleaned_data['text'].split('\n')]) }) bot = get_object_or_404( User, username=settings.ZDS_APP['member']['bot_account']) if not self.object.validation_private_message: self.object.validation_private_message = send_mp( bot, versioned.authors.all(), self.object.validation_message_title, versioned.title, msg, True, direct=False, hat=get_hat_from_settings('moderation'), ) self.object.save(force_slug_update=False) else: send_message_mp(bot, self.object.validation_private_message, msg) messages.success( self.request, _('Le contenu a bien été enlevé de la liste des billets choisis.')) return super(UnpickOpinion, self).form_valid(form)
def post(self, request, *args, **kwargs): validation = get_object_or_404(Validation, pk=kwargs['pk']) if validation.validator: validation.validator = None validation.date_reserve = None validation.status = 'PENDING' validation.save() messages.info(request, _("Ce contenu n'est plus réservé.")) return redirect(reverse('validation:list')) else: validation.validator = request.user validation.date_reserve = datetime.now() validation.status = 'PENDING_V' validation.save() versioned = validation.content.load_version(sha=validation.version) msg = render_to_string( 'tutorialv2/messages/validation_reserve.md', { 'content': versioned, 'url': versioned.get_absolute_url() + '?version=' + validation.version, }) authors = list(validation.content.authors.all()) if validation.validator in authors: authors.remove(validation.validator) if len(authors) > 0: send_mp( validation.validator, authors, _('Contenu réservé - {0}').format(validation.content.title), validation.content.title, msg, True, leave=False, direct=False, mark_as_read=True, hat=get_hat_from_settings('validation'), ) messages.info(request, _('Ce contenu a bien été réservé par {0}.').format(request.user.username)) return redirect( reverse('content:view', args=[validation.content.pk, validation.content.slug]) + '?version=' + validation.version )
def create(self, validated_data): # This hack is necessary because `text` isn't a field of PrivateTopic. self._fields.pop('text') return send_mp( self.context.get('request').user, validated_data.get('participants'), validated_data.get('title'), validated_data.get('subtitle') or '', validated_data.get('text'), True, False)
def form_valid(self, form): versioned = self.versioned_object user = self.request.user if user not in versioned.authors.all( ) and not user.has_perm('tutorialv2.change_validation'): raise PermissionDenied if form.cleaned_data['version'] != self.object.sha_public: raise PermissionDenied unpublish_content(self.object, moderator=self.request.user) # send PM msg = render_to_string( 'tutorialv2/messages/validation_revoke.md', { 'content': versioned, 'url': versioned.get_absolute_url(), 'admin': user, 'message_reject': '\n'.join( ['> ' + a for a in form.cleaned_data['text'].split('\n')]) }) bot = get_object_or_404( User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, versioned.authors.all(), _('Dépublication'), versioned.title, msg, True, direct=False, hat=get_hat_from_settings('moderation'), ) messages.success(self.request, _('Le contenu a bien été dépublié.')) self.success_url = self.versioned_object.get_absolute_url() return super(UnpublishOpinion, self).form_valid(form)
def solve_hat_request(request, request_pk): """ Solve a hat request by granting or denying the requested hat according to moderator's decision. """ hat_request = get_object_or_404(HatRequest, pk=request_pk) if 'grant' in request.POST: # hat is granted hat, created = Hat.objects.get_or_create(name__iexact=hat_request.hat, defaults={'name': hat_request.hat}) if created: messages.success(request, _('La casquette « {} » a été créée.').format(hat_request.hat)) hat_request.user.profile.hats.add(hat) messages.success(request, _('La casquette « {0} » a été accordée à {1}.').format( hat_request.hat, hat_request.user.username)) else: messages.success(request, _('La casquette « {0} » a été refusée à {1}.').format( hat_request.hat, hat_request.user.username)) # send a PM to notify member about this decision bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) msg = render_to_string( 'member/messages/hat_request_decision.md', { 'is_granted': 'grant' in request.POST, 'moderator': request.user, 'hat': hat_request.hat, 'site_name': settings.ZDS_APP['site']['literal_name'], 'comment': request.POST.get('comment', '')[:1000] } ) send_mp(bot, [hat_request.user], _('Casquette « {} »').format(hat_request.hat), '', msg, False, True, False, hat=get_hat_from_settings('hats_management')) hat_request.delete() return redirect('requested-hats')
def form_valid(self, form): db_object = self.object versioned = self.versioned_object self.success_url = versioned.get_absolute_url_online() if not db_object.sha_picked: raise PermissionDenied('Impossible de retirer des billets choisis un billet pas choisi.') if db_object.sha_picked != form.cleaned_data['version']: raise PermissionDenied('Impossible de retirer des billets choisis un billet pas choisi.') db_object.sha_picked = None db_object.save() PickListOperation.objects\ .filter(operation='PICK', is_effective=True, content=self.object)\ .first().cancel(self.request.user) # mark to reindex to boost correctly in the search self.public_content_object.es_flagged = True self.public_content_object.save() msg = render_to_string( 'tutorialv2/messages/validation_invalid_opinion.md', { 'content': versioned, 'url': versioned.get_absolute_url(), 'admin': self.request.user, 'message_reject': '\n'.join(['> ' + a for a in form.cleaned_data['text'].split('\n')]) }) bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, versioned.authors.all(), _('Billet retiré de la liste des billets choisis'), versioned.title, msg, True, direct=False, hat=get_hat_from_settings('moderation'), ) messages.success(self.request, _('Le contenu a bien été enlevé de la liste des billets choisis.')) return super(UnpickOpinion, self).form_valid(form)
def alert_authors(self): """ Send a private message to all authors (with a `PublishableContent`) for new tags system. :return: None """ bot = get_object_or_404( User, username=settings.ZDS_APP["member"]["bot_account"]) bots = [ get_object_or_404( User, username=settings.ZDS_APP["member"]["bot_account"]), get_object_or_404( User, username=settings.ZDS_APP["member"]["anonymous_account"]), get_object_or_404( User, username=settings.ZDS_APP["member"]["external_account"]), ] users = [] contents = PublishableContent.objects.all() for content in contents: authors = content.authors.all() for author in authors: if author not in users and author not in bots: users.append(author) for user in users: msg = ( "Bonjour,\n\nDepuis la dernière version de Zeste de Savoir, tous les contenus (articles, tutori" "els et bientôt tribunes libres) possèdent maintenant une nouvelle classification ([ZEP-25](https:/" "/zestedesavoir.com/forums/sujet/2378/zep-25-categorisation-des-articles-et-tutoriels/)). Les **tag" "s** ont fait leur apparition et les catégories ont été revues afin de faciliter et d'aléger cette" " classification.\n\nLes anciennes catégories ont été transformées en tags et de nouvelles catégori" "es plus générales ont été ajoutés. L'équipe de Zeste de Savoir va ou a déjà changé les catégories" " des contenus publiés.\n\nNous vous invitons à vérifier les catégories de vos articles et tutoriel" "s mais également la pertinence des tags et en ajouter si besoin.\n\n\nNous restons à votre disposi" "tion et votre écoute pour toutes suggestions ou remarques,\n\nL'équipe de Zeste de Savoir" ) send_mp( bot, [user], "Changement de classification du contenu sur Zeste de Savoir", "Ce qui change pour vous en tant qu'auteur", msg, ) self.stdout.write(f"[ZEP-25] : PM send to {user}")
def form_valid(self, form): versioned = self.versioned_object user = self.request.user if user not in versioned.authors.all( ) and not user.has_perm('tutorialv2.change_validation'): raise PermissionDenied if form.cleaned_data['version'] != self.object.sha_public: raise PermissionDenied unpublish_content(self.object, moderator=self.request.user) if [self.request.user] != list(self.object.authors.all()): # Sends PM if the deleter is not the author # (or is not the only one) of the opinion. msg = render_to_string( 'tutorialv2/messages/validation_revoke.md', { 'content': versioned, 'url': versioned.get_absolute_url(), 'admin': user, 'message_reject': '\n'.join([ '> ' + a for a in form.cleaned_data['text'].split('\n') ]) }) bot = get_object_or_404( User, username=settings.ZDS_APP['member']['bot_account']) if not self.object.validation_private_message: self.object.validation_private_message = send_mp( bot, versioned.authors.all(), self.object.validation_message_title, versioned.title, msg, True, direct=False, hat=get_hat_from_settings('moderation'), ) self.object.save(force_slug_update=False) else: send_message_mp(bot, self.object.validation_private_message, msg, hat=get_hat_from_settings('moderation'), no_notification_for=self.request.user) messages.success(self.request, _('Le contenu a bien été dépublié.')) self.success_url = self.versioned_object.get_absolute_url() return super(UnpublishOpinion, self).form_valid(form)
def post(self, request, *args, **kwargs): validation = get_object_or_404(Validation, pk=kwargs["pk"]) if validation.validator: validation.validator = None validation.date_reserve = None validation.status = "PENDING" validation.save() messages.info(request, _(u"Ce contenu n'est plus réservé.")) return redirect(reverse("validation:list")) else: validation.validator = request.user validation.date_reserve = datetime.now() validation.status = "PENDING_V" validation.save() versioned = validation.content.load_version(sha=validation.version) msg = render_to_string( 'tutorialv2/messages/validation_reserve.md', { 'content': versioned, 'url': versioned.get_absolute_url() + '?version=' + validation.version, }) send_mp(validation.validator, validation.content.authors.all(), _(u"Contenu réservé - {0}").format( validation.content.title), validation.content.title, msg, True, direct=False) messages.info( request, _(u"Ce contenu a bien été réservé par {0}.").format( request.user.username)) return redirect( reverse("content:view", args=[validation.content.pk, validation.content.slug]) + "?version=" + validation.version)
def solve(alert, note, user, text_solve=''): """Solve alert (delete it) and send a PM if a explanation is given :param alert: the alert to solve :type alert: Alert :param note: the note on which the alert has been raised :type note: ContentReaction :param text_solve: explanation :type text_solve: str """ if text_solve: bot = get_object_or_404( User, username=settings.ZDS_APP['member']['bot_account']) msg = render_to_string( 'tutorialv2/messages/resolve_alert.md', { 'content': note.related_content, 'url': note.related_content.get_absolute_url_online(), 'name': alert.author.username, 'target_name': note.author.username, 'modo_name': user.username, 'message': '\n'.join(['> ' + line for line in text_solve.split('\n')]), 'alert_text': '\n'.join(['> ' + line for line in alert.text.split('\n')]) }) send_mp( bot, [alert.author], _(u"Résolution d'alerte"), note.related_content.title, msg, False, ) alert.delete()
def solve_alert(request): """ Solves an alert (i.e. delete it from alert list) and sends an email to the user that created the alert, if the resolver leaves a comment. This can only be done by staff. """ if not request.user.has_perm("forum.change_post"): raise PermissionDenied alert = get_object_or_404(Alert, pk=request.POST["alert_pk"]) post = Post.objects.get(pk=alert.comment.id) if "text" in request.POST and request.POST["text"] != "": bot = get_object_or_404( User, username=settings.ZDS_APP['member']['bot_account']) msg = render_to_string( "forum/messages/solve_alert_pm.md", { 'alert_author': alert.author.username, 'post_author': post.author.username, 'post_title': post.topic.title, 'post_url': settings.ZDS_APP['site']['url'] + post.get_absolute_url(), 'staff_name': request.user.username, 'staff_message': request.POST["text"] }) send_mp( bot, [alert.author], u"Résolution d'alerte : {0}".format(post.topic.title), "", msg, False, ) alert.delete() messages.success(request, u"L'alerte a bien été résolue.") return redirect(post.get_absolute_url())
def create(self, validated_data): # This hack is necessary because `text` isn't a field of PrivateTopic. self._fields.pop('text') return send_mp(self.context.get('request').user, validated_data.get('participants'), validated_data.get('title'), validated_data.get('subtitle') or '', validated_data.get('text'), True, False)
def notify_member(self): """ Notify the request author about the decision that has been made. """ if self.is_granted is None: raise Exception('The request must have been solved to use this method.') solved_by_bot = self.moderator == get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) message = render_to_string( 'member/messages/hat_request_decision.md', { 'is_granted': self.is_granted, 'hat': self.hat, 'comment': self.comment, 'solved_by_bot': solved_by_bot, } ) send_mp(self.moderator, [self.user], _('Casquette « {} »').format(self.hat), '', message, leave=solved_by_bot, mark_as_read=True, hat=get_hat_from_settings('hats_management'))
def form_valid(self, form): # get database representation and validated version db_object = self.object versioned = self.versioned_object self.success_url = versioned.get_absolute_url_online() db_object.sha_picked = form.cleaned_data["version"] db_object.picked_date = datetime.now() db_object.save() # mark to reindex to boost correctly in the search self.public_content_object.es_flagged = True self.public_content_object.save() PickListOperation.objects.create( content=self.object, operation="PICK", staff_user=self.request.user, operation_date=datetime.now(), version=db_object.sha_picked, ) msg = render_to_string( "tutorialv2/messages/validation_opinion.md", { "title": versioned.title, "url": versioned.get_absolute_url(), }, ) bot = get_object_or_404( User, username=settings.ZDS_APP["member"]["bot_account"]) if not self.object.validation_private_message: self.object.validation_private_message = send_mp( bot, versioned.authors.all(), self.object.validation_message_title, versioned.title, msg, send_by_mail=True, direct=False, hat=get_hat_from_settings("moderation"), ) self.object.save() else: send_message_mp( bot, self.object.validation_private_message, msg, hat=get_hat_from_settings("moderation"), no_notification_for=[self.request.user], ) messages.success(self.request, _("Le billet a bien été choisi.")) return super().form_valid(form)
def test_creation_private_topic(self): """ When we create a topic, its author follows it. """ topic = send_mp(author=self.user1, users=[], title='Testing', subtitle='', text='', leave=False) subscriptions = PrivateTopicAnswerSubscription.objects.get_subscriptions(topic) self.assertEqual(1, len(subscriptions)) self.assertEqual(self.user1, subscriptions[0].user) self.assertTrue(subscriptions[0].by_email) self.assertIsNone(subscriptions[0].last_notification)
def form_valid(self, form): # get database representation and validated version db_object = self.object versioned = self.versioned_object self.success_url = versioned.get_absolute_url_online() if not db_object.in_public(): raise Http404('This opinion is not published.') elif PickListOperation.objects.filter(content=self.object, is_effective=True).exists(): raise PermissionDenied('There is already an effective operation for this content.') try: PickListOperation.objects.create(content=self.object, operation=form.cleaned_data['operation'], staff_user=self.request.user, operation_date=datetime.now(), version=db_object.sha_public) if form.cleaned_data['operation'] == 'REMOVE_PUB': unpublish_content(self.object, moderator=self.request.user) # send PM msg = render_to_string( 'tutorialv2/messages/validation_unpublish_opinion.md', { 'content': versioned, 'url': versioned.get_absolute_url(), 'moderator': self.request.user, }) bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, versioned.authors.all(), _('Dépublication'), versioned.title, msg, True, direct=False, hat=get_hat_from_settings('moderation'), ) except ValueError: logger.exception('Could not %s the opinion %s', form.cleaned_data['operation'], str(self.object)) return HttpResponse(json.dumps({'result': 'FAIL', 'reason': str(_('Mauvaise opération'))}), status=400) self.success_url = self.object.get_absolute_url_online() return HttpResponse(json.dumps({'result': 'OK'}))
def form_valid(self, form): versioned = self.versioned_object user = self.request.user if user not in versioned.authors.all() and not user.has_perm('tutorialv2.change_validation'): raise PermissionDenied if form.cleaned_data['version'] != self.object.sha_public: raise PermissionDenied unpublish_content(self.object, moderator=self.request.user) if [self.request.user] != list(self.object.authors.all()): # Sends PM if the deleter is not the author # (or is not the only one) of the opinion. msg = render_to_string( 'tutorialv2/messages/validation_revoke.md', { 'content': versioned, 'url': versioned.get_absolute_url(), 'admin': user, 'message_reject': '\n'.join(['> ' + a for a in form.cleaned_data['text'].split('\n')]) }) bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, versioned.authors.all(), _('Dépublication'), versioned.title, msg, True, direct=False, hat=get_hat_from_settings('moderation'), ) messages.success(self.request, _('Le contenu a bien été dépublié.')) self.success_url = self.versioned_object.get_absolute_url() return super(UnpublishOpinion, self).form_valid(form)
def notify_member(self, ban, msg): """ Notify the member sanctioned with a MP. :param ban: Sanction. :type ban: Ban object :param msg: message send at the user sanctioned. :type msg: string object :return: nothing :rtype: None """ bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, [ban.user], ban.type, "", msg, True, direct=True, )
def create(self, validated_data): # This hack is necessary because `text` isn't a field of PrivateTopic. self.fields.pop("text") return send_mp( self.context.get("request").user, validated_data.get("participants"), validated_data.get("title"), validated_data.get("subtitle") or "", validated_data.get("text"), send_by_mail=True, leave=False, )
def solve_alert(request): """ Solves an alert (i.e. delete it from alert list) and sends an email to the user that created the alert, if the resolver leaves a comment. This can only be done by staff. """ if not request.user.has_perm("forum.change_post"): raise PermissionDenied alert = get_object_or_404(Alert, pk=request.POST["alert_pk"]) post = Post.objects.get(pk=alert.comment.id) if "text" in request.POST and request.POST["text"] != "": bot = get_object_or_404( User, username=settings.ZDS_APP['member']['bot_account']) msg = \ (u'Bonjour {0},' u'Vous recevez ce message car vous avez signalé le message de *{1}*, ' u'dans le sujet [{2}]({3}). Votre alerte a été traitée par **{4}** ' u'et il vous a laissé le message suivant :' u'\n\n> {5}\n\nToute l\'équipe de la modération vous remercie !'.format( alert.author.username, post.author.username, post.topic.title, settings.ZDS_APP['site']['url'] + post.get_absolute_url(), request.user.username, request.POST["text"],)) send_mp( bot, [alert.author], u"Résolution d'alerte : {0}".format(post.topic.title), "", msg, False, ) alert.delete() messages.success(request, u"L'alerte a bien été résolue.") return redirect(post.get_absolute_url())
def new(request): """Creates a new private topic.""" if request.method == "POST": # If the client is using the "preview" button if "preview" in request.POST: form = PrivateTopicForm( initial={ "participants": request.POST["participants"], "title": request.POST["title"], "subtitle": request.POST["subtitle"], "text": request.POST["text"], } ) return render_template("mp/topic/new.html", {"form": form}) form = PrivateTopicForm(request.POST) if form.is_valid(): data = form.data # Retrieve all participants of the MP. ctrl = [] list_part = data["participants"].replace(",", " ").split() for part in list_part: part = part.strip() if part == "": continue p = get_object_or_404(User, username=part) # We don't the author of the MP. if request.user == p: continue ctrl.append(p) p_topic = send_mp(request.user, ctrl, data["title"], data["subtitle"], data["text"], True, False) return redirect(p_topic.get_absolute_url()) else: return render_template("mp/topic/new.html", {"form": form}) else: if "username" in request.GET: try: # check that username in url is in the database dest = User.objects.get(username=request.GET["username"]).username except: dest = None else: dest = None form = PrivateTopicForm(initial={"participants": dest}) return render_template("mp/topic/new.html", {"form": form})
def form_valid(self, form): versioned = self.versioned_object user = self.request.user if user not in versioned.authors.all() and not user.has_perm("tutorialv2.change_validation"): raise PermissionDenied if form.cleaned_data["version"] != self.object.sha_public: raise PermissionDenied unpublish_content(self.object, moderator=self.request.user) if [self.request.user] != list(self.object.authors.all()): # Sends PM if the deleter is not the author # (or is not the only one) of the opinion. msg = render_to_string( "tutorialv2/messages/validation_revoke.md", { "content": versioned, "url": versioned.get_absolute_url(), "admin": user, "message_reject": "\n".join(["> " + a for a in form.cleaned_data["text"].split("\n")]), }, ) bot = get_object_or_404(User, username=settings.ZDS_APP["member"]["bot_account"]) if not self.object.validation_private_message: self.object.validation_private_message = send_mp( bot, versioned.authors.all(), self.object.validation_message_title, versioned.title, msg, send_by_mail=True, direct=False, hat=get_hat_from_settings("moderation"), ) self.object.save() else: send_message_mp( bot, self.object.validation_private_message, msg, hat=get_hat_from_settings("moderation"), no_notification_for=[self.request.user], ) messages.success(self.request, _("Le contenu a bien été dépublié.")) self.success_url = self.versioned_object.get_absolute_url() return super().form_valid(form)
def form_valid(self, form): # get database representation and validated version db_object = self.object versioned = self.versioned_object self.success_url = versioned.get_absolute_url_online() db_object.sha_picked = form.cleaned_data['version'] db_object.picked_date = datetime.now() db_object.save() # mark to reindex to boost correctly in the search self.public_content_object.es_flagged = True self.public_content_object.save() PickListOperation.objects.create(content=self.object, operation='PICK', staff_user=self.request.user, operation_date=datetime.now(), version=db_object.sha_public) msg = render_to_string('tutorialv2/messages/validation_opinion.md', { 'title': versioned.title, 'url': versioned.get_absolute_url(), }) bot = get_object_or_404( User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, versioned.authors.all(), _('Billet approuvé'), versioned.title, msg, True, direct=False, hat=get_hat_from_settings('moderation'), ) messages.success(self.request, _('Le contenu a bien été validé.')) return super(PickOpinion, self).form_valid(form)
def form_valid(self, form): participants = [] for participant in form.data['participants'].split(","): current = participant.strip() if current == '': continue participants.append(get_object_or_404(User, username=current)) p_topic = send_mp(self.request.user, participants, form.data['title'], form.data['subtitle'], form.data['text'], True, False) return redirect(p_topic.get_absolute_url())
def notify_member(self, ban, msg): """ Notify the member sanctioned with a MP. :param ban: Sanction. :type ban: Ban object :param msg: message send at the user sanctioned. :type msg: string object :return: nothing :rtype: None """ bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, [ban.user], ban.type, '', msg, True, direct=True, hat=get_hat_from_settings('moderation'), )
def form_valid(self, form): # get database representation and validated version db_object = self.object versioned = self.versioned_object self.success_url = versioned.get_absolute_url_online() db_object.sha_picked = form.cleaned_data['version'] db_object.picked_date = datetime.now() db_object.save() # mark to reindex to boost correctly in the search self.public_content_object.es_flagged = True self.public_content_object.save() PickListOperation.objects.create(content=self.object, operation='PICK', staff_user=self.request.user, operation_date=datetime.now(), version=db_object.sha_picked) msg = render_to_string( 'tutorialv2/messages/validation_opinion.md', { 'title': versioned.title, 'url': versioned.get_absolute_url(), }) bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) send_mp( bot, versioned.authors.all(), _('Billet approuvé'), versioned.title, msg, True, direct=False, hat=get_hat_from_settings('moderation'), ) messages.success(self.request, _('Le billet a bien été choisi.')) return super(PickOpinion, self).form_valid(form)
def notify_member(self, ban, msg): """ Notify the member sanctioned with a MP. :param ban: Sanction. :type ban: Ban object :param msg: message send at the user sanctioned. :type msg: string object :return: nothing :rtype: None """ bot = get_object_or_404( User, username=settings.ZDS_APP["member"]["bot_account"]) send_mp( bot, [ban.user], ban.type, "", msg, send_by_mail=True, direct=True, hat=get_hat_from_settings("moderation"), )
def test_no_emails_for_those_who_have_other_things_in_that_place(self): """ Test that we do not try to send e-mails to those who have not registered a valid one. """ self.assertEqual(0, len(mail.outbox)) topic = send_mp(author=self.userStandard1, users=[self.userOAuth2], title='Testing', subtitle='', text='', send_by_mail=True, leave=False) self.assertEqual(0, len(mail.outbox)) send_message_mp(self.userOAuth2, topic, '', send_by_mail=True) self.assertEqual(1, len(mail.outbox))
def alert_authors(self): """ Send a private message to all authors (with a `PublishableContent`) for new tags system. :return: None """ bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) bots = [ get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']), get_object_or_404(User, username=settings.ZDS_APP['member']['anonymous_account']), get_object_or_404(User, username=settings.ZDS_APP['member']['external_account']) ] users = [] contents = PublishableContent.objects.all() for content in contents: authors = content.authors.all() for author in authors: if author not in users and author not in bots: users.append(author) for user in users: msg = 'Bonjour,\n\nDepuis la dernière version de Zeste de Savoir, tous les contenus (articles, tutori' \ 'els et bientôt tribunes libres) possèdent maintenant une nouvelle classification ([ZEP-25](https:/' \ '/zestedesavoir.com/forums/sujet/2378/zep-25-categorisation-des-articles-et-tutoriels/)). Les **tag' \ 's** ont fait leur apparition et les catégories ont été revues afin de faciliter et d\'aléger cette' \ ' classification.\n\nLes anciennes catégories ont été transformées en tags et de nouvelles catégori' \ 'es plus générales ont été ajoutés. L\'équipe de Zeste de Savoir va ou a déjà changé les catégories' \ ' des contenus publiés.\n\nNous vous invitons à vérifier les catégories de vos articles et tutoriel' \ 's mais également la pertinence des tags et en ajouter si besoin.\n\n\nNous restons à votre disposi' \ 'tion et votre écoute pour toutes suggestions ou remarques,\n\nL\'équipe de Zeste de Savoir' send_mp( bot, [user], 'Changement de classification du contenu sur Zeste de Savoir', "Ce qui change pour vous en tant qu'auteur", msg ) self.stdout.write('[ZEP-25] : PM send to {}'.format(user))
def form_valid(self, form): db_object = self.object versioned = self.versioned_object self.success_url = versioned.get_absolute_url_online() if not db_object.sha_picked: raise PermissionDenied("Impossible de retirer des billets choisis un billet pas choisi.") if db_object.sha_picked != form.cleaned_data["version"]: raise PermissionDenied("Impossible de retirer des billets choisis un billet pas choisi.") db_object.sha_picked = None db_object.save() PickListOperation.objects.filter(operation="PICK", is_effective=True, content=self.object).first().cancel( self.request.user ) # mark to reindex to boost correctly in the search self.public_content_object.es_flagged = True self.public_content_object.save() msg = render_to_string( "tutorialv2/messages/validation_invalid_opinion.md", { "content": versioned, "url": versioned.get_absolute_url(), "admin": self.request.user, "message_reject": "\n".join(["> " + a for a in form.cleaned_data["text"].split("\n")]), }, ) bot = get_object_or_404(User, username=settings.ZDS_APP["member"]["bot_account"]) if not self.object.validation_private_message: self.object.validation_private_message = send_mp( bot, versioned.authors.all(), self.object.validation_message_title, versioned.title, msg, send_by_mail=True, direct=False, hat=get_hat_from_settings("moderation"), ) self.object.save() else: send_message_mp(bot, self.object.validation_private_message, msg) messages.success(self.request, _("Le contenu a bien été enlevé de la liste des billets choisis.")) return super().form_valid(form)
def setUp(self): self.author = ProfileFactory() self.user = ProfileFactory() 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_mark_read_a_notification(self): """ When we mark a private topic as read, we mark its notification as read. """ topic = send_mp(author=self.user1, users=[self.user2, self.user3], title='Testing', subtitle='', text='', leave=False) notifications = Notification.objects.get_unread_notifications_of(self.user2) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first()) self.assertEqual(topic.last_message, notifications.first().content_object) mark_read(topic, self.user2) notifications = Notification.objects.get_unread_notifications_of(self.user2) self.assertEqual(0, len(notifications))
def test_remove_notifications_when_a_user_leave_private_topic(self): """ When a user leaves a private topic, we mark the current notification as read if it exists. """ topic = send_mp(author=self.user1, users=[self.user2], title='Testing', subtitle='', text='', leave=False) notifications = Notification.objects.get_unread_notifications_of( self.user2) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first()) self.assertEqual(topic.last_message, notifications.first().content_object) self.assertIsNotNone( PrivateTopicAnswerSubscription.objects.get_existing( self.user2, topic, is_active=True)) send_message_mp(self.user2, topic, 'Test') topic.participants.remove(self.user2) topic.save() self.assertEqual( 0, len(Notification.objects.get_unread_notifications_of(self.user2))) self.assertIsNotNone( PrivateTopicAnswerSubscription.objects.get_existing( self.user2, topic, is_active=False)) self.assertEqual( 1, len(Notification.objects.get_unread_notifications_of(self.user1))) response = self.client.post(reverse('mp-delete', args=[topic.pk, topic.slug]), follow=True) self.assertEqual(200, response.status_code) self.assertEqual( 0, len(Notification.objects.get_unread_notifications_of(self.user1)))
def form_valid(self, form): participants = [] for participant in form.data['participants'].split(','): current = participant.strip() if not current: continue participants.append(get_object_or_404(User, username=current)) p_topic = send_mp(self.request.user, participants, form.data['title'], form.data['subtitle'], form.data['text'], True, False, hat=get_hat_from_request(self.request)) return redirect(p_topic.get_absolute_url())
def test_reuse_old_notification(self): """ When there already is a read notification for a given content, we reuse it. """ topic = send_mp(author=self.user1, users=[self.user2], title='Testing', subtitle='', text='', leave=False) send_message_mp(self.user2, topic, '', send_by_mail=True) notifications = Notification.objects.get_unread_notifications_of(self.user1) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first()) self.assertEqual(topic.last_message, notifications.first().content_object) mark_read(topic, self.user1) send_message_mp(self.user2, topic, '', send_by_mail=True) notifications = Notification.objects.filter(subscription__user=self.user1) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first())
def form_valid(self, form): participants = [] for participant in form.data["participants"].split(","): current = participant.strip() if not current: continue participants.append(get_object_or_404(User, username=current)) p_topic = send_mp( self.request.user, participants, form.data["title"], form.data["subtitle"], form.data["text"], send_by_mail=True, leave=False, hat=get_hat_from_request(self.request), ) return redirect(p_topic.get_absolute_url())
def test_generate_a_notification_when_add_a_participant(self): """ When we add a user to a private topic, we generate a notification for this user at the last message. """ topic = send_mp(author=self.user1, users=[self.user2], title='Testing', subtitle='', text='', leave=False) subscriptions = PrivateTopicAnswerSubscription.objects.filter(user=self.user3) self.assertEqual(0, len(subscriptions)) topic.participants.add(self.user3) topic.save() subscriptions = PrivateTopicAnswerSubscription.objects.filter(user=self.user3) self.assertEqual(1, len(subscriptions)) notifications = Notification.objects.get_unread_notifications_of(self.user3) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.filter()) self.assertEqual(topic.last_message, notifications.first().content_object)
def test_generate_a_notification_after_new_post(self): """ When a user posts on a private topic, we generate a notification for all participants. """ topic = send_mp(author=self.user1, users=[self.user2, self.user3], title='Testing', subtitle='', text='', leave=False) notifications = Notification.objects.get_unread_notifications_of(self.user2) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first()) self.assertEqual(topic.last_message, notifications.first().content_object) mark_read(topic, self.user2) notifications = Notification.objects.get_unread_notifications_of(self.user2) self.assertEqual(0, len(notifications)) send_message_mp(self.user3, topic, '') notifications = Notification.objects.get_unread_notifications_of(self.user2) self.assertEqual(1, len(notifications)) self.assertIsNotNone(notifications.first()) self.assertEqual(topic.last_message, notifications.first().content_object)
def active_account(request): """Active token for a user.""" try: token = request.GET["token"] except KeyError: return redirect(reverse("zds.pages.views.home")) token = get_object_or_404(TokenRegister, token=token) usr = token.user # User can't confirm his request if he is already activated. if usr.is_active: return render_template("member/register/token_already_used.html") # User can't confirm his request if it is too late. if datetime.now() > token.date_end: return render_template("member/register/token_failed.html", {"token": token}) usr.is_active = True usr.save() # send register message bot = get_object_or_404(User, username=settings.BOT_ACCOUNT) msg = ( u'Bonjour **{0}**,' u'\n\n' u'Ton compte a été activé, et tu es donc officiellement ' u'membre de la communauté de Zeste de Savoir.' u'\n\n' u'Zeste de Savoir est une communauté dont le but est de diffuser des ' u'connaissances au plus grand nombre.' u'\n\n' u'Sur ce site, tu trouveras un ensemble de [tutoriels]({1}) dans ' u'plusieurs domaines et plus particulièrement autour de l\'informatique ' u'et des sciences. Tu y retrouveras aussi des [articles]({2}) ' u'traitant de sujets d\'actualité ou non, qui, tout comme les tutoriels, ' u'sont écrits par des [membres]({3}) de la communauté. ' u'Pendant tes lectures et ton apprentissage, si jamais tu as des ' u'questions à poser, tu retrouveras sur les [forums]({4}) des personnes ' u'prêtes à te filer un coup de main et ainsi t\'éviter de passer ' u'plusieurs heures sur un problème.' u'\n\n' u'L\'ensemble du contenu disponible sur le site est et sera toujours gratuit, ' u'car la communauté de Zeste de Savoir est attachée aux valeurs du libre ' u'partage et désire apporter le savoir à tout le monde quels que soient ses moyens.' u'\n\n' u'En espérant que tu te plairas ici, ' u'je te laisse maintenant faire un petit tour.' u'\n\n' u'Clem\'' .format(usr.username, settings.SITE_URL + reverse("zds.tutorial.views.index"), settings.SITE_URL + reverse("zds.article.views.index"), settings.SITE_URL + reverse("zds.member.views.index"), settings.SITE_URL + reverse("zds.forum.views.index"))) send_mp( bot, [usr], u"Bienvenue sur Zeste de Savoir", u"Le manuel du nouveau membre", msg, True, True, False, ) return render_template("member/register/token_success.html", {"usr": usr}) token.delete()
def modify_profile(request, user_pk): """Modifies sanction of a user if there is a POST request.""" profile = get_object_or_404(Profile, user__pk=user_pk) if request.method == "POST": ban = Ban() ban.moderator = request.user ban.user = profile.user ban.pubdate = datetime.now() if "ls" in request.POST: profile.can_write = False ban.type = u"Lecture Seule" ban.text = request.POST["ls-text"] detail = (u'Vous ne pouvez plus poster dans les forums, ni dans les ' u'commentaires d\'articles et de tutoriels.') if "ls-temp" in request.POST: ban.type = u"Lecture Seule Temporaire" ban.text = request.POST["ls-temp-text"] profile.can_write = False profile.end_ban_write = datetime.now() \ + timedelta(days=int(request.POST["ls-jrs"]), hours=0, minutes=0, seconds=0) detail = (u'Vous ne pouvez plus poster dans les forums, ni dans les ' u'commentaires d\'articles et de tutoriels pendant {0} jours.' .format(request.POST["ls-jrs"])) if "ban-temp" in request.POST: ban.type = u"Ban Temporaire" ban.text = request.POST["ban-temp-text"] profile.can_read = False profile.end_ban_read = datetime.now() \ + timedelta(days=int(request.POST["ban-jrs"]), hours=0, minutes=0, seconds=0) detail = (u'Vous ne pouvez plus vous connecter sur Zeste de Savoir ' u'pendant {0} jours.'.format(request.POST["ban-jrs"])) logout_user(profile.user.username) if "ban" in request.POST: ban.type = u"Ban définitif" ban.text = request.POST["ban-text"] profile.can_read = False detail = u"vous ne pouvez plus vous connecter sur Zeste de Savoir." logout_user(profile.user.username) if "un-ls" in request.POST: ban.type = u"Autorisation d'écrire" ban.text = request.POST["unls-text"] profile.can_write = True detail = (u'Vous pouvez désormais poster sur les forums, dans les ' u'commentaires d\'articles et tutoriels.') if "un-ban" in request.POST: ban.type = u"Autorisation de se connecter" ban.text = request.POST["unban-text"] profile.can_read = True detail = u"vous pouvez désormais vous connecter sur le site." profile.save() ban.save() # send register message if "un-ls" in request.POST or "un-ban" in request.POST: msg = \ u"""Bonjour **{0}**, **Bonne Nouvelle**, la sanction qui pesait sur vous a été levée par **{1}**. Ce qui signifie que {2} Le motif de votre sanction est : `{3}` Cordialement, L'équipe Zeste de Savoir. """.format(ban.user, ban.moderator, detail, ban.text) else: msg = \ u"""Bonjour **{0}**, Vous avez été santionné par **{1}**. La sanction est de type *{2}*, ce qui signifie que {3} Le motif de votre sanction est : `{4}` Cordialement, L'équipe Zeste de Savoir. """.format(ban.user, ban.moderator, ban.type, detail, ban.text) bot = get_object_or_404(User, username=settings.BOT_ACCOUNT) send_mp( bot, [ban.user], ban.type, "Sanction", msg, True, direct=True, ) return redirect(profile.get_absolute_url())
def form_valid(self, form): user = self.request.user validation = Validation.objects\ .filter(pk=self.kwargs['pk'])\ .prefetch_related('content')\ .prefetch_related('content__authors')\ .last() if not validation: raise PermissionDenied if validation.status not in ['PENDING', 'PENDING_V']: raise PermissionDenied # cannot cancel a validation that is already accepted or rejected if user not in validation.content.authors.all() and not user.has_perm('tutorialv2.change_validation'): raise PermissionDenied versioned = validation.content.load_version(sha=validation.version) # reject validation: quote = '\n'.join(['> ' + line for line in form.cleaned_data['text'].split('\n')]) validation.status = 'CANCEL' validation.comment_authors += _('\n\nLa validation a été **annulée** pour la raison suivante :\n\n{}')\ .format(quote) validation.date_validation = datetime.now() validation.save() validation.content.sha_validation = None validation.content.save() # warn the former validator that the all thing have been canceled if validation.validator: bot = get_object_or_404(User, username=settings.ZDS_APP['member']['bot_account']) msg = render_to_string( 'tutorialv2/messages/validation_cancel.md', { 'content': versioned, 'validator': validation.validator.username, 'url': versioned.get_absolute_url() + '?version=' + validation.version, 'user': self.request.user, 'message': quote }) send_mp( bot, [validation.validator], _('Demande de validation annulée').format(), versioned.title, msg, False, hat=get_hat_from_settings('validation'), ) messages.info(self.request, _('La validation de ce contenu a bien été annulée.')) self.success_url = reverse('content:view', args=[validation.content.pk, validation.content.slug]) + \ '?version=' + validation.version return super(CancelValidation, self).form_valid(form)
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)