Example #1
0
    def test_autowatch_reply(self, get_current):
        """
        Tests the autowatch setting of users.

        If a user has the setting turned on, they should get
        notifications after posting in a thread for that thread. If they
        have that setting turned off, they should not.
        """

        get_current.return_value.domain = 'testserver'

        u = user(save=True)
        t1 = question(save=True)
        t2 = question(save=True)
        assert not QuestionReplyEvent.is_notifying(u, t1)
        assert not QuestionReplyEvent.is_notifying(u, t2)

        self.client.login(username=u.username, password='******')
        s = Setting.objects.create(user=u, name='questions_watch_after_reply',
                                   value='True')
        data = {'content': 'some content'}
        post(self.client, 'questions.reply', data, args=[t1.id])
        assert QuestionReplyEvent.is_notifying(u, t1)

        s.value = 'False'
        s.save()
        post(self.client, 'questions.reply', data, args=[t2.id])
        assert not QuestionReplyEvent.is_notifying(u, t2)
Example #2
0
    def save(self, user, locale, product, product_config, *args, **kwargs):
        self.instance.creator = user
        self.instance.locale = locale
        self.instance.product = product

        category_config = product_config["categories"][self.cleaned_data["category"]]
        if category_config:
            t = category_config.get("topic")
            if t:
                self.instance.topic = Topic.objects.get(slug=t, product=product)

        question = super(NewQuestionForm, self).save(*args, **kwargs)

        if self.cleaned_data.get("notifications", False):
            QuestionReplyEvent.notify(question.creator, question)

        user_ct = ContentType.objects.get_for_model(user)
        qst_ct = ContentType.objects.get_for_model(question)
        # Move over to the question all of the images I added to the reply form
        up_images = ImageAttachment.objects.filter(creator=user, content_type=user_ct)
        up_images.update(content_type=qst_ct, object_id=question.id)

        # User successfully submitted a new question
        question.add_metadata(**self.cleaned_metadata)

        if product_config:
            # TODO: This add_metadata call should be removed once we are
            # fully IA-driven (sync isn't special case anymore).
            question.add_metadata(product=product_config["key"])

        # The first time a question is saved, automatically apply some tags:
        question.auto_tag()

        return question
Example #3
0
    def test_autowatch_reply(self, get_current):
        """
        Tests the autowatch setting of users.

        If a user has the setting turned on, they should get
        notifications after posting in a thread for that thread. If they
        have that setting turned off, they should not.
        """

        get_current.return_value.domain = 'testserver'

        u = UserFactory()
        t1 = QuestionFactory()
        t2 = QuestionFactory()
        assert not QuestionReplyEvent.is_notifying(u, t1)
        assert not QuestionReplyEvent.is_notifying(u, t2)

        self.client.login(username=u.username, password='******')
        s = Setting.objects.create(user=u, name='questions_watch_after_reply',
                                   value='True')
        data = {'content': 'some content'}
        post(self.client, 'questions.reply', data, args=[t1.id])
        assert QuestionReplyEvent.is_notifying(u, t1)

        s.value = 'False'
        s.save()
        post(self.client, 'questions.reply', data, args=[t2.id])
        assert not QuestionReplyEvent.is_notifying(u, t2)
    def test_autowatch_reply(self, get_current):
        """
        Tests the autowatch setting of users.

        If a user has the setting turned on, they should get
        notifications after posting in a thread for that thread. If they
        have that setting turned off, they should not.
        """

        get_current.return_value.domain = "testserver"

        u = user(save=True)
        t1 = question(save=True)
        t2 = question(save=True)
        assert not QuestionReplyEvent.is_notifying(u, t1)
        assert not QuestionReplyEvent.is_notifying(u, t2)

        self.client.login(username=u.username, password="******")
        s = Setting.objects.create(user=u, name="questions_watch_after_reply", value="True")
        data = {"content": "some content"}
        post(self.client, "questions.reply", data, args=[t1.id])
        assert QuestionReplyEvent.is_notifying(u, t1)

        s.value = "False"
        s.save()
        post(self.client, "questions.reply", data, args=[t2.id])
        assert not QuestionReplyEvent.is_notifying(u, t2)
