def test_thread_summary_rendering_dummy_cache(self):
        cache.cache = DummyCache('', {})  # Disable caching

        ss = SearchState.get_empty()
        thread = self.q.thread
        test_html = thread.get_summary_html(search_state=ss)

        context = {
            'thread': thread,
            'question': thread._question_post(),
            'search_state': ss,
            'visitor': None
        }
        proper_html = get_template('widgets/question_summary.html').render(
            context)
        self.assertEqual(test_html, proper_html)

        # Make double-check that all tags are included
        self.assertTrue(ss.add_tag('tag1').full_url() in test_html)
        self.assertTrue(ss.add_tag('tag2').full_url() in test_html)
        self.assertTrue(ss.add_tag('tag3').full_url() in test_html)
        self.assertFalse(ss.add_tag('mini-mini').full_url() in test_html)

        # Make sure that title and body text are escaped properly.
        # This should be obvious at this point, if the above test passes, but why not be explicit
        # UPDATE: And voila, these tests catched double-escaping bug in template, where `<` was `<`
        #         And indeed, post.summary is escaped before saving, in parse_and_save()
        # UPDATE 2:Weird things happen with question summary (it's double escaped etc., really weird) so
        # let's just make sure that there are no tag placeholders left
        self.assertTrue(
            '<<<tag1>>> fake title' in proper_html)
        #self.assertTrue('<<<tag2>>> <<<tag3>>> cheating' in proper_html)
        self.assertFalse('<<<tag1>>>' in proper_html)
        self.assertFalse('<<<tag2>>>' in proper_html)
        self.assertFalse('<<<tag3>>>' in proper_html)

        ###

        ss = ss.add_tag('mini-mini')
        context['search_state'] = ss
        test_html = thread.get_summary_html(search_state=ss)
        proper_html = get_template('widgets/question_summary.html').render(
            context)

        self.assertEqual(test_html, proper_html)

        # Make double-check that all tags are included (along with `mini-mini` tag)
        self.assertTrue(ss.add_tag('tag1').full_url() in test_html)
        self.assertTrue(ss.add_tag('tag2').full_url() in test_html)
        self.assertTrue(ss.add_tag('tag3').full_url() in test_html)
    def test_thread_summary_locmem_cache(self):
        cache.cache = LocMemCache('', {})  # Enable local caching

        thread = self.q.thread
        key = Thread.SUMMARY_CACHE_KEY_TPL % thread.id

        self.assertTrue(thread.summary_html_cached())
        self.assertIsNotNone(thread.get_cached_summary_html())

        ###
        cache.cache.delete(key)  # let's start over

        self.assertFalse(thread.summary_html_cached())
        self.assertIsNone(thread.get_cached_summary_html())

        context = {
            'thread': thread,
            'question': self.q,
            'search_state': DummySearchState(),
        }
        html = get_template('widgets/question_summary.html').render(context)
        filled_html = html.replace('<<<tag1>>>', SearchState.get_empty().add_tag('tag1').full_url())\
                          .replace('<<<tag2>>>', SearchState.get_empty().add_tag('tag2').full_url())\
                          .replace('<<<tag3>>>', SearchState.get_empty().add_tag('tag3').full_url())

        self.assertEqual(
            filled_html,
            thread.get_summary_html(search_state=SearchState.get_empty()))
        self.assertTrue(thread.summary_html_cached())
        self.assertEqual(html, thread.get_cached_summary_html())

        ###
        cache.cache.set(key, 'Test <<<tag1>>>', timeout=100)

        self.assertTrue(thread.summary_html_cached())
        self.assertEqual('Test <<<tag1>>>', thread.get_cached_summary_html())
        self.assertEqual(
            'Test %s' % SearchState.get_empty().add_tag('tag1').full_url(),
            thread.get_summary_html(search_state=SearchState.get_empty()))

        ###
        cache.cache.set(key, 'TestBBB <<<tag1>>>', timeout=100)

        self.assertTrue(thread.summary_html_cached())
        self.assertEqual('TestBBB <<<tag1>>>',
                         thread.get_cached_summary_html())
        self.assertEqual(
            'TestBBB %s' % SearchState.get_empty().add_tag('tag1').full_url(),
            thread.get_summary_html(search_state=SearchState.get_empty()))

        ###
        cache.cache.delete(key)
        thread.update_summary_html = lambda dummy: "Monkey-patched <<<tag2>>>"

        self.assertFalse(thread.summary_html_cached())
        self.assertIsNone(thread.get_cached_summary_html())
        self.assertEqual(
            'Monkey-patched %s' %
            SearchState.get_empty().add_tag('tag2').full_url(),
            thread.get_summary_html(search_state=SearchState.get_empty()))
Exemple #3
0
def VALIDATE_EMAIL(parts=None, reply_address_object=None, from_address=None, **kwargs):
    """process the validation email and save
    the email signature
    todo: go a step further and
    """
    reply_code = reply_address_object.address
    try:
        content, stored_files, signature = mail.process_parts(parts, reply_code)
        user = reply_address_object.user
        if signature and signature != user.email_signature:
            user.email_signature = signature
        user.email_isvalid = True
        user.save()

        data = {
            "site_name": askbot_settings.APP_SHORT_NAME,
            "site_url": askbot_settings.APP_URL,
            "ask_address": "ask@" + askbot_settings.REPLY_BY_EMAIL_HOSTNAME,
        }
        template = get_template("email/re_welcome_lamson_on.html")

        mail.send_mail(
            subject_line=_("Re: Welcome to %(site_name)s") % data,
            body_text=template.render(Context(data)),
            recipient_list=[from_address],
        )
    except ValueError:
        raise ValueError(_("Please reply to the welcome email " "without editing it"))
Exemple #4
0
def edit_group_membership(request):
    form = forms.EditGroupMembershipForm(request.POST)
    if form.is_valid():
        group_name = form.cleaned_data['group_name']
        user_id = form.cleaned_data['user_id']
        try:
            user = models.User.objects.get(id = user_id)
        except models.User.DoesNotExist:
            raise exceptions.PermissionDenied(
                'user with id %d not found' % user_id
            )

        action = form.cleaned_data['action']
        #warning: possible race condition
        if action == 'add':
            group_params = {'group_name': group_name, 'user': user}
            group = models.Tag.group_tags.get_or_create(**group_params)
            request.user.edit_group_membership(user, group, 'add')
            template = get_template('widgets/group_snippet.html')
            return {
                'name': group.name,
                'description': getattr(group.tag_wiki, 'text', ''),
                'html': template.render({'group': group})
            }
        elif action == 'remove':
            try:
                group = models.Tag.group_tags.get_by_name(group_name = group_name)
                request.user.edit_group_membership(user, group, 'remove')
            except models.Tag.DoesNotExist:
                raise exceptions.PermissionDenied()
        else:
            raise exceptions.PermissionDenied()
    else:
        raise exceptions.PermissionDenied()
Exemple #5
0
def edit_group_membership(request):
    form = forms.EditGroupMembershipForm(request.POST)
    if form.is_valid():
        group_name = form.cleaned_data['group_name']
        user_id = form.cleaned_data['user_id']
        try:
            user = models.User.objects.get(id = user_id)
        except models.User.DoesNotExist:
            raise exceptions.PermissionDenied(
                'user with id %d not found' % user_id
            )

        action = form.cleaned_data['action']
        #warning: possible race condition
        if action == 'add':
            group_params = {'group_name': group_name, 'user': user}
            group = models.Tag.group_tags.get_or_create(**group_params)
            request.user.edit_group_membership(user, group, 'add')
            template = get_template('widgets/group_snippet.html')
            return {
                'name': group.name,
                'description': getattr(group.tag_wiki, 'text', ''),
                'html': template.render({'group': group})
            }
        elif action == 'remove':
            try:
                group = models.Tag.group_tags.get_by_name(group_name = group_name)
                request.user.edit_group_membership(user, group, 'remove')
            except models.Tag.DoesNotExist:
                raise exceptions.PermissionDenied()
        else:
            raise exceptions.PermissionDenied()
    else:
        raise exceptions.PermissionDenied()
Exemple #6
0
def report(type, exercises, with_solutions=True, base_url='http://localhost'):
    '''
    render pdf/rtf/txt report
    '''
    now = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
    text = get_template('report/%s.html' % type).render({
        'exercises': exercises,
        'with_solutions': with_solutions,
        'now': now,
        'base_url': base_url,
    })

    if type == 'pdf':
        fp = StringIO()
        try:
            pdf = pisaDocument(latex2img(text), fp, link_callback=_upfile_path)
            return fp.getvalue()
        except:
            pass
        finally:
            fp.close()
    elif type == 'rtf':
        convetor = HTML2RTF()
        convetor.feed(latex2img(text))
        return convetor.get_rtf()
    else:
        text = html_entity_decode(text)
        return html2text(text)
 def setUp(self):
     self.template_name = 'email/welcome_lamson_on.html'
     self.context = {'site_name': 'askbot.com',
                     'email_code': 'DwFwndQty'}
     template = get_template(self.template_name)
     self.rendered_template = template.render(Context(self.context))
     self.expected_output = 'Welcome to askbot.com!\n\nImportant: Please reply to this message, without editing it. We need this to determine your email signature and that the email address is valid and was typed correctly.\n\nUntil we receive the response from you, you will not be able ask or answer questions on askbot.com by email.\n\nSincerely,askbot.com Administrator\n\nDwFwndQty'
Exemple #8
0
def VALIDATE_EMAIL(parts=None,
                   reply_address_object=None,
                   from_address=None,
                   **kwargs):
    """process the validation email and save
    the email signature
    todo: go a step further and
    """
    reply_code = reply_address_object.address
    try:
        content, stored_files, signature = mail.process_parts(
            parts, reply_code)
        user = reply_address_object.user
        if signature and signature != user.email_signature:
            user.email_signature = signature
        user.email_isvalid = True
        user.save()

        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': askbot_settings.APP_URL,
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(subject_line=_('Re: Welcome to %(site_name)s') % data,
                       body_text=template.render(Context(data)),
                       recipient_list=[
                           from_address,
                       ])
    except ValueError:
        raise ValueError(
            _('Please reply to the welcome email '
              'without editing it'))
