Esempio n. 1
0
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())
Esempio n. 2
0
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())
Esempio n. 3
0
    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)
Esempio n. 4
0
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})
Esempio n. 5
0
    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)
Esempio n. 6
0
    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)
Esempio n. 7
0
    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)
Esempio n. 8
0
    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)
Esempio n. 9
0
    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))
Esempio n. 10
0
    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)
Esempio n. 11
0
    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)
Esempio n. 12
0
    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)))
Esempio n. 13
0
    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)
Esempio n. 14
0
    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)
Esempio n. 15
0
    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
            )
Esempio n. 16
0
 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)
Esempio n. 17
0
    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
            )
Esempio n. 18
0
    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)
Esempio n. 19
0
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')
Esempio n. 20
0
    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)
Esempio n. 21
0
    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}")
Esempio n. 22
0
    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)
Esempio n. 23
0
    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)
Esempio n. 24
0
    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()
Esempio n. 25
0
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())
Esempio n. 26
0
 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)
Esempio n. 27
0
    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'))
Esempio n. 28
0
    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)
Esempio n. 29
0
    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)
Esempio n. 30
0
    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)
Esempio n. 31
0
    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'}))
Esempio n. 32
0
    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)
Esempio n. 33
0
    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,
        )
Esempio n. 34
0
 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,
     )
Esempio n. 35
0
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())
Esempio n. 36
0
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)
Esempio n. 38
0
    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)
Esempio n. 39
0
    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())
Esempio n. 40
0
    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'),
        )
Esempio n. 41
0
    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)
Esempio n. 42
0
    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"),
        )
Esempio n. 43
0
    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))
Esempio n. 44
0
    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)
Esempio n. 46
0
    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)
Esempio n. 47
0
    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))
Esempio n. 48
0
    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))
Esempio n. 49
0
    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)))
Esempio n. 50
0
    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())
Esempio n. 51
0
    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())
Esempio n. 52
0
    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())
Esempio n. 53
0
    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())
Esempio n. 54
0
    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)
Esempio n. 55
0
    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)
Esempio n. 56
0
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()
Esempio n. 57
0
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())
Esempio n. 58
0
    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)
Esempio n. 59
0
    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)