Example #5
0
    def setUp(self):
        p = profile()
        p.save()
        self.user = p.user
        self.client.login(username=self.user.username, password='******')

        self.question = question(creator=self.user, save=True)
        QuestionReplyEvent.notify(self.user, self.question)
Example #6
0
    def test_no_notification_on_update(self):
        """Saving an existing question does not watch it."""

        q = Question.objects.get(pk=1)
        assert not QuestionReplyEvent.is_notifying(q.creator, q)

        q.save()
        assert not QuestionReplyEvent.is_notifying(q.creator, q)
Example #7
0
    def setUp(self):
        p = profile()
        p.save()
        self.user = p.user
        self.client.login(username=self.user.username, password='******')

        self.question = question(creator=self.user, save=True)
        QuestionReplyEvent.notify(self.user, self.question)
Example #8
0
def reply(request, question_id):
    """Post a new answer to a question."""
    question = get_object_or_404(Question, pk=question_id, is_spam=False)
    answer_preview = None

    if not question.allows_new_answer(request.user):
        raise PermissionDenied

    form = AnswerForm(request.POST, **{"user": request.user, "question": question})

    # NOJS: delete images
    if "delete_images" in request.POST:
        for image_id in request.POST.getlist("delete_image"):
            ImageAttachment.objects.get(pk=image_id).delete()

        return question_details(request, question_id=question_id, form=form)

    # NOJS: upload image
    if "upload_image" in request.POST:
        upload_imageattachment(request, request.user)
        return question_details(request, question_id=question_id, form=form)

    if form.is_valid() and not request.limited:
        answer = Answer(
            question=question,
            creator=request.user,
            content=form.cleaned_data["content"],
        )
        if "preview" in request.POST:
            answer_preview = answer
        else:
            if form.cleaned_data.get("is_spam"):
                _add_to_moderation_queue(request, answer)
            else:
                answer.save()

            ans_ct = ContentType.objects.get_for_model(answer)
            # Move over to the answer all of the images I added to the
            # reply form
            user_ct = ContentType.objects.get_for_model(request.user)
            up_images = ImageAttachment.objects.filter(creator=request.user, content_type=user_ct)
            up_images.update(content_type=ans_ct, object_id=answer.id)

            # Handle needsinfo tag
            if "needsinfo" in request.POST:
                question.set_needs_info()
            elif "clear_needsinfo" in request.POST:
                question.unset_needs_info()

            if Setting.get_for_user(request.user, "questions_watch_after_reply"):
                QuestionReplyEvent.notify(request.user, question)

            return HttpResponseRedirect(answer.get_absolute_url())

    return question_details(
        request, question_id=question_id, form=form, answer_preview=answer_preview
    )
Example #9
0
    def test_no_notification_on_update(self):
        """Saving an existing question does not watch it."""

        q = QuestionFactory()
        QuestionReplyEvent.stop_notifying(q.creator, q)
        assert not QuestionReplyEvent.is_notifying(q.creator, q)

        q.save()
        assert not QuestionReplyEvent.is_notifying(q.creator, q)
Example #10
0
    def test_no_notification_on_update(self):
        """Saving an existing question does not watch it."""

        q = question(save=True)
        QuestionReplyEvent.stop_notifying(q.creator, q)
        assert not QuestionReplyEvent.is_notifying(q.creator, q)

        q.save()
        assert not QuestionReplyEvent.is_notifying(q.creator, q)
    def test_notify_arbitrary_reply_to(self):
        """
        Test that notifications to the asker have a correct reply to field.
        """
        watcher = user(save=True)
        QuestionReplyEvent.notify(watcher, self.question)
        self.makeAnswer()

        notification = [m for m in mail.outbox if m.to == [watcher.email]][0]
        # Headers should be compared case-insensitively.
        headers = dict((k.lower(), v) for k, v in notification.extra_headers.items())
        eq_("*****@*****.**", headers["reply-to"])
    def test_notify_anonymous_reply_to(self):
        """
        Test that notifications to the asker have a correct reply to field.
        """
        ANON_EMAIL = "*****@*****.**"
        QuestionReplyEvent.notify(ANON_EMAIL, self.question)
        self.makeAnswer()

        notification = [m for m in mail.outbox if m.to == [ANON_EMAIL]][0]
        # Headers should be compared case-insensitively.
        headers = dict((k.lower(), v) for k, v in notification.extra_headers.items())
        eq_("*****@*****.**", headers["reply-to"])