Exemple #9
0
def edit_group_membership(request):
    form = forms.EditGroupMembershipForm(request.POST)
    if form.is_valid():
        group_name = form.cleaned_data["group_name"]
        user_id = form.cleaned_data["user_id"]
        try:
            user = models.User.objects.get(id=user_id)
        except models.User.DoesNotExist:
            raise exceptions.PermissionDenied("user with id %d not found" % user_id)

        action = form.cleaned_data["action"]
        # warning: possible race condition
        if action == "add":
            group_params = {"group_name": group_name, "user": user}
            group = models.Tag.group_tags.get_or_create(**group_params)
            request.user.edit_group_membership(user, group, "add")
            template = get_template("widgets/group_snippet.html")
            return {
                "name": group.name,
                "description": getattr(group.tag_wiki, "text", ""),
                "html": template.render({"group": group}),
            }
        elif action == "remove":
            try:
                group = models.Tag.group_tags.get_by_name(group_name=group_name)
                request.user.edit_group_membership(user, group, "remove")
            except models.Tag.DoesNotExist:
                raise exceptions.PermissionDenied()
        else:
            raise exceptions.PermissionDenied()
    else:
        raise exceptions.PermissionDenied()
Exemple #10
0
def feedback(request):
    data = {'page_class': 'meta'}
    form = None

    if askbot_settings.ALLOW_ANONYMOUS_FEEDBACK is False:
        if request.user.is_anonymous():
            message = _('Please sign in or register to send your feedback')
            request.user.message_set.create(message=message)
            redirect_url = get_login_url() + '?next=' + request.path
            return HttpResponseRedirect(redirect_url)

    if request.method == "POST":
        form = FeedbackForm(is_auth=request.user.is_authenticated(),
                            data=request.POST)
        if form.is_valid():
            if not request.user.is_authenticated():
                data['email'] = form.cleaned_data.get('email', None)
            data['message'] = form.cleaned_data['message']
            data['name'] = form.cleaned_data.get('name', None)
            template = get_template('email/feedback_email.txt', request)
            message = template.render(RequestContext(request, data))
            mail_moderators(_('Q&A forum feedback'), message)
            msg = _('Thanks for the feedback!')
            request.user.message_set.create(message=msg)
            return HttpResponseRedirect(get_next_url(request))
    else:
        form = FeedbackForm(is_auth=request.user.is_authenticated(),
                            initial={'next': get_next_url(request)})

    data['form'] = form
    return render_into_skin('feedback.html', data, request)
Exemple #11
0
def feedback(request):
    data = {'page_class': 'meta'}
    form = None

    if askbot_settings.ALLOW_ANONYMOUS_FEEDBACK is False:
        if request.user.is_anonymous():
            message = _('Please sign in or register to send your feedback')
            request.user.message_set.create(message=message)
            redirect_url = get_login_url() + '?next=' + request.path
            return HttpResponseRedirect(redirect_url)

    if request.method == "POST":
        form = FeedbackForm(
            is_auth=request.user.is_authenticated(),
            data=request.POST
        )
        if form.is_valid():
            if not request.user.is_authenticated():
                data['email'] = form.cleaned_data.get('email',None)
            data['message'] = form.cleaned_data['message']
            data['name'] = form.cleaned_data.get('name',None)
            template = get_template('email/feedback_email.txt', request)
            message = template.render(RequestContext(request, data))
            mail_moderators(_('Q&A forum feedback'), message)
            msg = _('Thanks for the feedback!')
            request.user.message_set.create(message=msg)
            return HttpResponseRedirect(get_next_url(request))
    else:
        form = FeedbackForm(is_auth = request.user.is_authenticated(),
                            initial={'next':get_next_url(request)})

    data['form'] = form
    return render_into_skin('feedback.html', data, request)
    def test_thread_summary_rendering_dummy_cache(self):
        cache.cache = DummyCache('', {})  # Disable caching

        ss = SearchState.get_empty()
        thread = self.q.thread
        test_html = thread.get_summary_html(search_state=ss)

        context = {
            'thread': thread,
            'question': thread._question_post(),
            'search_state': ss,
            'visitor': None
        }
        proper_html = get_template('widgets/question_summary.html').render(context)
        self.assertEqual(test_html, proper_html)

        # Make double-check that all tags are included
        self.assertTrue(ss.add_tag('tag1').full_url() in test_html)
        self.assertTrue(ss.add_tag('tag2').full_url() in test_html)
        self.assertTrue(ss.add_tag('tag3').full_url() in test_html)
        self.assertFalse(ss.add_tag('mini-mini').full_url() in test_html)

        # Make sure that title and body text are escaped properly.
        # This should be obvious at this point, if the above test passes, but why not be explicit
        # UPDATE: And voila, these tests catched double-escaping bug in template, where `&lt;` was `&amp;lt;`
        #         And indeed, post.summary is escaped before saving, in parse_and_save()
        # UPDATE 2:Weird things happen with question summary (it's double escaped etc., really weird) so
        # let's just make sure that there are no tag placeholders left
        self.assertTrue('&lt;&lt;&lt;tag1&gt;&gt;&gt; fake title' in proper_html)
        #self.assertTrue('&lt;&lt;&lt;tag2&gt;&gt;&gt; &lt;&lt;&lt;tag3&gt;&gt;&gt; cheating' in proper_html)
        self.assertFalse('<<<tag1>>>' in proper_html)
        self.assertFalse('<<<tag2>>>' in proper_html)
        self.assertFalse('<<<tag3>>>' in proper_html)

        ###

        ss = ss.add_tag('mini-mini')
        context['search_state'] = ss
        test_html = thread.get_summary_html(search_state=ss)
        proper_html = get_template('widgets/question_summary.html').render(context)

        self.assertEqual(test_html, proper_html)

        # Make double-check that all tags are included (along with `mini-mini` tag)
        self.assertTrue(ss.add_tag('tag1').full_url() in test_html)
        self.assertTrue(ss.add_tag('tag2').full_url() in test_html)
        self.assertTrue(ss.add_tag('tag3').full_url() in test_html)
    def test_thread_summary_locmem_cache(self):
        cache.cache = LocMemCache('', {})  # Enable local caching

        thread = self.q.thread
        key = Thread.SUMMARY_CACHE_KEY_TPL % thread.id

        self.assertTrue(thread.summary_html_cached())
        self.assertIsNotNone(thread.get_cached_summary_html())

        ###
        cache.cache.delete(key) # let's start over

        self.assertFalse(thread.summary_html_cached())
        self.assertIsNone(thread.get_cached_summary_html())

        context = {
            'thread': thread,
            'question': self.q,
            'search_state': DummySearchState(),
        }
        html = get_template('widgets/question_summary.html').render(context)
        filled_html = html.replace('<<<tag1>>>', SearchState.get_empty().add_tag('tag1').full_url())\
                          .replace('<<<tag2>>>', SearchState.get_empty().add_tag('tag2').full_url())\
                          .replace('<<<tag3>>>', SearchState.get_empty().add_tag('tag3').full_url())

        self.assertEqual(filled_html, thread.get_summary_html(search_state=SearchState.get_empty()))
        self.assertTrue(thread.summary_html_cached())
        self.assertEqual(html, thread.get_cached_summary_html())

        ###
        cache.cache.set(key, 'Test <<<tag1>>>', timeout=100)

        self.assertTrue(thread.summary_html_cached())
        self.assertEqual('Test <<<tag1>>>', thread.get_cached_summary_html())
        self.assertEqual(
            'Test %s' % SearchState.get_empty().add_tag('tag1').full_url(),
            thread.get_summary_html(search_state=SearchState.get_empty())
        )

        ###
        cache.cache.set(key, 'TestBBB <<<tag1>>>', timeout=100)

        self.assertTrue(thread.summary_html_cached())
        self.assertEqual('TestBBB <<<tag1>>>', thread.get_cached_summary_html())
        self.assertEqual(
            'TestBBB %s' % SearchState.get_empty().add_tag('tag1').full_url(),
            thread.get_summary_html(search_state=SearchState.get_empty())
        )

        ###
        cache.cache.delete(key)
        thread.update_summary_html = lambda: "Monkey-patched <<<tag2>>>"

        self.assertFalse(thread.summary_html_cached())
        self.assertIsNone(thread.get_cached_summary_html())
        self.assertEqual(
            'Monkey-patched %s' % SearchState.get_empty().add_tag('tag2').full_url(),
            thread.get_summary_html(search_state=SearchState.get_empty())
        )
def process_reply(func):
    @functools.wraps(func)
    def wrapped(message, host = None, address = None):
        """processes forwarding rules, and run the handler
        in the case of error, send a bounce email
        """

        try:
            for rule in django_settings.LAMSON_FORWARD:
                if re.match(rule['pattern'], message.base['to']):
                    relay = Relay(host=rule['host'],
                               port=rule['port'], debug=1)
                    relay.deliver(message)
                    return
        except AttributeError:
            pass

        error = None

        try:
            reply_address = ReplyAddress.objects.get(
                                            address = address,
                                            allowed_from_email = message.From
                                        )

            #here is the business part of this function
            parts = get_parts(message)
            for part_type, content in parts:
                if part_type == 'body':
                    print '==============================='
                    print 'message :', content
                    break
                else:
                    continue
            func(
                from_address = message.From,
                subject_line = message['Subject'],
                parts = parts,
                reply_address_object = reply_address
            )

        except ReplyAddress.DoesNotExist:
            error = _("You were replying to an email address\
             unknown to the system or you were replying from a different address from the one where you\
             received the notification.")
        except Exception, e:
            import sys
            sys.stderr.write(str(e))
            import traceback
            sys.stderr.write(traceback.format_exc())

        if error is not None:
            template = get_template('email/reply_by_email_error.html')
            body_text = template.render(Context({'error':error}))
            mail.send_mail(
                subject_line = "Error posting your reply",
                body_text = body_text,
                recipient_list = [message.From],
            )
 def _html_for_question(self, q):
     context = {
         'thread': q.thread,
         'question': q,
         'search_state': DummySearchState(),
         }
     html = get_template('widgets/question_summary.html').render(context)
     return html
Exemple #16
0
def get_html_template(request):
    """returns rendered template"""
    template_name = request.REQUEST.get("template_name", None)
    allowed_templates = ("widgets/tag_category_selector.html",)
    # have allow simple context for the templates
    if template_name not in allowed_templates:
        raise Http404
    return {"html": get_template(template_name).render()}
