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 `&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( '<<<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()))
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"))
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()
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'
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'))
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()
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 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 `<` was `&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('<<<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: "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
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()), )
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
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')
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 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 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')
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)
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])
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 )
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
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])
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])
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])
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
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 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], )
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)
def render(self, context): request = self.request_var.resolve(context) jinja_template = get_template(self.filename, request) return jinja_template.render(context)
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))
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)
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, ))
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, ))
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], )
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&' % 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
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)
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'
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&' % 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
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