Example #13
0
    def test_notify_anonymous_reply_to(self):
        """
        Test that notifications to the asker have a correct reply to field.
        """
        ANON_EMAIL = '*****@*****.**'
        QuestionReplyEvent.notify(ANON_EMAIL, self.question)
        self.makeAnswer()

        notification = [m for m in mail.outbox if m.to == [ANON_EMAIL]][0]
        # Headers should be compared case-insensitively.
        headers = dict((k.lower(), v)
                       for k, v in notification.extra_headers.items())
        eq_('*****@*****.**', headers['reply-to'])
Example #14
0
    def test_notify_arbitrary_reply_to(self):
        """
        Test that notifications to the asker have a correct reply to field.
        """
        watcher = user(save=True)
        QuestionReplyEvent.notify(watcher, self.question)
        self.makeAnswer()

        notification = [m for m in mail.outbox if m.to == [watcher.email]][0]
        # Headers should be compared case-insensitively.
        headers = dict((k.lower(), v)
                       for k, v in notification.extra_headers.items())
        eq_('*****@*****.**', headers['reply-to'])
    def test_notify_anonymous(self):
        """Test that anonymous users are notified of new answers."""
        ANON_EMAIL = "*****@*****.**"
        QuestionReplyEvent.notify(ANON_EMAIL, self.question)
        self.makeAnswer()

        # One for the asker's email, and one for the anonymous email.
        eq_(2, len(mail.outbox))
        notification = [m for m in mail.outbox if m.to == [ANON_EMAIL]][0]

        eq_([ANON_EMAIL], notification.to)
        eq_("Re: {0}".format(self.question.title), notification.subject)

        body = re.sub(r"auth=[a-zA-Z0-9%_-]+", "auth=AUTH", notification.body)
        starts_with(body, ANSWER_EMAIL_TO_ANONYMOUS.format(**self.format_args()))
Example #16
0
    def test_notify_arbitrary(self):
        """Test that arbitrary users are notified of new answers."""
        watcher = user(save=True)
        QuestionReplyEvent.notify(watcher, self.question)
        self.makeAnswer()

        # One for the asker's email, and one for the watcher's email.
        eq_(2, len(mail.outbox))
        notification = [m for m in mail.outbox if m.to == [watcher.email]][0]

        eq_([watcher.email], notification.to)
        eq_("Re: {0}".format(self.question.title), notification.subject)

        body = re.sub(r'auth=[a-zA-Z0-9%_-]+', 'auth=AUTH', notification.body)
        starts_with(body, ANSWER_EMAIL.format(to_user=display_name(watcher), **self.format_args()))
    def test_notify_arbitrary(self):
        """Test that arbitrary users are notified of new answers."""
        watcher = user(save=True)
        QuestionReplyEvent.notify(watcher, self.question)
        self.makeAnswer()

        # One for the asker's email, and one for the watcher's email.
        eq_(2, len(mail.outbox))
        notification = [m for m in mail.outbox if m.to == [watcher.email]][0]

        eq_([watcher.email], notification.to)
        eq_("Re: {0}".format(self.question.title), notification.subject)

        body = re.sub(r"auth=[a-zA-Z0-9%_-]+", "auth=AUTH", notification.body)
        starts_with(body, ANSWER_EMAIL.format(to_user=watcher.username, **self.format_args()))
Example #18
0
    def test_notify_arbitrary(self):
        """Test that arbitrary users are notified of new answers."""
        watcher = UserFactory()
        QuestionReplyEvent.notify(watcher, self.question)
        self.makeAnswer()

        # One for the asker's email, and one for the watcher's email.
        eq_(2, len(mail.outbox))
        notification = [m for m in mail.outbox if m.to == [watcher.email]][0]

        eq_([watcher.email], notification.to)
        eq_(u'Re: {0}'.format(self.question.title), notification.subject)

        body = re.sub(r'auth=[a-zA-Z0-9%_-]+', 'auth=AUTH', notification.body)
        starts_with(body, ANSWER_EMAIL.format(to_user=display_name(watcher), **self.format_args()))