def PROCESS(
    parts = None,
    reply_address_object = None,
    subject_line = None,
    from_address = None,
    **kwargs
):
    """handler to process the emailed message
    and make a post to askbot based on the contents of
    the email, including the text body and the file attachments"""
    #1) get actual email content 
    #   todo: factor this out into the process_reply decorator
    reply_code = reply_address_object.address
    body_text, stored_files, signature = mail.process_parts(parts, reply_code)

    #2) process body text and email signature
    user = reply_address_object.user
    if signature:#if there, then it was stripped
        if signature != user.email_signature:
            user.email_signature = signature
    else:#try to strip signature
        stripped_body_text = user.strip_email_signature(body_text)
        #todo: add test cases for emails without the signature
        if stripped_body_text == body_text and user.email_signature:
            #todo: send an email asking to update the signature
            raise ValueError('email signature changed or unknown')
        body_text = stripped_body_text

    #3) validate email address and save user
    user.email_isvalid = True
    user.save()#todo: actually, saving is not necessary, if nothing changed

    #4) actually make an edit in the forum
    robj = reply_address_object
    add_post_actions = ('post_comment', 'post_answer', 'auto_answer_or_comment')
    if robj.reply_action == 'replace_content':
        robj.edit_post(body_text, title = subject_line)
    elif robj.reply_action == 'append_content':
        robj.edit_post(body_text)#in this case we don't touch the title
    elif robj.reply_action in add_post_actions:
        if robj.was_used:
            robj.edit_post(body_text, edit_response = True)
        else:
            robj.create_reply(body_text)
    elif robj.reply_action == 'validate_email':
        #todo: this is copy-paste - factor it out to askbot.mail.messages
        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': askbot_settings.APP_URL,
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(
            subject_line = _('Re: %s') % subject_line,
            body_text = template.render(Context(data)),
            recipient_list = [from_address,]
        )
    def test_thread_summary_locmem_cache(self):
        cache.cache = LocMemCache("", {})  # Enable local caching

        thread = self.q.thread
        key = Thread.SUMMARY_CACHE_KEY_TPL % thread.id

        self.assertTrue(thread.summary_html_cached())
        self.assertIsNotNone(thread.get_cached_summary_html())

        ###
        cache.cache.delete(key)  # let's start over

        self.assertFalse(thread.summary_html_cached())
        self.assertIsNone(thread.get_cached_summary_html())

        context = {"thread": thread, "question": self.q, "search_state": DummySearchState()}
        html = get_template("widgets/question_summary.html").render(context)
        filled_html = (
            html.replace("<<<tag1>>>", SearchState.get_empty().add_tag("tag1").full_url())
            .replace("<<<tag2>>>", SearchState.get_empty().add_tag("tag2").full_url())
            .replace("<<<tag3>>>", SearchState.get_empty().add_tag("tag3").full_url())
        )

        self.assertEqual(filled_html, thread.get_summary_html(search_state=SearchState.get_empty()))
        self.assertTrue(thread.summary_html_cached())
        self.assertEqual(html, thread.get_cached_summary_html())

        ###
        cache.cache.set(key, "Test <<<tag1>>>", timeout=100)

        self.assertTrue(thread.summary_html_cached())
        self.assertEqual("Test <<<tag1>>>", thread.get_cached_summary_html())
        self.assertEqual(
            "Test %s" % SearchState.get_empty().add_tag("tag1").full_url(),
            thread.get_summary_html(search_state=SearchState.get_empty()),
        )

        ###
        cache.cache.set(key, "TestBBB <<<tag1>>>", timeout=100)

        self.assertTrue(thread.summary_html_cached())
        self.assertEqual("TestBBB <<<tag1>>>", thread.get_cached_summary_html())
        self.assertEqual(
            "TestBBB %s" % SearchState.get_empty().add_tag("tag1").full_url(),
            thread.get_summary_html(search_state=SearchState.get_empty()),
        )

        ###
        cache.cache.delete(key)
        thread.update_summary_html = lambda: "Monkey-patched <<<tag2>>>"

        self.assertFalse(thread.summary_html_cached())
        self.assertIsNone(thread.get_cached_summary_html())
        self.assertEqual(
            "Monkey-patched %s" % SearchState.get_empty().add_tag("tag2").full_url(),
            thread.get_summary_html(search_state=SearchState.get_empty()),
        )
Exemple #19
0
 def _html_for_exercise(self, q):
     context = {
         'thread': q.thread,
         'exercise': q,
         'search_state': DummySearchState(),
         'visitor': None
     }
     html = get_template('widgets/exercise_summary.html').render(context)
     return html
Exemple #20
0
def render_ask_widget_js(request, widget_id):
    widget = get_object_or_404(models.AskWidget, pk=widget_id)
    variable_name = "AskbotAskWidget%d" % widget.id
    content_tpl =  get_template('embed/askbot_widget.js', request)
    context_dict = {'widget': widget,
                    'host': request.get_host(),
                    'variable_name': variable_name}
    content =  content_tpl.render(Context(context_dict))
    return HttpResponse(content, mimetype='text/javascript')
Exemple #21
0
 def _html_for_exercise(self, q):
     context = {
         'thread': q.thread,
         'exercise': q,
         'search_state': DummySearchState(),
         'visitor': None
     }
     html = get_template('widgets/exercise_summary.html').render(context)
     return html
Exemple #22
0
def PROCESS(parts=None,
            reply_address_object=None,
            subject_line=None,
            from_address=None,
            **kwargs):
    """handler to process the emailed message
    and make a post to askbot based on the contents of
    the email, including the text body and the file attachments"""
    #1) get actual email content
    #   todo: factor this out into the process_reply decorator
    reply_code = reply_address_object.address
    body_text, stored_files, signature = mail.process_parts(parts, reply_code)

    #2) process body text and email signature
    user = reply_address_object.user
    if signature:  #if there, then it was stripped
        if signature != user.email_signature:
            user.email_signature = signature
    else:  #try to strip signature
        stripped_body_text = user.strip_email_signature(body_text)
        #todo: add test cases for emails without the signature
        if stripped_body_text == body_text and user.email_signature:
            #todo: send an email asking to update the signature
            raise ValueError('email signature changed or unknown')
        body_text = stripped_body_text

    #3) validate email address and save user
    user.email_isvalid = True
    user.save()  #todo: actually, saving is not necessary, if nothing changed

    #4) actually make an edit in the forum
    robj = reply_address_object
    add_post_actions = ('post_comment', 'post_answer',
                        'auto_answer_or_comment')
    if robj.reply_action == 'replace_content':
        robj.edit_post(body_text, title=subject_line)
    elif robj.reply_action == 'append_content':
        robj.edit_post(body_text)  #in this case we don't touch the title
    elif robj.reply_action in add_post_actions:
        if robj.was_used:
            robj.edit_post(body_text, edit_response=True)
        else:
            robj.create_reply(body_text)
    elif robj.reply_action == 'validate_email':
        #todo: this is copy-paste - factor it out to askbot.mail.messages
        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': askbot_settings.APP_URL,
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(subject_line=_('Re: %s') % subject_line,
                       body_text=template.render(Context(data)),
                       recipient_list=[
                           from_address,
                       ])
Exemple #23
0
def process_reply(func):
    @functools.wraps(func)
    def wrapped(message, host=None, address=None):
        """processes forwarding rules, and run the handler
        in the case of error, send a bounce email
        """

        try:
            for rule in django_settings.LAMSON_FORWARD:
                if re.match(rule['pattern'], message.base['to']):
                    relay = Relay(host=rule['host'],
                                  port=rule['port'],
                                  debug=1)
                    relay.deliver(message)
                    return
        except AttributeError:
            pass

        error = None

        try:
            reply_address = ReplyAddress.objects.get(
                address=address, allowed_from_email=message.From)

            #here is the business part of this function
            parts = get_parts(message)
            for part_type, content in parts:
                if part_type == 'body':
                    print '==============================='
                    print 'message :', content
                    break
                else:
                    continue
            func(from_address=message.From,
                 subject_line=message['Subject'],
                 parts=parts,
                 reply_address_object=reply_address)

        except ReplyAddress.DoesNotExist:
            error = _("You were replying to an email address\
             unknown to the system or you were replying from a different address from the one where you\
             received the notification.")
        except Exception, e:
            import sys
            sys.stderr.write(str(e))
            import traceback
            sys.stderr.write(traceback.format_exc())

        if error is not None:
            template = get_template('email/reply_by_email_error.html')
            body_text = template.render(Context({'error': error}))
            mail.send_mail(
                subject_line="Error posting your reply",
                body_text=body_text,
                recipient_list=[message.From],
            )
Exemple #24
0
def render_ask_widget_css(request, widget_id):
    widget = get_object_or_404(models.AskWidget, pk=widget_id)
    variable_name = "AskbotAskWidget%d" % widget.id
    content_tpl =  get_template('embed/askbot_widget.css', request)
    context_dict = {'widget': widget,
                    'host': request.get_host(),
                    'editor_type': askbot_settings.EDITOR_TYPE,
                    'variable_name': variable_name}
    content =  content_tpl.render(Context(context_dict))
    return HttpResponse(content, mimetype='text/css')
Exemple #25
0
def notify_author_of_published_revision_celery_task(revision):
    #todo: move this to ``askbot.mail`` module
    #for answerable email only for now, because
    #we don't yet have the template for the read-only notification
    if askbot_settings.REPLY_BY_EMAIL:
        #generate two reply codes (one for edit and one for addition)
        #to format an answerable email or not answerable email
        reply_options = {
            'user': revision.author,
            'post': revision.post,
            'reply_action': 'append_content'
        }
        append_content_address = ReplyAddress.objects.create_new(
            **reply_options).as_email_address()
        reply_options['reply_action'] = 'replace_content'
        replace_content_address = ReplyAddress.objects.create_new(
            **reply_options).as_email_address()

        #populate template context variables
        reply_code = append_content_address + ',' + replace_content_address
        if revision.post.post_type == 'question':
            mailto_link_subject = revision.post.thread.title
        else:
            mailto_link_subject = _('An edit for my answer')
        #todo: possibly add more mailto thread headers to organize messages

        prompt = _('To add to your post EDIT ABOVE THIS LINE')
        reply_separator_line = const.SIMPLE_REPLY_SEPARATOR_TEMPLATE % prompt
        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'post': revision.post,
            'author_email_signature': revision.author.email_signature,
            'replace_content_address': replace_content_address,
            'reply_separator_line': reply_separator_line,
            'mailto_link_subject': mailto_link_subject,
            'reply_code': reply_code
        }

        #load the template
        from askbot.skins.loaders import get_template
        template = get_template('email/notify_author_about_approved_post.html')
        #todo: possibly add headers to organize messages in threads
        headers = {'Reply-To': append_content_address}
        #send the message
        mail.send_mail(
            subject_line=_('Your post at %(site_name)s is now published') %
            data,
            body_text=template.render(Context(data)),
            recipient_list=[
                revision.author.email,
            ],
            related_object=revision,
            activity_type=const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
            headers=headers)
