diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-06-07 01:53:53 -0400 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-06-07 01:53:53 -0400 |
commit | 9f679e83639c642d903eeacde695baef1be44ec1 (patch) | |
tree | dd6c5772f77ac43c5044989959c6df678d16408b /askbot/utils | |
parent | 428c91d505a4a09192f1bbc70f7f1c0c1429cc4b (diff) | |
parent | 84e1fc6f99879ede88f2d51df2b2730b5df6ff41 (diff) | |
download | askbot-9f679e83639c642d903eeacde695baef1be44ec1.tar.gz askbot-9f679e83639c642d903eeacde695baef1be44ec1.tar.bz2 askbot-9f679e83639c642d903eeacde695baef1be44ec1.zip |
made moderation dialog work again after the merge
Diffstat (limited to 'askbot/utils')
-rw-r--r-- | askbot/utils/email.py | 28 | ||||
-rw-r--r-- | askbot/utils/html.py | 15 | ||||
-rw-r--r-- | askbot/utils/mail.py | 347 |
3 files changed, 14 insertions, 376 deletions
diff --git a/askbot/utils/email.py b/askbot/utils/email.py deleted file mode 100644 index 34b11c45..00000000 --- a/askbot/utils/email.py +++ /dev/null @@ -1,28 +0,0 @@ -from django.core.mail import EmailMultiAlternatives -from django.conf import settings as django_settings -from django.template import loader, Context -from django.utils.html import strip_tags -from threading import Thread - -def send_email( - subject, - recipients, - template, - context = {}, - sender = django_settings.DEFAULT_FROM_EMAIL, - txt_template = None - ): - context['settings'] = django_settings - html_body = loader.get_template(template).render(Context(context)) - - if txt_template is None: - txt_body = strip_tags(html_body) - else: - txt_body = loader.get_template(txt_template).render(Context(context)) - - msg = EmailMultiAlternatives(subject, txt_body, sender, recipients) - msg.attach_alternative(html_body, "text/html") - - thread = Thread(target=EmailMultiAlternatives.send, args=[msg]) - thread.setDaemon(True) - thread.start() diff --git a/askbot/utils/html.py b/askbot/utils/html.py index f91fa980..1ce3ad35 100644 --- a/askbot/utils/html.py +++ b/askbot/utils/html.py @@ -1,7 +1,10 @@ """Utilities for working with HTML.""" import html5lib from html5lib import sanitizer, serializer, tokenizer, treebuilders, treewalkers -import re, htmlentitydefs +import re +import htmlentitydefs +from urlparse import urlparse +from django.core.urlresolvers import reverse class HTMLSanitizerMixin(sanitizer.HTMLSanitizerMixin): acceptable_elements = ('a', 'abbr', 'acronym', 'address', 'b', 'big', @@ -51,6 +54,16 @@ def sanitize_html(html): output_generator = s.serialize(stream) return u''.join(output_generator) +def site_link(url_name, title): + """returns html for the link to the given url + todo: may be improved to process url parameters, keyword + and other arguments + """ + from askbot.conf import settings + base_url = urlparse(settings.APP_URL) + url = base_url.scheme + '://' + base_url.netloc + reverse(url_name) + return '<a href="%s">%s</a>' % (url, title) + def unescape(text): """source: http://effbot.org/zone/re-sub.htm#unescape-html Removes HTML or XML character references and entities from a text string. diff --git a/askbot/utils/mail.py b/askbot/utils/mail.py deleted file mode 100644 index 4f653e6b..00000000 --- a/askbot/utils/mail.py +++ /dev/null @@ -1,347 +0,0 @@ -"""functions that send email in askbot -these automatically catch email-related exceptions -""" -import os -import smtplib -import logging -from django.core import mail -from django.conf import settings as django_settings -from django.core.exceptions import PermissionDenied -from django.forms import ValidationError -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import string_concat -from askbot import exceptions -from askbot import const -from askbot.conf import settings as askbot_settings -from askbot.utils import url_utils -from askbot.utils.file_utils import store_file -#todo: maybe send_mail functions belong to models -#or the future API -def prefix_the_subject_line(subject): - """prefixes the subject line with the - EMAIL_SUBJECT_LINE_PREFIX either from - from live settings, which take default from django - """ - prefix = askbot_settings.EMAIL_SUBJECT_PREFIX - if prefix != '': - subject = prefix.strip() + ' ' + subject.strip() - return subject - -def extract_first_email_address(text): - """extract first matching email address - from text string - returns ``None`` if there are no matches - """ - match = const.EMAIL_REGEX.search(text) - if match: - return match.group(0) - else: - return None - -def thread_headers(post, orig_post, update): - """modify headers for email messages, so - that emails appear as threaded conversations in gmail""" - suffix_id = django_settings.SERVER_EMAIL - if update == const.TYPE_ACTIVITY_ASK_QUESTION: - msg_id = "NQ-%s-%s" % (post.id, suffix_id) - headers = {'Message-ID': msg_id} - elif update == const.TYPE_ACTIVITY_ANSWER: - msg_id = "NA-%s-%s" % (post.id, suffix_id) - orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) - headers = {'Message-ID': msg_id, - 'In-Reply-To': orig_id} - elif update == const.TYPE_ACTIVITY_UPDATE_QUESTION: - msg_id = "UQ-%s-%s-%s" % (post.id, post.last_edited_at, suffix_id) - orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) - headers = {'Message-ID': msg_id, - 'In-Reply-To': orig_id} - elif update == const.TYPE_ACTIVITY_COMMENT_QUESTION: - msg_id = "CQ-%s-%s" % (post.id, suffix_id) - orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) - headers = {'Message-ID': msg_id, - 'In-Reply-To': orig_id} - elif update == const.TYPE_ACTIVITY_UPDATE_ANSWER: - msg_id = "UA-%s-%s-%s" % (post.id, post.last_edited_at, suffix_id) - orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) - headers = {'Message-ID': msg_id, - 'In-Reply-To': orig_id} - elif update == const.TYPE_ACTIVITY_COMMENT_ANSWER: - msg_id = "CA-%s-%s" % (post.id, suffix_id) - orig_id = "NQ-%s-%s" % (orig_post.id, suffix_id) - headers = {'Message-ID': msg_id, - 'In-Reply-To': orig_id} - else: - # Unknown type -> Can't set headers - return {} - - return headers - -def send_mail( - subject_line = None, - body_text = None, - from_email = django_settings.DEFAULT_FROM_EMAIL, - recipient_list = None, - activity_type = None, - related_object = None, - headers = None, - raise_on_failure = False, - ): - """ - todo: remove parameters not relevant to the function - sends email message - logs email sending activity - and any errors are reported as critical - in the main log file - - related_object is not mandatory, other arguments - are. related_object (if given, will be saved in - the activity record) - - if raise_on_failure is True, exceptions.EmailNotSent is raised - """ - try: - assert(subject_line is not None) - subject_line = prefix_the_subject_line(subject_line) - msg = mail.EmailMessage( - subject_line, - body_text, - from_email, - recipient_list, - headers = headers - ) - msg.content_subtype = 'html' - msg.send() - if related_object is not None: - assert(activity_type is not None) - except Exception, error: - logging.critical(unicode(error)) - if raise_on_failure == True: - raise exceptions.EmailNotSent(unicode(error)) - -def mail_moderators( - subject_line = '', - body_text = '', - raise_on_failure = False): - """sends email to forum moderators and admins - """ - from django.db.models import Q - from askbot.models import User - recipient_list = User.objects.filter( - Q(status='m') | Q(is_superuser=True) - ).filter( - is_active = True - ).values_list('email', flat=True) - recipient_list = set(recipient_list) - - from_email = '' - if hasattr(django_settings, 'DEFAULT_FROM_EMAIL'): - from_email = django_settings.DEFAULT_FROM_EMAIL - - try: - mail.send_mail(subject_line, body_text, from_email, recipient_list) - except smtplib.SMTPException, error: - logging.critical(unicode(error)) - if raise_on_failure == True: - raise exceptions.EmailNotSent(unicode(error)) - -INSTRUCTIONS_PREAMBLE = _('<p>To ask by email, please:</p>') -QUESTION_TITLE_INSTRUCTION = _( - '<li>Type title in the subject line</li>' -) -QUESTION_DETAILS_INSTRUCTION = _( - '<li>Type details of your question into the email body</li>' -) -OPTIONAL_TAGS_INSTRUCTION = _( -"""<li>The beginning of the subject line can contain tags, -<em>enclosed in the square brackets</em> like so: [Tag1; Tag2]</li>""" -) -REQUIRED_TAGS_INSTRUCTION = _( -"""<li>In the beginning of the subject add at least one tag -<em>enclosed in the brackets</em> like so: [Tag1; Tag2].</li>""" -) -TAGS_INSTRUCTION_FOOTNOTE = _( -"""<p>Note that a tag may consist of more than one word, to separate -the tags, use a semicolon or a comma, for example, [One tag; Other tag]</p>""" -) - -def bounce_email(email, subject, reason = None, body_text = None): - """sends a bounce email at address ``email``, with the subject - line ``subject``, accepts several reasons for the bounce: - * ``'problem_posting'``, ``unknown_user`` and ``permission_denied`` - * ``body_text`` in an optional parameter that allows to append - extra text to the message - """ - if reason == 'problem_posting': - error_message = _( - '<p>Sorry, there was an error posting your question ' - 'please contact the %(site)s administrator</p>' - ) % {'site': askbot_settings.APP_SHORT_NAME} - - if askbot_settings.TAGS_ARE_REQUIRED: - error_message = string_concat( - INSTRUCTIONS_PREAMBLE, - '<ul>', - QUESTION_TITLE_INSTRUCTION, - REQUIRED_TAGS_INSTRUCTION, - QUESTION_DETAILS_INSTRUCTION, - '</ul>', - TAGS_INSTRUCTION_FOOTNOTE - ) - else: - error_message = string_concat( - INSTRUCTIONS_PREAMBLE, - '<ul>', - QUESTION_TITLE_INSTRUCTION, - QUESTION_DETAILS_INSTRUCTION, - OPTIONAL_TAGS_INSTRUCTION, - '</ul>', - TAGS_INSTRUCTION_FOOTNOTE - ) - - elif reason == 'unknown_user': - error_message = _( - '<p>Sorry, in order to post questions on %(site)s ' - 'by email, please <a href="%(url)s">register first</a></p>' - ) % { - 'site': askbot_settings.APP_SHORT_NAME, - 'url': url_utils.get_login_url() - } - elif reason == 'permission_denied': - error_message = _( - '<p>Sorry, your question could not be posted ' - 'due to insufficient privileges of your user account</p>' - ) - else: - raise ValueError('unknown reason to bounce an email: "%s"' % reason) - - if body_text != None: - error_message = string_concat(error_message, body_text) - - #print 'sending email' - #print email - #print subject - #print error_message - send_mail( - recipient_list = (email,), - subject_line = 'Re: ' + subject, - body_text = error_message - ) - -def extract_reply(text): - """take the part above the separator - and discard the last line above the separator""" - if const.REPLY_SEPARATOR_REGEX.search(text): - text = const.REPLY_SEPARATOR_REGEX.split(text)[0] - return '\n'.join(text.splitlines(True)[:-3]) - else: - return text - -def process_attachment(attachment): - """will save a single - attachment and return - link to file in the markdown format and the - file storage object - """ - file_storage, file_name, file_url = store_file(attachment) - markdown_link = '[%s](%s) ' % (attachment.name, file_url) - file_extension = os.path.splitext(attachment.name)[1] - #todo: this is a hack - use content type - if file_extension.lower() in ('.png', '.jpg', '.jpeg', '.gif'): - markdown_link = '!' + markdown_link - return markdown_link, file_storage - -def process_parts(parts): - """Process parts will upload the attachments and parse out the - body, if body is multipart. Secondly - links to attachments - will be added to the body of the question. - Returns ready to post body of the message and the list - of uploaded files. - """ - body_markdown = '' - stored_files = list() - attachments_markdown = '' - for (part_type, content) in parts: - if part_type == 'attachment': - markdown, stored_file = process_attachment(content) - stored_files.append(stored_file) - attachments_markdown += '\n\n' + markdown - elif part_type == 'body': - body_markdown += '\n\n' + content - elif part_type == 'inline': - markdown, stored_file = process_attachment(content) - stored_files.append(stored_file) - body_markdown += markdown - - #if the response separator is present - - #split the body with it, and discard the "so and so wrote:" part - body_markdown = extract_reply(body_markdown) - - body_markdown += attachments_markdown - return body_markdown.strip(), stored_files - - -def process_emailed_question(from_address, subject, parts, tags = None): - """posts question received by email or bounces the message""" - #a bunch of imports here, to avoid potential circular import issues - from askbot.forms import AskByEmailForm - from askbot.models import User - - try: - #todo: delete uploaded files when posting by email fails!!! - body, stored_files = process_parts(parts) - data = { - 'sender': from_address, - 'subject': subject, - 'body_text': body - } - form = AskByEmailForm(data) - if form.is_valid(): - email_address = form.cleaned_data['email'] - user = User.objects.get( - email__iexact = email_address - ) - - if user.email_isvalid == False: - raise PermissionDenied('Lacking email signature') - - tagnames = form.cleaned_data['tagnames'] - title = form.cleaned_data['title'] - body_text = form.cleaned_data['body_text'] - - #defect - here we might get "too many tags" issue - if tags: - tagnames += ' ' + ' '.join(tags) - - stripped_body_text = user.strip_email_signature(body_text) - if stripped_body_text == body_text and user.email_signature: - #todo: send an email asking to update the signature - raise ValueError('email signature changed') - - user.post_question( - title = title, - tags = tagnames.strip(), - body_text = stripped_body_text, - by_email = True, - email_address = from_address - ) - else: - raise ValidationError() - - except User.DoesNotExist: - bounce_email(email_address, subject, reason = 'unknown_user') - except User.MultipleObjectsReturned: - bounce_email(email_address, subject, reason = 'problem_posting') - except PermissionDenied, error: - bounce_email( - email_address, - subject, - reason = 'permission_denied', - body_text = unicode(error) - ) - except ValidationError: - if from_address: - bounce_email( - from_address, - subject, - reason = 'problem_posting', - ) |