Example #19
0
    def test_notify_anonymous(self):
        """Test that anonymous users are notified of new answers."""
        ANON_EMAIL = '*****@*****.**'
        QuestionReplyEvent.notify(ANON_EMAIL, self.question)
        self.makeAnswer()

        # One for the asker's email, and one for the anonymous email.
        eq_(2, len(mail.outbox))
        notification = [m for m in mail.outbox if m.to == [ANON_EMAIL]][0]

        eq_([ANON_EMAIL], notification.to)
        eq_("Re: {0}".format(self.question.title), notification.subject)

        body = re.sub(r'auth=[a-zA-Z0-9%_-]+', 'auth=AUTH', notification.body)
        starts_with(body, ANSWER_EMAIL_TO_ANONYMOUS
                    .format(**self.format_args()))
Example #20
0
    def save(self, update=True, no_notify=False, *args, **kwargs):
        """
        Override save method to update question info and take care of
        updated.
        """

        new = self.id is None

        if new:
            page = self.question.num_answers / config.ANSWERS_PER_PAGE + 1
            self.page = page
        else:
            self.updated = datetime.now()
            self.clear_cached_html()

        super(Answer, self).save(*args, **kwargs)

        if new:
            # Occasionally, num_answers seems to get out of sync with the
            # actual number of answers. This changes it to pull from
            # uncached on the off chance that fixes it. Plus if we enable
            # caching of counts, this will continue to work.
            self.question.num_answers = Answer.uncached.filter(
                question=self.question).count()
            self.question.last_answer = self
            self.question.save(update)
            self.question.clear_cached_contributors()

            if not no_notify:
                # Avoid circular import: events.py imports Question.
                from kitsune.questions.events import QuestionReplyEvent
                QuestionReplyEvent(self).fire(exclude=self.creator)
        else:
            # Clear the attached images cache.
            self.clear_cached_images()
Example #21
0
    def test_notification_created(self):
        """Creating a new question auto-watches it for answers."""

        u = user(save=True)
        q = question(creator=u, title='foo', content='bar', save=True)

        assert QuestionReplyEvent.is_notifying(u, q)
Example #22
0
def unsubscribe_watch(request, watch_id, secret):
    """Stop watching a question, for anonymous users."""
    watch = get_object_or_404(Watch, pk=watch_id)
    question = watch.content_object
    success = False
    if watch.secret == secret and isinstance(question, Question):
        user_or_email = watch.user or watch.email
        QuestionReplyEvent.stop_notifying(user_or_email, question)
        QuestionSolvedEvent.stop_notifying(user_or_email, question)
        success = True

    return render(
        request,
        "questions/unsubscribe_watch.html",
        {"question": question, "success": success},
    )
Example #23
0
    def save(self, update=False, *args, **kwargs):
        """Override save method to take care of updated if requested."""
        new = not self.id

        if not new:
            self.clear_cached_html()
            if update:
                self.updated = datetime.now()

        super(Question, self).save(*args, **kwargs)

        if new:
            # Avoid circular import, events.py imports Question
            from kitsune.questions.events import QuestionReplyEvent
            # Authors should automatically watch their own questions.
            QuestionReplyEvent.notify(self.creator, self)
Example #24
0
    def test_notification_created(self):
        """Creating a new question auto-watches it for answers."""

        u = UserFactory()
        q = QuestionFactory(creator=u, title='foo', content='bar')

        assert QuestionReplyEvent.is_notifying(u, q)
Example #25
0
    def save(self, update=False, *args, **kwargs):
        """Override save method to take care of updated if requested."""
        new = not self.id

        if not new:
            self.clear_cached_html()
            if update:
                self.updated = datetime.now()

        super(Question, self).save(*args, **kwargs)

        if new:
            # Avoid circular import, events.py imports Question
            from kitsune.questions.events import QuestionReplyEvent
            # Authors should automatically watch their own questions.
            QuestionReplyEvent.notify(self.creator, self)