Exemple #26
0
def _send_email_key(user):
    """private function. sends email containing validation key
    to user's email address
    """
    subject = _("Recover your %(site)s account") % {"site": askbot_settings.APP_SHORT_NAME}
    data = {
        "validation_link": askbot_settings.APP_URL + reverse("user_account_recover", kwargs={"key": user.email_key})
    }
    template = get_template("authopenid/email_validation.txt")
    message = template.render(data)
    send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
Exemple #27
0
def notify_author_of_published_revision_celery_task(revision):
    #todo: move this to ``askbot.mail`` module
    #for answerable email only for now, because
    #we don't yet have the template for the read-only notification
    if askbot_settings.REPLY_BY_EMAIL:
        #generate two reply codes (one for edit and one for addition)
        #to format an answerable email or not answerable email
        reply_options = {
            'user': revision.author,
            'post': revision.post,
            'reply_action': 'append_content'
        }
        append_content_address = ReplyAddress.objects.create_new(
                                                        **reply_options
                                                    ).as_email_address()
        reply_options['reply_action'] = 'replace_content'
        replace_content_address = ReplyAddress.objects.create_new(
                                                        **reply_options
                                                    ).as_email_address()

        #populate template context variables
        reply_code = append_content_address + ',' + replace_content_address
        if revision.post.post_type == 'question':
            mailto_link_subject = revision.post.thread.title
        else:
            mailto_link_subject = _('An edit for my answer')
        #todo: possibly add more mailto thread headers to organize messages

        prompt = _('To add to your post EDIT ABOVE THIS LINE')
        reply_separator_line = const.SIMPLE_REPLY_SEPARATOR_TEMPLATE % prompt
        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'post': revision.post,
            'author_email_signature': revision.author.email_signature,
            'replace_content_address': replace_content_address,
            'reply_separator_line': reply_separator_line,
            'mailto_link_subject': mailto_link_subject,
            'reply_code': reply_code
        }

        #load the template
        from askbot.skins.loaders import get_template
        template = get_template('email/notify_author_about_approved_post.html')
        #todo: possibly add headers to organize messages in threads
        headers = {'Reply-To': append_content_address}
        #send the message
        mail.send_mail(
            subject_line = _('Your post at %(site_name)s is now published') % data,
            body_text = template.render(Context(data)),
            recipient_list = [revision.author.email,],
            related_object = revision,
            activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
            headers = headers
        )
Exemple #28
0
 def update_summary_html(self):
     context = {
         'thread': self,
         'question': self._question_post(refresh=True),  # fetch new question post to make sure we're up-to-date
         'search_state': DummySearchState(),
     }
     html = get_template('widgets/question_summary.html').render(context)
     # INFO: Timeout is set to 30 days:
     # * timeout=0/None is not a reliable cross-backend way to set infinite timeout
     # * We probably don't need to pollute the cache with threads older than 30 days
     # * Additionally, Memcached treats timeouts > 30day as dates (https://code.djangoproject.com/browser/django/tags/releases/1.3/django/core/cache/backends/memcached.py#L36),
     #   which probably doesn't break anything but if we can stick to 30 days then let's stick to it
     cache.cache.set(self.SUMMARY_CACHE_KEY_TPL % self.id, html, timeout=60*60*24*30)
     return html
Exemple #29
0
def _send_email_key(user):
    """private function. sends email containing validation key
    to user's email address
    """
    subject = _("Recover your %(site)s account") % {'site': askbot_settings.APP_SHORT_NAME}
    data = {
        'validation_link': askbot_settings.APP_URL + \
                            reverse(
                                    'user_account_recover',
                                    kwargs={'key':user.email_key}
                            )
    }
    template = get_template('authopenid/email_validation.txt')
    message = template.render(data)
    send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
Exemple #30
0
def send_email_key(email, key, handler_url_name='user_account_recover'):
    """private function. sends email containing validation key
    to user's email address
    """
    subject = _("Recover your %(site)s account") % \
                {'site': askbot_settings.APP_SHORT_NAME}

    url = urlparse(askbot_settings.APP_URL)
    data = {
        'validation_link': url.scheme + '://' + url.netloc + \
                            reverse(handler_url_name) +\
                            '?validation_code=' + key
    }
    template = get_template('authopenid/email_validation.txt')
    message = template.render(data)
    send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [email])
Exemple #31
0
def send_email_key(email, key, handler_url_name='user_account_recover'):
    """private function. sends email containing validation key
    to user's email address
    """
    subject = _("Recover your %(site)s account") % \
                {'site': askbot_settings.APP_SHORT_NAME}

    url = urlparse(askbot_settings.APP_URL)
    data = {
        'validation_link': url.scheme + '://' + url.netloc + \
                            reverse(handler_url_name) +\
                            '?validation_code=' + key
    }
    template = get_template('authopenid/email_validation.txt')
    message = template.render(data)
    send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [email])
Exemple #32
0
def _send_email_key(user):
    """private function. sends email containing validation key
    to user's email address
    """
    subject = _("Recover your %(site)s account") % {'site': askbot_settings.APP_SHORT_NAME}

    url = urlparse(askbot_settings.APP_URL)
    data = {
        'validation_link': url.scheme + '://' + url.netloc + \
                            reverse(
                                    'user_account_recover',
                                    kwargs={'key':user.email_key}
                            )
    }
    template = get_template('authopenid/email_validation.txt')
    message = template.render(data)
    send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
Exemple #33
0
 def update_summary_html(self):
     context = {
         'thread': self,
         'question': self._question_post(refresh=True),  # fetch new question post to make sure we're up-to-date
         'search_state': DummySearchState(),
     }
     html = get_template('widgets/question_summary.html').render(context)
     # INFO: Timeout is set to 30 days:
     # * timeout=0/None is not a reliable cross-backend way to set infinite timeout
     # * We probably don't need to pollute the cache with threads older than 30 days
     # * Additionally, Memcached treats timeouts > 30day as dates (https://code.djangoproject.com/browser/django/tags/releases/1.3/django/core/cache/backends/memcached.py#L36),
     #   which probably doesn't break anything but if we can stick to 30 days then let's stick to it
     cache.cache.set(
         self.SUMMARY_CACHE_KEY_TPL % self.id,
         html,
         timeout=const.LONG_TIME
     )
     return html
Exemple #34
0
 def process_exception(self, request, exception):
     #todo: move this to separate middleware
     exc_type, exc_value, exc_traceback = sys.exc_info()
     logging.critical(''.join(traceback.format_tb(exc_traceback)))
     logging.critical(exc_type)
     logging.critical(exc_value)
     if exc_type == Http404:
         return None
     if getattr(settings, 'DEBUG', False) == True:
         return None
     else:
         #todo - we have a strange requirement - maybe remove
         #500.html needs RequestContext, while handler500 only receives Context
         #need to log some more details about the request
         logging.critical(utils.http.get_request_info(request))
         from askbot.skins.loaders import get_template
         template = get_template('500.jinja.html', request)
         return HttpResponse(template.render(RequestContext(request)))
 def process_exception(self, request, exception):
     #todo: move this to separate middleware
     exc_type, exc_value, exc_traceback = sys.exc_info()
     logging.critical(''.join(traceback.format_tb(exc_traceback)))
     logging.critical(exc_type)
     logging.critical(exc_value)
     if exc_type == Http404:
         return None
     if getattr(settings, 'DEBUG', False) == True:
         return None
     else:
         #todo - we have a strange requirement - maybe remove 
         #500.html needs RequestContext, while handler500 only receives Context
         #need to log some more details about the request
         logging.critical(utils.http.get_request_info(request))
         from askbot.skins.loaders import get_template
         template = get_template('500.jinja.html', request)
         return HttpResponse(template.render(RequestContext(request)))
Exemple #36
0
def feedback(request):
    data = {'page_class': 'meta'}
    form = None
    if request.method == "POST":
        form = FeedbackForm(request.POST)
        if form.is_valid():
            if not request.user.is_authenticated:
                data['email'] = form.cleaned_data.get('email',None)
            data['message'] = form.cleaned_data['message']
            data['name'] = form.cleaned_data.get('name',None)
            template = get_template('feedback_email.txt', request)
            message = template.render(RequestContext(request, data))
            mail_moderators(_('Q&A forum feedback'), message)
            msg = _('Thanks for the feedback!')
            request.user.message_set.create(message=msg)
            return HttpResponseRedirect(get_next_url(request))
    else:
        form = FeedbackForm(initial={'next':get_next_url(request)})

    data['form'] = form
    return render_into_skin('feedback.html', data, request)
def PROCESS(message, address = None, host = None):
    try:
        for rule in settings.LAMSON_FORWARD:
            if re.match(rule['pattern'], message.base['to']):
                relay = Relay(host=rule['host'], 
                           port=rule['port'], debug=1)
                relay.deliver(message)
                return
    except AttributeError:
        pass

    error = None
    try:
        reply_address = ReplyAddress.objects.get_unused(address, message.From)
        separator = _("======= Reply above this line. ====-=-=")
        parts = message.body().split(separator)
        if len(parts) != 2 :
            error = _("Your message was malformed. Please make sure to qoute \
                the original notification you received at the end of your reply.")
        else:
            reply_part = parts[0]
            reply_part = '\n'.join(reply_part.splitlines(True)[:-3])
            reply_address.create_reply(reply_part.strip())
    except ReplyAddress.DoesNotExist:
        error = _("You were replying to an email address\
         unknown to the system or you were replying from a different address from the one where you\
         received the notification.")
    if error is not None:
        from askbot.utils import mail
        from django.template import Context
        from askbot.skins.loaders import get_template

        template = get_template('reply_by_email_error.html')
        body_text = template.render(Context({'error':error}))
        mail.send_mail(
            subject_line = "Error posting your reply",
            body_text = body_text,
            recipient_list = [message.From],
        )        
