summaryrefslogtreecommitdiffstats
path: root/askbot/utils
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-06-07 01:53:53 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-06-07 01:53:53 -0400
commit9f679e83639c642d903eeacde695baef1be44ec1 (patch)
treedd6c5772f77ac43c5044989959c6df678d16408b /askbot/utils
parent428c91d505a4a09192f1bbc70f7f1c0c1429cc4b (diff)
parent84e1fc6f99879ede88f2d51df2b2730b5df6ff41 (diff)
downloadaskbot-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.py28
-rw-r--r--askbot/utils/html.py15
-rw-r--r--askbot/utils/mail.py347
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',
- )