Example #26
0
    def test_notification_created(self):
        """Creating a new question auto-watches it for answers."""

        u = UserFactory()
        q = QuestionFactory(creator=u, title='foo', content='bar')

        assert QuestionReplyEvent.is_notifying(u, q)
Example #27
0
    def test_notification_created(self):
        """Creating a new question auto-watches it for answers."""

        u = user(save=True)
        q = question(creator=u, title='foo', content='bar', save=True)

        assert QuestionReplyEvent.is_notifying(u, q)
Example #28
0
    def test_notification_created(self):
        """Creating a new question auto-watches it for answers."""

        u = User.objects.get(pk=118533)
        q = Question(creator=u, title='foo', content='bar')
        q.save()

        assert QuestionReplyEvent.is_notifying(u, q)
Example #29
0
def watch_question(request, question_id):
    """Start watching a question for replies or solution."""

    question = get_object_or_404(Question, pk=question_id, is_spam=False)
    form = WatchQuestionForm(request.user, request.POST)

    # Process the form
    msg = None
    if form.is_valid():
        user_or_email = (request.user if request.user.is_authenticated else
                         form.cleaned_data["email"])
        try:
            if form.cleaned_data["event_type"] == "reply":
                QuestionReplyEvent.notify(user_or_email, question)
            else:
                QuestionSolvedEvent.notify(user_or_email, question)
        except ActivationRequestFailed:
            msg = _("Could not send a message to that email address.")

    # Respond to ajax request
    if request.is_ajax():
        if form.is_valid():
            msg = msg or (_("You will be notified of updates by email.")
                          if request.user.is_authenticated else _(
                              "You should receive an email shortly "
                              "to confirm your subscription."))
            return HttpResponse(json.dumps({"message": msg}))

        if request.POST.get("from_vote"):
            tmpl = "questions/includes/question_vote_thanks.html"
        else:
            tmpl = "questions/includes/email_subscribe.html"

        html = render_to_string(tmpl,
                                context={
                                    "question": question,
                                    "watch_form": form
                                },
                                request=request)
        return HttpResponse(json.dumps({"html": html}))

    if msg:
        messages.add_message(request, messages.ERROR, msg)

    return HttpResponseRedirect(question.get_absolute_url())
Example #30
0
    def test_notify_anonymous(self):
        """Test that anonymous users are notified of new answers."""
        ANON_EMAIL = '*****@*****.**'
        QuestionReplyEvent.notify(ANON_EMAIL, self.question)
        self.makeAnswer()

        # One for the asker's email, and one for the anonymous email.
        eq_(2, len(mail.outbox))
        notification = [m for m in mail.outbox if m.to == [ANON_EMAIL]][0]

        eq_([ANON_EMAIL], notification.to)
        eq_("{0} commented on a Firefox question you're watching"
            .format(self.answer.creator.username),
            notification.subject)

        body = re.sub(r'auth=[a-zA-Z0-9%_-]+', 'auth=AUTH', notification.body)
        starts_with(body, ANSWER_EMAIL_TO_ANONYMOUS
                    .format(**self.format_args()))
Example #31
0
    def test_autowatch_reply(self, get_current):
        get_current.return_value.domain = 'testserver'

        u = user(save=True)
        t1 = question(save=True)
        t2 = question(save=True)
        assert not QuestionReplyEvent.is_notifying(u, t1)
        assert not QuestionReplyEvent.is_notifying(u, t2)

        self.client.login(username=u.username, password='******')
        s = Setting.objects.create(user=u, name='questions_watch_after_reply',
                                   value='True')
        data = {'content': 'some content'}
        post(self.client, 'questions.reply', data, args=[t1.id])
        assert QuestionReplyEvent.is_notifying(u, t1)

        s.value = 'False'
        s.save()
        post(self.client, 'questions.reply', data, args=[t2.id])
        assert not QuestionReplyEvent.is_notifying(u, t2)
    def test_autowatch_reply(self, get_current):
        get_current.return_value.domain = 'testserver'

        u = user(save=True)
        t1 = question(save=True)
        t2 = question(save=True)
        assert not QuestionReplyEvent.is_notifying(u, t1)
        assert not QuestionReplyEvent.is_notifying(u, t2)

        self.client.login(username=u.username, password='******')
        s = Setting.objects.create(user=u, name='questions_watch_after_reply',
                                   value='True')
        data = {'content': 'some content'}
        post(self.client, 'questions.reply', data, args=[t1.id])
        assert QuestionReplyEvent.is_notifying(u, t1)

        s.value = 'False'
        s.save()
        post(self.client, 'questions.reply', data, args=[t2.id])
        assert not QuestionReplyEvent.is_notifying(u, t2)