Exemple #38
0
def feedback(request):
    data = {"page_class": "meta"}
    form = None

    if askbot_settings.ALLOW_ANONYMOUS_FEEDBACK is False:
        if request.user.is_anonymous():
            message = _("Please sign in or register to send your feedback")
            request.user.message_set.create(message=message)
            redirect_url = get_login_url() + "?next=" + request.path
            return HttpResponseRedirect(redirect_url)

    if request.method == "POST":
        form = FeedbackForm(is_auth=request.user.is_authenticated(), data=request.POST)
        if form.is_valid():

            if not request.user.is_authenticated():
                data["email"] = form.cleaned_data.get("email", None)
            else:
                data["email"] = request.user.email

            data["message"] = form.cleaned_data["message"]
            data["name"] = form.cleaned_data.get("name", None)
            template = get_template("email/feedback_email.txt", request)
            message = template.render(RequestContext(request, data))

            headers = {}
            if data["email"]:
                headers = {"Reply-To": data["email"]}

            mail_moderators(_("Q&A forum feedback"), message, headers=headers)
            msg = _("Thanks for the feedback!")
            request.user.message_set.create(message=msg)
            return HttpResponseRedirect(get_next_url(request))
    else:
        form = FeedbackForm(is_auth=request.user.is_authenticated(), initial={"next": get_next_url(request)})

    data["form"] = form
    return render_into_skin("feedback.html", data, request)
Exemple #39
0
 def render(self, context):
     request = self.request_var.resolve(context)
     jinja_template = get_template(self.filename, request)
     return jinja_template.render(context)
Exemple #40
0
def send_instant_notifications_about_activity_in_post(
                                                update_activity = None,
                                                post = None,
                                                recipients = None,
                                            ):
    #reload object from the database
    post = Post.objects.get(id=post.id)
    if post.is_approved() is False:
        return

    if recipients is None:
        return

    acceptable_types = const.RESPONSE_ACTIVITY_TYPES_FOR_INSTANT_NOTIFICATIONS

    if update_activity.activity_type not in acceptable_types:
        return

    #calculate some variables used in the loop below
    from askbot.skins.loaders import get_template
    update_type_map = const.RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES
    update_type = update_type_map[update_activity.activity_type]
    origin_post = post.get_origin_post()
    headers = mail.thread_headers(
                            post,
                            origin_post,
                            update_activity.activity_type
                        )

    logger = logging.getLogger()
    if logger.getEffectiveLevel() <= logging.DEBUG:
        log_id = uuid.uuid1()
        message = 'email-alert %s, logId=%s' % (post.get_absolute_url(), log_id)
        logger.debug(message)
    else:
        log_id = None


    for user in recipients:
        if user.is_blocked():
            continue

        reply_address, alt_reply_address = get_reply_to_addresses(user, post)

        subject_line, body_text = format_instant_notification_email(
                            to_user = user,
                            from_user = update_activity.user,
                            post = post,
                            reply_address = reply_address,
                            alt_reply_address = alt_reply_address,
                            update_type = update_type,
                            template = get_template('email/instant_notification.html')
                        )

        headers['Reply-To'] = reply_address
        try:
            mail.send_mail(
                subject_line=subject_line,
                body_text=body_text,
                recipient_list=[user.email],
                related_object=origin_post,
                activity_type=const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
                headers=headers,
                raise_on_failure=True
            )
        except askbot_exceptions.EmailNotSent, error:
            logger.debug(
                '%s, error=%s, logId=%s' % (user.email, error, log_id)
            )
        else:
            logger.debug('success %s, logId=%s' % (user.email, log_id))
Exemple #41
0
def questions(request, **kwargs):
    """
    List of Questions, Tagged questions, and Unanswered questions.
    matching search query or user selection
    """
    #before = datetime.datetime.now()
    if request.method != 'GET':
        return HttpResponseNotAllowed(['GET'])

    search_state = SearchState(user_logged_in=request.user.is_authenticated(), **kwargs)
    page_size = int(askbot_settings.DEFAULT_QUESTIONS_PAGE_SIZE)

    qs, meta_data = models.Thread.objects.run_advanced_search(request_user=request.user, search_state=search_state)

    if meta_data['non_existing_tags']:
        search_state = search_state.remove_tags(meta_data['non_existing_tags'])

    paginator = Paginator(qs, page_size)
    if paginator.num_pages < search_state.page:
        search_state.page = 1
    page = paginator.page(search_state.page)

    page.object_list = list(page.object_list) # evaluate queryset

    # INFO: Because for the time being we need question posts and thread authors
    #       down the pipeline, we have to precache them in thread objects
    models.Thread.objects.precache_view_data_hack(threads=page.object_list)

    related_tags = Tag.objects.get_related_to_search(threads=page.object_list, ignored_tag_names=meta_data.get('ignored_tag_names', []))
    tag_list_type = askbot_settings.TAG_LIST_FORMAT
    if tag_list_type == 'cloud': #force cloud to sort by name
        related_tags = sorted(related_tags, key = operator.attrgetter('name'))

    contributors = list(models.Thread.objects.get_thread_contributors(thread_list=page.object_list).only('id', 'username', 'gravatar'))

    paginator_context = {
        'is_paginated' : (paginator.count > page_size),

        'pages': paginator.num_pages,
        'page': search_state.page,
        'has_previous': page.has_previous(),
        'has_next': page.has_next(),
        'previous': page.previous_page_number(),
        'next': page.next_page_number(),

        'base_url' : search_state.query_string(),
        'page_size' : page_size,
    }

    # We need to pass the rss feed url based
    # on the search state to the template.
    # We use QueryDict to get a querystring
    # from dicts and arrays. Much cleaner
    # than parsing and string formating.
    rss_query_dict = QueryDict("").copy()
    if search_state.query:
        # We have search string in session - pass it to
        # the QueryDict
        rss_query_dict.update({"q": search_state.query})
    if search_state.tags:
        # We have tags in session - pass it to the
        # QueryDict but as a list - we want tags+
        rss_query_dict.setlist("tags", search_state.tags)
    context_feed_url = '/feeds/rss/?%s' % rss_query_dict.urlencode() # Format the url with the QueryDict

    reset_method_count = len(filter(None, [search_state.query, search_state.tags, meta_data.get('author_name', None)]))

    if request.is_ajax():
        q_count = paginator.count

        question_counter = ungettext('%(q_num)s question', '%(q_num)s questions', q_count)
        question_counter = question_counter % {'q_num': humanize.intcomma(q_count),}

        if q_count > page_size:
            paginator_tpl = get_template('main_page/paginator.html', request)
            paginator_html = paginator_tpl.render(Context({
                'context': functions.setup_paginator(paginator_context),
                'questions_count': q_count,
                'page_size' : page_size,
                'search_state': search_state,
            }))
        else:
            paginator_html = ''

        questions_tpl = get_template('main_page/questions_loop.html', request)
        questions_html = questions_tpl.render(Context({
            'threads': page,
            'search_state': search_state,
            'reset_method_count': reset_method_count,
        }))

        ajax_data = {
            'query_data': {
                'tags': search_state.tags,
                'sort_order': search_state.sort,
                'ask_query_string': search_state.ask_query_string(),
            },
            'paginator': paginator_html,
            'question_counter': question_counter,
            'faces': [extra_tags.gravatar(contributor, 48) for contributor in contributors],
            'feed_url': context_feed_url,
            'query_string': search_state.query_string(),
            'page_size' : page_size,
            'questions': questions_html.replace('\n',''),
            'non_existing_tags': meta_data['non_existing_tags']
        }
        ajax_data['related_tags'] = [{
            'name': tag.name,
            'used_count': humanize.intcomma(tag.local_used_count)
        } for tag in related_tags]

        return HttpResponse(simplejson.dumps(ajax_data), mimetype = 'application/json')

    else: # non-AJAX branch

        template_data = {
            'active_tab': 'questions',
            'author_name' : meta_data.get('author_name',None),
            'contributors' : contributors,
            'context' : paginator_context,
            'is_unanswered' : False,#remove this from template
            'interesting_tag_names': meta_data.get('interesting_tag_names', None),
            'ignored_tag_names': meta_data.get('ignored_tag_names', None),
            'subscribed_tag_names': meta_data.get('subscribed_tag_names', None),
            'language_code': translation.get_language(),
            'name_of_anonymous_user' : models.get_name_of_anonymous_user(),
            'page_class': 'main-page',
            'page_size': page_size,
            'query': search_state.query,
            'threads' : page,
            'questions_count' : paginator.count,
            'reset_method_count': reset_method_count,
            'scope': search_state.scope,
            'show_sort_by_relevance': askbot.conf.should_show_sort_by_relevance(),
            'search_tags' : search_state.tags,
            'sort': search_state.sort,
            'tab_id' : search_state.sort,
            'tags' : related_tags,
            'tag_list_type' : tag_list_type,
            'font_size' : extra_tags.get_tag_font_size(related_tags),
            'display_tag_filter_strategy_choices': const.TAG_DISPLAY_FILTER_STRATEGY_CHOICES,
            'email_tag_filter_strategy_choices': const.TAG_EMAIL_FILTER_STRATEGY_CHOICES,
            'update_avatar_data': schedules.should_update_avatar_data(request),
            'query_string': search_state.query_string(),
            'search_state': search_state,
            'feed_url': context_feed_url,
        }

        return render_into_skin('main_page.html', template_data, request)