Example #33
0
    def test_notify_unique_auth_tokens(self, email_mock):
        """Test that arbitrary users get unique auth tokens."""
        auth_backend = TokenLoginBackend()
        auth_re = re.compile(r'auth=([a-zA-Z0-9%_-]+)')
        watcher = UserFactory()
        QuestionReplyEvent.notify(watcher, self.question)
        asker_id = self.question.creator.id
        self.makeAnswer()

        def get_auth_token(ctx):
            return auth_re.search(ctx['answer_url']).group(1).replace('%3D', '=')

        eq_(email_mock.call_count, 2)
        all_calls = email_mock.call_args_list
        for call in all_calls:
            ctx = call[1]['context_vars']
            user = ctx['to_user']
            if user.id == asker_id:
                auth = get_auth_token(ctx)
                eq_(user, auth_backend.authenticate(auth))
            else:
                assert auth_re.search(ctx['answer_url']) is None
Example #34
0
    def test_notify_unique_auth_tokens(self, email_mock):
        """Test that arbitrary users get unique auth tokens."""
        auth_backend = TokenLoginBackend()
        auth_re = re.compile(r'auth=([a-zA-Z0-9%_-]+)')
        watcher = UserFactory()
        QuestionReplyEvent.notify(watcher, self.question)
        asker_id = self.question.creator.id
        self.makeAnswer()

        def get_auth_token(ctx):
            return auth_re.search(ctx['answer_url']).group(1).replace('%3D', '=')

        eq_(email_mock.call_count, 2)
        all_calls = email_mock.call_args_list
        for call in all_calls:
            ctx = call[1]['context_vars']
            user = ctx['to_user']
            if user.id == asker_id:
                auth = get_auth_token(ctx)
                eq_(user, auth_backend.authenticate(auth))
            else:
                assert auth_re.search(ctx['answer_url']) is None
Example #35
0
    def save(self, update=True, no_notify=False, *args, **kwargs):
        """
        Override save method to update question info and take care of
        updated.
        """

        new = self.id is None

        if new:
            page = self.question.num_answers // config.ANSWERS_PER_PAGE + 1
            self.page = page
        else:
            self.updated = datetime.now()
            self.clear_cached_html()

        super(Answer, self).save(*args, **kwargs)

        self.question.num_answers = Answer.objects.filter(
            question=self.question, is_spam=False).count()
        latest = Answer.objects.filter(question=self.question,
                                       is_spam=False).order_by("-created")[:1]
        self.question.last_answer = self if new else latest[0] if len(
            latest) else None
        self.question.save(update)

        if new:
            # Occasionally, num_answers seems to get out of sync with the
            # actual number of answers. This changes it to pull from
            # uncached on the off chance that fixes it. Plus if we enable
            # caching of counts, this will continue to work.
            self.question.clear_cached_contributors()

            if not no_notify:
                # tidings
                # Avoid circular import: events.py imports Question.
                from kitsune.questions.events import QuestionReplyEvent

                if not self.is_spam:
                    QuestionReplyEvent(self).fire(exclude=self.creator)

                # actstream
                actstream.actions.follow(self.creator,
                                         self,
                                         send_action=False,
                                         actor_only=False)
                actstream.actions.follow(self.creator,
                                         self.question,
                                         send_action=False,
                                         actor_only=False)
Example #36
0
def update(request, flagged_object_id):
    """Update the status of a flagged object."""
    flagged = get_object_or_404(FlaggedObject, pk=flagged_object_id)
    new_status = request.POST.get("status")
    if new_status:
        ct = flagged.content_type
        # If the object is an Answer let's fire a notification
        # if the flag is invalid
        if str(new_status) == str(
                FlaggedObject.FLAG_REJECTED) and ct.model_class() == Answer:
            answer = flagged.content_object
            QuestionReplyEvent(answer).fire(exclude=answer.creator)

        flagged.status = new_status
        flagged.save()

    return HttpResponseRedirect(reverse("flagit.queue"))
Example #37
0
def _answers_data(request,
                  question_id,
                  form=None,
                  watch_form=None,
                  answer_preview=None):
    """Return a map of the minimal info necessary to draw an answers page."""
    question = get_object_or_404(Question, pk=question_id)
    answers_ = question.answers.all()

    # Remove spam flag if an answer passed the moderation queue
    if not settings.READ_ONLY:
        answers_.filter(flags__status=2).update(is_spam=False)

    if not request.user.has_perm("flagit.can_moderate"):
        answers_ = answers_.filter(is_spam=False)

    answers_ = paginate(request, answers_, per_page=config.ANSWERS_PER_PAGE)
    feed_urls = ((
        reverse("questions.answers.feed", kwargs={"question_id": question_id}),
        AnswersFeed().title(question),
    ), )
    frequencies = dict(FREQUENCY_CHOICES)

    is_watching_question = request.user.is_authenticated and (
        QuestionReplyEvent.is_notifying(request.user, question)
        or QuestionSolvedEvent.is_notifying(request.user, question))
    return {
        "question": question,
        "answers": answers_,
        "form": form or AnswerForm(),
        "answer_preview": answer_preview,
        "watch_form": watch_form or _init_watch_form(request, "reply"),
        "feeds": feed_urls,
        "frequencies": frequencies,
        "is_watching_question": is_watching_question,
        "can_tag": request.user.has_perm("questions.tag_question"),
        "can_create_tags": request.user.has_perm("taggit.add_tag"),
    }
    def test_answer_notification(self, get_current):
        """Assert that hitting the watch toggle toggles and that proper mails
        are sent to anonymous users, registered users, and the question
        asker."""
        # TODO: This test is way too monolithic, and the fixtures encode
        # assumptions that aren't obvious here. Split this test into about 5,
        # each of which tests just 1 thing. Consider using instantiation
        # helpers.
        get_current.return_value.domain = 'testserver'

        # An arbitrary registered user watches:
        watcher = user(save=True)
        q = self._toggle_watch_question('reply', watcher, turn_on=True)

        # An anonymous user watches:
        QuestionReplyEvent.notify('*****@*****.**', q)

        # The question asker watches:
        QuestionReplyEvent.notify(q.creator, q)

        # Post a reply
        replier = user(save=True)
        self.client.login(username=replier.username, password='******')
        post(self.client, 'questions.reply', {'content': 'an answer'},
             args=[q.id])

        a = Answer.uncached.filter().order_by('-id')[0]

        # Order of emails is not important.
        eq_(3, len(mail.outbox))

        emails_to = [m.to[0] for m in mail.outbox]

        i = emails_to.index(watcher.email)
        attrs_eq(mail.outbox[i], to=[watcher.email],
                 subject='%s commented on a Firefox question '
                         "you're watching" % a.creator.username)
        body = mail.outbox[i].body
        body = re.sub(r'auth=[a-zA-Z0-9%_-]+', r'auth=AUTH', body)
        starts_with(body, ANSWER_EMAIL.format(
            to_user=watcher.username,
            title=q.title,
            content=a.content,
            replier=replier.username,
            question_id=q.id,
            answer_id=a.id))

        i = emails_to.index(q.creator.email)
        attrs_eq(mail.outbox[i], to=[q.creator.email],
                 subject='%s posted an answer to your question "%s"' %
                         (a.creator.username, q.title))
        body = mail.outbox[i].body
        body = re.sub(r'auth=[a-zA-Z0-9%_-]+', r'auth=AUTH', body)
        starts_with(body, ANSWER_EMAIL_TO_ASKER.format(
            asker=q.creator.username,
            title=q.title,
            content=a.content,
            replier=replier.username,
            question_id=q.id,
            answer_id=a.id))

        i = emails_to.index('*****@*****.**')
        attrs_eq(mail.outbox[i], to=['*****@*****.**'],
                 subject="%s commented on a Firefox question you're watching" %
                         a.creator.username)
        body = mail.outbox[i].body
        body = re.sub(r'auth=[a-zA-Z0-9%_-]+', r'auth=AUTH', body)
        starts_with(body, ANSWER_EMAIL_TO_ANONYMOUS.format(
            title=q.title,
            content=a.content,
            replier=replier.username,
            question_id=q.id,
            answer_id=a.id))