Exemple #42
0
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_UNANSWERED_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date
        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_UNANSWERED_REMINDER,
            askbot_settings.UNANSWERED_REMINDER_FREQUENCY,
            max_reminders=askbot_settings.MAX_UNANSWERED_REMINDERS)

        questions = models.Post.objects.get_questions().exclude(
            thread__closed=True).exclude(deleted=True).added_between(
                start=schedule.start_cutoff_date,
                end=schedule.end_cutoff_date).filter(
                    thread__answer_count=0).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status='b'):
            user_questions = questions.exclude(author=user)
            user_questions = user.get_tag_filtered_questions(user_questions)

            if askbot_settings.GROUPS_ENABLED:
                user_groups = user.get_groups()
                user_questions = user_questions.filter(groups__in=user_groups)

            final_question_list = user_questions.get_questions_needing_reminder(
                user=user,
                activity_type=const.TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT,
                recurrence_delay=schedule.recurrence_delay)

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            threads = Thread.objects.filter(
                id__in=[qq.thread_id for qq in final_question_list])
            tag_summary = Thread.objects.get_tag_summary_from_threads(threads)

            subject_line = ungettext(
                '%(question_count)d unanswered question about %(topics)s',
                '%(question_count)d unanswered questions about %(topics)s',
                question_count) % {
                    'question_count': question_count,
                    'topics': tag_summary
                }

            data = {
                'site_url': askbot_settings.APP_URL,
                'questions': final_question_list,
                'subject_line': subject_line
            }

            template = get_template('email/unanswered_question_reminder.html')
            body_text = template.render(Context(data))

            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(subject_line=subject_line,
                               body_text=body_text,
                               recipient_list=(user.email, ))
Exemple #43
0
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_ACCEPT_ANSWER_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date

        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER,
            askbot_settings.ACCEPT_ANSWER_REMINDER_FREQUENCY,
            askbot_settings.MAX_ACCEPT_ANSWER_REMINDERS)

        questions = models.Post.objects.get_questions().exclude(
            deleted=True).added_between(
                start=schedule.start_cutoff_date, end=schedule.end_cutoff_date
            ).filter(thread__answer_count__gt=0).filter(
                thread__accepted_answer__isnull=True  #answer_accepted = False
            ).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status='b'):
            user_questions = questions.filter(author=user)

            final_question_list = user_questions.get_questions_needing_reminder(
                activity_type=const.TYPE_ACTIVITY_ACCEPT_ANSWER_REMINDER_SENT,
                user=user,
                recurrence_delay=schedule.recurrence_delay)
            #todo: rewrite using query set filter
            #may be a lot more efficient

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            subject_line = _(
                'Accept the best answer for %(question_count)d of your questions'
            ) % {
                'question_count': question_count
            }

            #todo - make a template for these
            if question_count == 1:
                reminder_phrase = _(
                    'Please accept the best answer for this question:')
            else:
                reminder_phrase = _(
                    'Please accept the best answer for these questions:')

            data = {
                'site_url': askbot_settings.APP_URL,
                'questions': final_question_list,
                'reminder_phrase': reminder_phrase
            }

            template = get_template('email/accept_answer_reminder.html')
            body_text = template.render(Context(data))

            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(subject_line=subject_line,
                               body_text=body_text,
                               recipient_list=(user.email, ))
Exemple #44
0
def questions(request, **kwargs):
    """
    List of Questions, Tagged questions, and Unanswered questions.
    matching search query or user selection
    """
    # before = datetime.datetime.now()
    if request.method != "GET":
        return HttpResponseNotAllowed(["GET"])

    search_state = SearchState(user_logged_in=request.user.is_authenticated(), **kwargs)
    page_size = int(askbot_settings.DEFAULT_QUESTIONS_PAGE_SIZE)

    qs, meta_data = models.Thread.objects.run_advanced_search(request_user=request.user, search_state=search_state)
    if meta_data["non_existing_tags"]:
        search_state = search_state.remove_tags(meta_data["non_existing_tags"])

    paginator = Paginator(qs, page_size)
    if paginator.num_pages < search_state.page:
        search_state.page = 1
    page = paginator.page(search_state.page)
    page.object_list = list(page.object_list)  # evaluate the queryset

    # INFO: Because for the time being we need question posts and thread authors
    #       down the pipeline, we have to precache them in thread objects
    models.Thread.objects.precache_view_data_hack(threads=page.object_list)

    related_tags = Tag.objects.get_related_to_search(
        threads=page.object_list, ignored_tag_names=meta_data.get("ignored_tag_names", [])
    )
    tag_list_type = askbot_settings.TAG_LIST_FORMAT
    if tag_list_type == "cloud":  # force cloud to sort by name
        related_tags = sorted(related_tags, key=operator.attrgetter("name"))

    contributors = list(
        models.Thread.objects.get_thread_contributors(thread_list=page.object_list).only("id", "username", "gravatar")
    )

    paginator_context = {
        "is_paginated": (paginator.count > page_size),
        "pages": paginator.num_pages,
        "page": search_state.page,
        "has_previous": page.has_previous(),
        "has_next": page.has_next(),
        "previous": page.previous_page_number(),
        "next": page.next_page_number(),
        "base_url": search_state.query_string(),
        "page_size": page_size,
    }

    # We need to pass the rss feed url based
    # on the search state to the template.
    # We use QueryDict to get a querystring
    # from dicts and arrays. Much cleaner
    # than parsing and string formating.
    rss_query_dict = QueryDict("").copy()
    if search_state.query:
        # We have search string in session - pass it to
        # the QueryDict
        rss_query_dict.update({"q": search_state.query})
    if search_state.tags:
        # We have tags in session - pass it to the
        # QueryDict but as a list - we want tags+
        rss_query_dict.setlist("tags", search_state.tags)
    context_feed_url = "/%sfeeds/rss/?%s" % (
        settings.ASKBOT_URL,
        rss_query_dict.urlencode(),
    )  # Format the url with the QueryDict

    reset_method_count = len(filter(None, [search_state.query, search_state.tags, meta_data.get("author_name", None)]))

    if request.is_ajax():
        q_count = paginator.count

        question_counter = ungettext("%(q_num)s question", "%(q_num)s questions", q_count)
        question_counter = question_counter % {"q_num": humanize.intcomma(q_count)}

        if q_count > page_size:
            paginator_tpl = get_template("main_page/paginator.html", request)
            paginator_html = paginator_tpl.render(
                Context(
                    {
                        "context": functions.setup_paginator(paginator_context),
                        "questions_count": q_count,
                        "page_size": page_size,
                        "search_state": search_state,
                    }
                )
            )
        else:
            paginator_html = ""

        questions_tpl = get_template("main_page/questions_loop.html", request)
        questions_html = questions_tpl.render(
            Context(
                {
                    "threads": page,
                    "search_state": search_state,
                    "reset_method_count": reset_method_count,
                    "request": request,
                }
            )
        )

        ajax_data = {
            "query_data": {
                "tags": search_state.tags,
                "sort_order": search_state.sort,
                "ask_query_string": search_state.ask_query_string(),
            },
            "paginator": paginator_html,
            "question_counter": question_counter,
            "faces": [],  # [extra_tags.gravatar(contributor, 48) for contributor in contributors],
            "feed_url": context_feed_url,
            "query_string": search_state.query_string(),
            "page_size": page_size,
            "questions": questions_html.replace("\n", ""),
            "non_existing_tags": meta_data["non_existing_tags"],
        }
        ajax_data["related_tags"] = [
            {"name": escape(tag.name), "used_count": humanize.intcomma(tag.local_used_count)} for tag in related_tags
        ]

        return HttpResponse(simplejson.dumps(ajax_data), mimetype="application/json")

    else:  # non-AJAX branch

        template_data = {
            "active_tab": "questions",
            "author_name": meta_data.get("author_name", None),
            "contributors": contributors,
            "context": paginator_context,
            "is_unanswered": False,  # remove this from template
            "interesting_tag_names": meta_data.get("interesting_tag_names", None),
            "ignored_tag_names": meta_data.get("ignored_tag_names", None),
            "subscribed_tag_names": meta_data.get("subscribed_tag_names", None),
            "language_code": translation.get_language(),
            "name_of_anonymous_user": models.get_name_of_anonymous_user(),
            "page_class": "main-page",
            "page_size": page_size,
            "query": search_state.query,
            "threads": page,
            "questions_count": paginator.count,
            "reset_method_count": reset_method_count,
            "scope": search_state.scope,
            "show_sort_by_relevance": conf.should_show_sort_by_relevance(),
            "search_tags": search_state.tags,
            "sort": search_state.sort,
            "tab_id": search_state.sort,
            "tags": related_tags,
            "tag_list_type": tag_list_type,
            "font_size": extra_tags.get_tag_font_size(related_tags),
            "display_tag_filter_strategy_choices": conf.get_tag_display_filter_strategy_choices(),
            "email_tag_filter_strategy_choices": const.TAG_EMAIL_FILTER_STRATEGY_CHOICES,
            "update_avatar_data": schedules.should_update_avatar_data(request),
            "query_string": search_state.query_string(),
            "search_state": search_state,
            "feed_url": context_feed_url,
        }

        return render_into_skin("main_page.html", template_data, request)
                                        address = address,
                                        allowed_from_email = message.From
                                    )
        parts = get_parts(message)
        if reply_address.was_used:
            reply_address.edit_post(parts)
        else:
            reply_address.create_reply(parts)
    except ReplyAddress.DoesNotExist:
        error = _("You were replying to an email address\
         unknown to the system or you were replying from a different address from the one where you\
         received the notification.")
    except Exception, e:
        import sys
        sys.stderr.write(str(e))
        import traceback
        sys.stderr.write(traceback.format_exc())

    if error is not None:
        from askbot.utils import mail
        from django.template import Context
        from askbot.skins.loaders import get_template

        template = get_template('reply_by_email_error.html')
        body_text = template.render(Context({'error':error}))
        mail.send_mail(
            subject_line = "Error posting your reply",
            body_text = body_text,
            recipient_list = [message.From],
        )        