Example #39
0
def unwatch_question(request, question_id):
    """Stop watching a question."""
    question = get_object_or_404(Question, pk=question_id)
    QuestionReplyEvent.stop_notifying(request.user, question)
    QuestionSolvedEvent.stop_notifying(request.user, question)
    return HttpResponseRedirect(question.get_absolute_url())
Example #40
0
    def setUp(self):
        self.user = UserFactory()
        self.client.login(username=self.user.username, password='******')

        self.question = QuestionFactory(creator=self.user)
        QuestionReplyEvent.notify(self.user, self.question)
Example #41
0
    def setUp(self):
        self.user = UserFactory()
        self.client.login(username=self.user.username, password='******')

        self.question = QuestionFactory(creator=self.user)
        QuestionReplyEvent.notify(self.user, self.question)
 def setUp(self):
     super(TestAnswerNotifications, self).setUp()
     self._get_current_mock = mock.patch.object(Site.objects, 'get_current')
     self._get_current_mock.start().return_value.domain = 'testserver'
     self.question = QuestionFactory()
     QuestionReplyEvent.notify(self.question.creator, self.question)
Example #43
0
    def test_answer_notification(self, get_current):
        """Assert that hitting the watch toggle toggles and that proper mails
        are sent to anonymous users, registered users, and the question
        asker."""
        # TODO: This test is way too monolithic, and the fixtures encode
        # assumptions that aren't obvious here. Split this test into about 5,
        # each of which tests just 1 thing. Consider using instantiation
        # helpers.
        get_current.return_value.domain = 'testserver'

        # An arbitrary registered user watches:
        watcher = user(save=True)
        q = self._toggle_watch_question('reply', watcher, turn_on=True)

        # An anonymous user watches:
        QuestionReplyEvent.notify('*****@*****.**', q)

        # The question asker watches:
        QuestionReplyEvent.notify(q.creator, q)

        # Post a reply
        replier = user(save=True)
        self.client.login(username=replier.username, password='******')
        post(self.client,
             'questions.reply', {'content': 'an answer'},
             args=[q.id])

        a = Answer.uncached.filter().order_by('-id')[0]

        # Order of emails is not important.
        eq_(3, len(mail.outbox))

        emails_to = [m.to[0] for m in mail.outbox]

        i = emails_to.index(watcher.email)
        attrs_eq(mail.outbox[i],
                 to=[watcher.email],
                 subject='%s commented on a Firefox question '
                 "you're watching" % a.creator.username)
        starts_with(
            mail.outbox[i].body,
            ANSWER_EMAIL.format(to_user=watcher.username,
                                title=q.title,
                                content=a.content,
                                replier=replier.username,
                                question_id=q.id,
                                answer_id=a.id))

        i = emails_to.index(q.creator.email)
        attrs_eq(mail.outbox[i],
                 to=[q.creator.email],
                 subject='%s posted an answer to your question "%s"' %
                 (a.creator.username, q.title))
        starts_with(
            mail.outbox[i].body,
            ANSWER_EMAIL_TO_ASKER.format(asker=q.creator.username,
                                         title=q.title,
                                         content=a.content,
                                         replier=replier.username,
                                         question_id=q.id,
                                         answer_id=a.id))

        i = emails_to.index('*****@*****.**')
        attrs_eq(mail.outbox[i],
                 to=['*****@*****.**'],
                 subject="%s commented on a Firefox question you're watching" %
                 a.creator.username)
        starts_with(
            mail.outbox[i].body,
            ANSWER_EMAIL_TO_ANONYMOUS.format(title=q.title,
                                             content=a.content,
                                             replier=replier.username,
                                             question_id=q.id,
                                             answer_id=a.id))