Exemple #46
0
def questions(request):
    """
    List of Questions, Tagged questions, and Unanswered questions.
    matching search query or user selection
    """
    #before = datetime.datetime.now()
    #don't allow to post to this view
    if request.method == 'POST':
        raise Http404

    #update search state
    form = AdvancedSearchForm(request.GET)
    if form.is_valid():
        user_input = form.cleaned_data
    else:
        user_input = None
    search_state = request.session.get('search_state', SearchState())
    view_log = request.session['view_log']
    search_state.update(user_input, view_log, request.user)
    request.session['search_state'] = search_state
    request.session.modified = True

    #force reset for debugging
    #search_state.reset()
    #request.session.modified = True

    #todo: have this call implemented for sphinx, mysql and pgsql
    (qs, meta_data, related_tags) = models.Question.objects.run_advanced_search(
                                            request_user = request.user,
                                            search_state = search_state,
                                        )

    tag_list_type = askbot_settings.TAG_LIST_FORMAT

    #force cloud to sort by name
    if tag_list_type == 'cloud':
        related_tags = sorted(related_tags, key = operator.attrgetter('name'))

    font_size = extra_tags.get_tag_font_size(related_tags)

    paginator = Paginator(qs, search_state.page_size)

    if paginator.num_pages < search_state.page:
        raise Http404

    page = paginator.page(search_state.page)

    contributors = models.Question.objects.get_question_and_answer_contributors(page.object_list)

    paginator_context = {
        'is_paginated' : (paginator.count > search_state.page_size),
        'pages': paginator.num_pages,
        'page': search_state.page,
        'has_previous': page.has_previous(),
        'has_next': page.has_next(),
        'previous': page.previous_page_number(),
        'next': page.next_page_number(),
        'base_url' : request.path + '?sort=%s&amp;' % search_state.sort,#todo in T sort=>sort_method
        'page_size' : search_state.page_size,#todo in T pagesize -> page_size
    }

    if request.is_ajax():

        q_count = paginator.count
        if search_state.tags:
            question_counter = ungettext(
                                    '%(q_num)s question, tagged',
                                    '%(q_num)s questions, tagged',
                                    q_count
                                ) % {
                                    'q_num': humanize.intcomma(q_count),
                                }
        else:
            question_counter = ungettext(
                                    '%(q_num)s question',
                                    '%(q_num)s questions',
                                    q_count
                                ) % {
                                    'q_num': humanize.intcomma(q_count),
                                }

        if q_count > search_state.page_size:
            paginator_tpl = get_template('main_page/paginator.html', request)
            #todo: remove this patch on context after all templates are moved to jinja
            paginator_context['base_url'] = request.path + '?sort=%s&' % search_state.sort
            data = {
                'context': extra_tags.cnprog_paginator(paginator_context),
                'questions_count': q_count
            }
            paginator_html = paginator_tpl.render(Context(data))
        else:
            paginator_html = ''
        search_tags = list()
        if search_state.tags:
            search_tags = list(search_state.tags)
        query_data = {
            'tags': search_tags,
            'sort_order': search_state.sort
        }
        ajax_data = {
            #current page is 1 by default now
            #because ajax is only called by update in the search button
            'query_data': query_data,
            'paginator': paginator_html,
            'question_counter': question_counter,
            'questions': list(),
            'related_tags': list(),
            'faces': list()
        }

        badge_levels = dict(const.BADGE_TYPE_CHOICES)
        def pluralize_badge_count(count, level):
            return ungettext(
                '%(badge_count)d %(badge_level)s badge',
                '%(badge_count)d %(badge_level)s badges',
                count
            ) % {
                'badge_count': count,
                'badge_level': badge_levels[level]
            }

        gold_badge_css_class = const.BADGE_CSS_CLASSES[const.GOLD_BADGE],
        silver_badge_css_class = const.BADGE_CSS_CLASSES[const.SILVER_BADGE],
        bronze_badge_css_class = const.BADGE_CSS_CLASSES[const.BRONZE_BADGE],

        for tag in related_tags:
            tag_data = {
                'name': tag.name,
                'used_count': humanize.intcomma(tag.local_used_count)
            }
            ajax_data['related_tags'].append(tag_data)

        for contributor in contributors:
            ajax_data['faces'].append(extra_tags.gravatar(contributor, 48))
        #we render the template
        #from django.template import RequestContext
        questions_tpl = get_template('main_page/questions_loop.html', request)
        #todo: remove this patch on context after all templates are moved to jinja
        data = {
            'questions': page,
            'questions_count': q_count,
            'context': paginator_context,
            'language_code': translation.get_language(),
            'query': search_state.query,
        }

        questions_html = questions_tpl.render(Context(data))
        ajax_data['questions'] = questions_html.replace('\n','')
        return HttpResponse(
                    simplejson.dumps(ajax_data),
                    mimetype = 'application/json'
                )

    reset_method_count = 0
    if search_state.query:
        reset_method_count += 1
    if search_state.tags:
        reset_method_count += 1
    if meta_data.get('author_name',None):
        reset_method_count += 1

    template_data = {
        'active_tab': 'questions',
        'author_name' : meta_data.get('author_name',None),
        'contributors' : contributors,
        'context' : paginator_context,
        'is_unanswered' : False,#remove this from template
        'interesting_tag_names': meta_data.get('interesting_tag_names',None),
        'ignored_tag_names': meta_data.get('ignored_tag_names',None),
        'language_code': translation.get_language(),
        'name_of_anonymous_user' : models.get_name_of_anonymous_user(),
        'page_class': 'main-page',
        'query': search_state.query,
        'questions' : page,
        'questions_count' : paginator.count,
        'reset_method_count': reset_method_count,
        'scope': search_state.scope,
        'show_sort_by_relevance': askbot.conf.should_show_sort_by_relevance(),
        'search_tags' : search_state.tags,
        'sort': search_state.sort,
        'tab_id' : search_state.sort,
        'tags' : related_tags,
        'tag_list_type' : tag_list_type,
        'font_size' : font_size,
        'tag_filter_strategy_choices': const.TAG_FILTER_STRATEGY_CHOICES,
        'update_avatar_data': schedules.should_update_avatar_data(request),
    }

    assert(request.is_ajax() == False)
    #ajax request is handled in a separate branch above

    #before = datetime.datetime.now()
    response = render_into_skin('main_page.html', template_data, request)
    #after = datetime.datetime.now()
    #print after - before
    return response
Exemple #47
0
def questions(request, **kwargs):
    """
    List of Questions, Tagged questions, and Unanswered questions.
    matching search query or user selection
    """
    if request.method != 'GET':
        return HttpResponseNotAllowed(['GET'])

    search_state = SearchState(user_logged_in=request.user.is_authenticated(),
                               **kwargs)
    page_size = int(askbot_settings.DEFAULT_QUESTIONS_PAGE_SIZE)

    qs, meta_data = models.Thread.objects.run_advanced_search(
        request_user=request.user, search_state=search_state)

    if meta_data['non_existing_tags']:
        search_state = search_state.remove_tags(meta_data['non_existing_tags'])

    paginator = Paginator(qs, page_size)
    if paginator.num_pages < search_state.page:
        search_state.page = 1
    page = paginator.page(search_state.page)

    page.object_list = list(page.object_list)  # evaluate queryset

    # INFO: Because for the time being we need question posts and thread authors
    #       down the pipeline, we have to precache them in thread objects
    models.Thread.objects.precache_view_data_hack(threads=page.object_list)

    related_tags = Tag.objects.get_related_to_search(
        threads=page.object_list,
        ignored_tag_names=meta_data.get('ignored_tag_names', []))
    tag_list_type = askbot_settings.TAG_LIST_FORMAT
    if tag_list_type == 'cloud':  #force cloud to sort by name
        related_tags = sorted(related_tags, key=operator.attrgetter('name'))

    contributors = list(
        models.Thread.objects.get_thread_contributors(
            thread_list=page.object_list).only('id', 'username', 'gravatar'))

    paginator_context = {
        'is_paginated': (paginator.count > page_size),
        'pages': paginator.num_pages,
        'page': search_state.page,
        'has_previous': page.has_previous(),
        'has_next': page.has_next(),
        'previous': page.previous_page_number(),
        'next': page.next_page_number(),
        'base_url': search_state.query_string(),
        'page_size': page_size,
    }

    # We need to pass the rss feed url based
    # on the search state to the template.
    # We use QueryDict to get a querystring
    # from dicts and arrays. Much cleaner
    # than parsing and string formating.
    rss_query_dict = QueryDict("").copy()
    if search_state.query:
        # We have search string in session - pass it to
        # the QueryDict
        rss_query_dict.update({"q": search_state.query})
    if search_state.tags:
        # We have tags in session - pass it to the
        # QueryDict but as a list - we want tags+
        rss_query_dict.setlist("tags", search_state.tags)
    context_feed_url = '/feeds/rss/?%s' % rss_query_dict.urlencode(
    )  # Format the url with the QueryDict

    reset_method_count = len(
        filter(None, [
            search_state.query, search_state.tags,
            meta_data.get('author_name', None)
        ]))

    if request.is_ajax():
        q_count = paginator.count

        question_counter = ungettext('%(q_num)s question',
                                     '%(q_num)s questions', q_count)
        question_counter = question_counter % {
            'q_num': humanize.intcomma(q_count),
        }

        if q_count > page_size:
            paginator_tpl = get_template('main_page/paginator.html', request)
            paginator_html = paginator_tpl.render(
                Context({
                    'context': functions.setup_paginator(paginator_context),
                    'questions_count': q_count,
                    'page_size': page_size,
                    'search_state': search_state,
                }))
        else:
            paginator_html = ''

        questions_tpl = get_template('main_page/questions_loop.html', request)
        questions_html = questions_tpl.render(
            Context({
                'threads': page,
                'search_state': search_state,
                'reset_method_count': reset_method_count,
            }))

        ajax_data = {
            'query_data': {
                'tags': search_state.tags,
                'sort_order': search_state.sort,
                'ask_query_string': search_state.ask_query_string(),
            },
            'paginator':
            paginator_html,
            'question_counter':
            question_counter,
            'faces': [
                extra_tags.gravatar(contributor, 48)
                for contributor in contributors
            ],
            'feed_url':
            context_feed_url,
            'query_string':
            search_state.query_string(),
            'page_size':
            page_size,
            'questions':
            questions_html.replace('\n', ''),
            'non_existing_tags':
            meta_data['non_existing_tags']
        }
        ajax_data['related_tags'] = [{
            'name':
            tag.name,
            'used_count':
            humanize.intcomma(tag.local_used_count)
        } for tag in related_tags]

        return HttpResponse(simplejson.dumps(ajax_data),
                            mimetype='application/json')

    else:  # non-AJAX branch

        template_data = {
            'active_tab': 'questions',
            'author_name': meta_data.get('author_name', None),
            'contributors': contributors,
            'context': paginator_context,
            'is_unanswered': False,  #remove this from template
            'interesting_tag_names': meta_data.get('interesting_tag_names',
                                                   None),
            'ignored_tag_names': meta_data.get('ignored_tag_names', None),
            'subscribed_tag_names': meta_data.get('subscribed_tag_names',
                                                  None),
            'language_code': translation.get_language(),
            'name_of_anonymous_user': models.get_name_of_anonymous_user(),
            'page_class': 'main-page',
            'page_size': page_size,
            'query': search_state.query,
            'threads': page,
            'questions_count': paginator.count,
            'reset_method_count': reset_method_count,
            'scope': search_state.scope,
            'show_sort_by_relevance':
            askbot.conf.should_show_sort_by_relevance(),
            'search_tags': search_state.tags,
            'sort': search_state.sort,
            'tab_id': search_state.sort,
            'tags': related_tags,
            'tag_list_type': tag_list_type,
            'font_size': extra_tags.get_tag_font_size(related_tags),
            'display_tag_filter_strategy_choices':
            const.TAG_DISPLAY_FILTER_STRATEGY_CHOICES,
            'email_tag_filter_strategy_choices':
            const.TAG_EMAIL_FILTER_STRATEGY_CHOICES,
            'update_avatar_data': schedules.should_update_avatar_data(request),
            'query_string': search_state.query_string(),
            'search_state': search_state,
            'feed_url': context_feed_url,
        }

        return render_into_skin('main_page.html', template_data, request)
Exemple #48
0
 def setUp(self):
     self.template_name = 'email/welcome_lamson_on.html'
     self.context = {'site_name': 'askbot.com', 'email_code': 'DwFwndQty'}
     template = get_template(self.template_name)
     self.rendered_template = template.render(Context(self.context))
     self.expected_output = 'Welcome to askbot.com!\n\nImportant: Please reply to this message, without editing it. We need this to determine your email signature and that the email address is valid and was typed correctly.\n\nUntil we receive the response from you, you will not be able ask or problem exercises on askbot.com by email.\n\nSincerely,askbot.com Administrator\n\nDwFwndQty'
Exemple #49
0
 def render(self, context):
     request = self.request_var.resolve(context)
     jinja_template = get_template(self.filename, request)
     return jinja_template.render(context)
Exemple #50
0
def questions(request):
    """
    List of Questions, Tagged questions, and Unanswered questions.
    matching search query or user selection
    """
    #before = datetime.datetime.now()
    #don't allow to post to this view
    if request.method == 'POST':
        raise Http404

    #update search state
    form = AdvancedSearchForm(request.GET)
    if form.is_valid():
        user_input = form.cleaned_data
    else:
        user_input = None
    search_state = request.session.get('search_state', SearchState())
    view_log = request.session['view_log']
    search_state.update(user_input, view_log, request.user)
    request.session['search_state'] = search_state
    request.session.modified = True

    #force reset for debugging
    #search_state.reset()
    #request.session.modified = True

    #todo: have this call implemented for sphinx, mysql and pgsql
    (qs, meta_data,
     related_tags) = models.Question.objects.run_advanced_search(
         request_user=request.user,
         search_state=search_state,
     )

    paginator = Paginator(qs, search_state.page_size)

    if paginator.num_pages < search_state.page:
        raise Http404

    page = paginator.page(search_state.page)

    contributors = models.Question.objects.get_question_and_answer_contributors(
        page.object_list)

    paginator_context = {
        'is_paginated': (paginator.count > search_state.page_size),
        'pages': paginator.num_pages,
        'page': search_state.page,
        'has_previous': page.has_previous(),
        'has_next': page.has_next(),
        'previous': page.previous_page_number(),
        'next': page.next_page_number(),
        'base_url': request.path +
        '?sort=%s&amp;' % search_state.sort,  #todo in T sort=>sort_method
        'page_size': search_state.page_size,  #todo in T pagesize -> page_size
    }

    if request.is_ajax():

        q_count = paginator.count
        if search_state.tags:
            question_counter = ungettext(
                '%(q_num)s question, tagged', '%(q_num)s questions, tagged',
                q_count) % {
                    'q_num': humanize.intcomma(q_count),
                }
        else:
            question_counter = ungettext(
                '%(q_num)s question', '%(q_num)s questions', q_count) % {
                    'q_num': humanize.intcomma(q_count),
                }

        if q_count > search_state.page_size:
            paginator_tpl = get_template('blocks/paginator.html', request)
            #todo: remove this patch on context after all templates are moved to jinja
            paginator_context[
                'base_url'] = request.path + '?sort=%s&' % search_state.sort
            data = {
                'paginator_context':
                extra_tags.cnprog_paginator(paginator_context)
            }
            paginator_html = paginator_tpl.render(Context(data))
        else:
            paginator_html = ''
        search_tags = list()
        if search_state.tags:
            search_tags = list(search_state.tags)
        query_data = {'tags': search_tags, 'sort_order': search_state.sort}
        ajax_data = {
            #current page is 1 by default now
            #because ajax is only called by update in the search button
            'query_data': query_data,
            'paginator': paginator_html,
            'question_counter': question_counter,
            'questions': list(),
            'related_tags': list(),
            'faces': list()
        }

        badge_levels = dict(const.BADGE_TYPE_CHOICES)

        def pluralize_badge_count(count, level):
            return ungettext('%(badge_count)d %(badge_level)s badge',
                             '%(badge_count)d %(badge_level)s badges',
                             count) % {
                                 'badge_count': count,
                                 'badge_level': badge_levels[level]
                             }

        gold_badge_css_class = const.BADGE_CSS_CLASSES[const.GOLD_BADGE],
        silver_badge_css_class = const.BADGE_CSS_CLASSES[const.SILVER_BADGE],
        bronze_badge_css_class = const.BADGE_CSS_CLASSES[const.BRONZE_BADGE],

        for tag in related_tags:
            tag_data = {
                'name': tag.name,
                'used_count': humanize.intcomma(tag.local_used_count)
            }
            ajax_data['related_tags'].append(tag_data)

        for contributor in contributors:
            ajax_data['faces'].append(extra_tags.gravatar(contributor, 48))

        for question in page.object_list:
            timestamp = question.last_activity_at
            author = question.last_activity_by

            if question.score == 0:
                votes_class = 'no-votes'
            else:
                votes_class = 'some-votes'

            if question.answer_count == 0:
                answers_class = 'no-answers'
            elif question.answer_accepted:
                answers_class = 'accepted'
            else:
                answers_class = 'some-answers'

            if question.view_count == 0:
                views_class = 'no-views'
            else:
                views_class = 'some-views'

            country_code = None
            if author.country and author.show_country:
                country_code = author.country.code

            question_data = {
                'title':
                question.title,
                'summary':
                question.summary,
                'id':
                question.id,
                'tags':
                question.get_tag_names(),
                'votes':
                extra_filters.humanize_counter(question.score),
                'votes_class':
                votes_class,
                'votes_word':
                ungettext('vote', 'votes', question.score),
                'answers':
                extra_filters.humanize_counter(question.answer_count),
                'answers_class':
                answers_class,
                'answers_word':
                ungettext('answer', 'answers', question.answer_count),
                'views':
                extra_filters.humanize_counter(question.view_count),
                'views_class':
                views_class,
                'views_word':
                ungettext('view', 'views', question.view_count),
                'timestamp':
                unicode(timestamp),
                'timesince':
                functions.diff_date(timestamp),
                'u_id':
                author.id,
                'u_name':
                author.username,
                'u_rep':
                author.reputation,
                'u_gold':
                author.gold,
                'u_gold_title':
                pluralize_badge_count(author.gold, const.GOLD_BADGE),
                'u_gold_badge_symbol':
                const.BADGE_DISPLAY_SYMBOL,
                'u_gold_css_class':
                gold_badge_css_class,
                'u_silver':
                author.silver,
                'u_silver_title':
                pluralize_badge_count(author.silver, const.SILVER_BADGE),
                'u_silver_badge_symbol':
                const.BADGE_DISPLAY_SYMBOL,
                'u_silver_css_class':
                silver_badge_css_class,
                'u_bronze':
                author.bronze,
                'u_bronze_title':
                pluralize_badge_count(author.bronze, const.BRONZE_BADGE),
                'u_bronze_badge_symbol':
                const.BADGE_DISPLAY_SYMBOL,
                'u_bronze_css_class':
                bronze_badge_css_class,
                'u_country_code':
                country_code,
                'u_is_anonymous':
                question.is_anonymous,
            }
            ajax_data['questions'].append(question_data)

        return HttpResponse(simplejson.dumps(ajax_data),
                            mimetype='application/json')

    reset_method_count = 0
    if search_state.query:
        reset_method_count += 1
    if search_state.tags:
        reset_method_count += 1
    if meta_data.get('author_name', None):
        reset_method_count += 1

    template_data = {
        'active_tab': 'questions',
        'author_name': meta_data.get('author_name', None),
        'contributors': contributors,
        'context': paginator_context,
        'is_unanswered': False,  #remove this from template
        'interesting_tag_names': meta_data.get('interesting_tag_names', None),
        'ignored_tag_names': meta_data.get('ignored_tag_names', None),
        'language_code': translation.get_language(),
        'name_of_anonymous_user': models.get_name_of_anonymous_user(),
        'page_class': 'main-page',
        'query': search_state.query,
        'questions': page,
        'questions_count': paginator.count,
        'reset_method_count': reset_method_count,
        'scope': search_state.scope,
        'show_sort_by_relevance': askbot.conf.should_show_sort_by_relevance(),
        'search_tags': search_state.tags,
        'sort': search_state.sort,
        'tab_id': search_state.sort,
        'tags': related_tags,
        'tag_filter_strategy_choices': const.TAG_FILTER_STRATEGY_CHOICES,
    }

    assert (request.is_ajax() == False)
    #ajax request is handled in a separate branch above

    #before = datetime.datetime.now()
    response = render_into_skin('main_page.html', template_data, request)
    #after = datetime.datetime.now()
    #print after - before
    return response
Exemple #51
0
 def wrapped(*args, **kwargs):
     template_object = get_template(template)
     data = func(*args, **kwargs)
     return template_object.render(Context(data))
 def _html_for_question(self, q):
     context = {"thread": q.thread, "question": q, "search_state": DummySearchState()}
     html = get_template("widgets/question_summary.html").render(context)
     return html