summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-05-27 02:38:22 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-05-27 02:38:22 -0400
commit6ca7dd00282cf76edf80e2c003a2876a78981fdb (patch)
tree2458d103011dbd2fa2fbcab21f06660e29209e81
parenta3369a5eda129db32009961d75d1624756a4ec29 (diff)
downloadaskbot-6ca7dd00282cf76edf80e2c003a2876a78981fdb.tar.gz
askbot-6ca7dd00282cf76edf80e2c003a2876a78981fdb.tar.bz2
askbot-6ca7dd00282cf76edf80e2c003a2876a78981fdb.zip
test cases for the post approval notifications pass
-rw-r--r--askbot/const/__init__.py1
-rw-r--r--askbot/models/__init__.py57
-rw-r--r--askbot/models/post.py46
-rw-r--r--askbot/models/question.py2
-rw-r--r--askbot/skins/default/templates/email/notify_author_about_approved_post.html20
-rw-r--r--askbot/tasks.py10
-rw-r--r--askbot/templatetags/extra_filters_jinja.py4
-rw-r--r--askbot/tests/email_alert_tests.py44
-rw-r--r--askbot/tests/utils.py8
9 files changed, 162 insertions, 30 deletions
diff --git a/askbot/const/__init__.py b/askbot/const/__init__.py
index ae1d7d2d..e711de92 100644
--- a/askbot/const/__init__.py
+++ b/askbot/const/__init__.py
@@ -54,6 +54,7 @@ POST_SORT_METHODS = (
POST_TYPES = ('answer', 'comment', 'question', 'tag_wiki', 'reject_reason')
+SIMPLE_REPLY_SEPARATOR_TEMPLATE = '==== %s -=-=='
REPLY_SEPARATOR_TEMPLATE = '==== %(user_action)s %(instruction)s -=-=='
REPLY_WITH_COMMENT_TEMPLATE = _(
'Note: to reply with a comment, '
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index 6b425db8..96be2c69 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -2289,7 +2289,8 @@ def user_approve_post_revision(user, post_revision, timestamp = None):
#because this function extracts newly mentioned users
#and sends the post_updated signal, which ultimately triggers
#sending of the email update
- post.parse_and_save(author = post_revision.author)
+ post.parse_and_save(author = post_revision.author, was_approved = True)
+
if post_revision.post.post_type == 'question':
thread = post.thread
thread.approved = True
@@ -2807,26 +2808,61 @@ def send_instant_notifications_about_activity_in_post(
headers = headers
)
-def send_notification_about_approved_post(post):
+def notify_author_about_approved_post(post):
"""notifies author about approved post,
assumes that we have the very first revision
"""
- #for answerable email
+ #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': post.author,
+ 'post': 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 post.post_type == 'question':
+ mailto_link_subject = 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': post
+ 'post': post,
+ '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('zhopa')
+ 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 was approved') % data,
body_text = template.render(Context(data)),
- recipient_list = [post.author,],
+ recipient_list = [post.author.email,],
related_object = post,
- activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT
+ activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
+ headers = headers
)
@@ -2845,6 +2881,8 @@ def record_post_update_activity(
updated_by = None,
timestamp = None,
created = False,
+ was_approved = False,
+ by_email = False,
diff = None,
**kwargs
):
@@ -2875,6 +2913,11 @@ def record_post_update_activity(
created = created,
diff = diff,
)
+ if post.should_notify_author_about_publishing(
+ was_approved = was_approved,
+ by_email = by_email
+ ):
+ tasks.notify_author_about_approved_post_celery_task.delay(post)
#non-celery version
#tasks.record_post_update(
# post = post,
diff --git a/askbot/models/post.py b/askbot/models/post.py
index 2592ee94..b98c67a3 100644
--- a/askbot/models/post.py
+++ b/askbot/models/post.py
@@ -442,51 +442,55 @@ class Post(models.Model):
return data
#todo: when models are merged, it would be great to remove author parameter
- def parse_and_save(post, author = None, **kwargs):
+ def parse_and_save(
+ self, author = None, was_approved = False, by_email = False, **kwargs
+ ):
"""generic method to use with posts to be used prior to saving
post edit or addition
"""
assert(author is not None)
- last_revision = post.html
- data = post.parse_post_text()
+ last_revision = self.html
+ data = self.parse_post_text()
- post.html = data['html']
+ self.html = data['html']
newly_mentioned_users = set(data['newly_mentioned_users']) - set([author])
removed_mentions = data['removed_mentions']
#a hack allowing to save denormalized .summary field for questions
- if hasattr(post, 'summary'):
- post.summary = post.get_snippet()
+ if hasattr(self, 'summary'):
+ self.summary = self.get_snippet()
#delete removed mentions
for rm in removed_mentions:
rm.delete()
- created = post.pk is None
+ created = self.pk is None
#this save must precede saving the mention activity
#because generic relation needs primary key of the related object
- super(post.__class__, post).save(**kwargs)
+ super(self.__class__, self).save(**kwargs)
if last_revision:
- diff = htmldiff(last_revision, post.html)
+ diff = htmldiff(last_revision, self.html)
else:
- diff = post.get_snippet()
+ diff = self.get_snippet()
- timestamp = post.get_time_of_last_edit()
+ timestamp = self.get_time_of_last_edit()
#todo: this is handled in signal because models for posts
#are too spread out
from askbot.models import signals
signals.post_updated.send(
- post = post,
+ post = self,
updated_by = author,
newly_mentioned_users = newly_mentioned_users,
timestamp = timestamp,
created = created,
+ by_email = by_email,
+ was_approved = was_approved,
diff = diff,
- sender = post.__class__
+ sender = self.__class__
)
try:
@@ -514,6 +518,17 @@ class Post(models.Model):
def needs_moderation(self):
return self.approved == False
+ def should_notify_author_about_publishing(
+ self, was_approved = False, by_email = False
+ ):
+ """True if post is a newly published question or answer
+ which was posted by email and or just approved by the
+ moderator"""
+ if self.post_type in ('question', 'answer'):
+ if self.revisions.count() == 0:#brand new post
+ return was_approved or by_email
+ return False
+
def get_absolute_url(self, no_slug = False, question_post=None, thread=None):
from askbot.utils.slug import slugify
#todo: the url generation function is pretty bad -
@@ -1048,10 +1063,7 @@ class Post(models.Model):
return self.revisions.order_by('-revised_at')[0]
def get_latest_revision_number(self):
- if self.is_comment():
- return 1
- else:
- return self.get_latest_revision().revision
+ return self.get_latest_revision().revision
def get_time_of_last_edit(self):
if self.is_comment():
diff --git a/askbot/models/question.py b/askbot/models/question.py
index a18e719b..795ecfed 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -107,7 +107,7 @@ class ThreadManager(models.Manager):
question.last_edited_at = added_at
question.wikified_at = added_at
- question.parse_and_save(author = author)
+ question.parse_and_save(author = author, by_email = by_email)
question.add_revision(
author = author,
diff --git a/askbot/skins/default/templates/email/notify_author_about_approved_post.html b/askbot/skins/default/templates/email/notify_author_about_approved_post.html
new file mode 100644
index 00000000..6083afc1
--- /dev/null
+++ b/askbot/skins/default/templates/email/notify_author_about_approved_post.html
@@ -0,0 +1,20 @@
+{#
+ parameters:
+ * reply_separator_line
+ * replace_content_address
+ * mailto_link_subject
+ * post
+ * reply_code (comma-separated list of emails to respond to this message)
+#}
+{{ reply_separator_line }}
+<p>{% trans
+ post_text=post.text|safe_urlquote,
+ subject=mailto_link_subject|safe_urlquote
+%}If you would like to edit by email, please
+<a href="mailto://{{ replace_content_address }}?body={{ post_text }}&subject={{ subject }}">click here</a>{% endtrans %}</p>
+<p>{% trans %}Below is a copy of your post:{% endtrans %}</p>
+{% if post.post_type == 'question' %}
+ <p style="font-size:16px">{{ post.thread.title }}</p>
+{% endif %}
+{{ post.html }}
+<p style="font-size:8px;color:#aaa;">{{ reply_code }}</p>
diff --git a/askbot/tasks.py b/askbot/tasks.py
index 23966119..447b6b78 100644
--- a/askbot/tasks.py
+++ b/askbot/tasks.py
@@ -25,6 +25,7 @@ from celery.decorators import task
from askbot.conf import settings as askbot_settings
from askbot.models import Activity, Post, Thread, User
from askbot.models import send_instant_notifications_about_activity_in_post
+from askbot.models import notify_author_about_approved_post
from askbot.models.badges import award_badges_signal
# TODO: Make exceptions raised inside record_post_update_celery_task() ...
@@ -32,6 +33,10 @@ from askbot.models.badges import award_badges_signal
# (i.e. if Celery tasks are not deferred but executed straight away)
@task(ignore_result = True)
+def notify_author_about_approved_post_celery_task(post):
+ notify_author_about_approved_post(post)
+
+@task(ignore_result = True)
def record_post_update_celery_task(
post_id,
post_content_type_id,
@@ -156,10 +161,7 @@ def record_post_update(
post = post,
recipients = notification_subscribers,
)
- #if post.post_type in ('question', 'answer'):
- # if created and post.was_moderated():
- # notify_author_about_approved_post(post)
-
+
@task(ignore_result = True)
def record_question_visit(
diff --git a/askbot/templatetags/extra_filters_jinja.py b/askbot/templatetags/extra_filters_jinja.py
index b03e4a89..fa9d0ced 100644
--- a/askbot/templatetags/extra_filters_jinja.py
+++ b/askbot/templatetags/extra_filters_jinja.py
@@ -47,6 +47,10 @@ def add_tz_offset(datetime_object):
return str(datetime_object) + ' ' + TIMEZONE_STR
@register.filter
+def safe_urlquote(text):
+ return urllib.quote_plus(text.encode('utf8'))
+
+@register.filter
def strip_path(url):
"""removes path part of the url"""
return url_utils.strip_path(url)
diff --git a/askbot/tests/email_alert_tests.py b/askbot/tests/email_alert_tests.py
index 828b341b..5f20496d 100644
--- a/askbot/tests/email_alert_tests.py
+++ b/askbot/tests/email_alert_tests.py
@@ -949,3 +949,47 @@ class EmailFeedSettingTests(utils.AskbotTestCase):
new_user.add_missing_askbot_subscriptions()
data_after = TO_JSON(self.get_user_feeds())
self.assertEquals(data_before, data_after)
+
+class PostApprovalTests(utils.AskbotTestCase):
+ """test notifications sent to authors when their posts
+ are approved or published"""
+ def setUp(self):
+ assert(
+ django_settings.EMAIL_BACKEND == 'django.core.mail.backends.locmem.EmailBackend'
+ )
+
+ def test_emailed_question_answerable_approval_notification(self):
+ setting_backup = askbot_settings.REPLY_BY_EMAIL
+ askbot_settings.update('REPLY_BY_EMAIL', True)
+ self.u1 = self.create_user('user1', status = 'a')
+ question = self.post_question(user = self.u1, by_email = True)
+ outbox = django.core.mail.outbox
+ self.assertEquals(len(outbox), 1)
+ self.assertEquals(outbox[0].recipients(), [self.u1.email])
+ askbot_settings.update('REPLY_BY_EMAIL', setting_backup)
+
+ def test_moderated_question_answerable_approval_notification(self):
+ setting_backup1 = askbot_settings.REPLY_BY_EMAIL
+ askbot_settings.update('REPLY_BY_EMAIL', True)
+ setting_backup2 = askbot_settings.ENABLE_CONTENT_MODERATION
+ askbot_settings.update('ENABLE_CONTENT_MODERATION', True)
+
+ u1 = self.create_user('user1', status = 'a')
+ question = self.post_question(user = u1, by_email = True)
+
+ self.assertEquals(question.approved, False)
+
+ u2 = self.create_user('admin', status = 'd')
+
+ self.assertEquals(question.revisions.count(), 1)
+ u2.approve_post_revision(question.get_latest_revision())
+
+ outbox = django.core.mail.outbox
+ self.assertEquals(len(outbox), 2)
+ #moderation notification
+ self.assertEquals(outbox[0].recipients(), [u1.email,])
+ self.assertEquals(outbox[1].recipients(), [u1.email,])#approval
+
+ askbot_settings.update('REPLY_BY_EMAIL', setting_backup1)
+ askbot_settings.update('ENABLE_CONTENT_MODERATION', setting_backup2)
+
diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py
index fdeea371..8395b1ca 100644
--- a/askbot/tests/utils.py
+++ b/askbot/tests/utils.py
@@ -115,10 +115,11 @@ class AskbotTestCase(TestCase):
title = 'test question title',
body_text = 'test question body text',
tags = 'test',
+ by_email = False,
wiki = False,
is_anonymous = False,
follow = False,
- timestamp = None
+ timestamp = None,
):
"""posts and returns question on behalf
of user. If user is not given, it will be self.user
@@ -135,6 +136,7 @@ class AskbotTestCase(TestCase):
title = title,
body_text = body_text,
tags = tags,
+ by_email = by_email,
wiki = wiki,
is_anonymous = is_anonymous,
timestamp = timestamp
@@ -155,6 +157,7 @@ class AskbotTestCase(TestCase):
user = None,
question = None,
body_text = 'test answer text',
+ by_email = False,
follow = False,
wiki = False,
timestamp = None
@@ -165,6 +168,7 @@ class AskbotTestCase(TestCase):
return user.post_answer(
question = question,
body_text = body_text,
+ by_email = by_email,
follow = follow,
wiki = wiki,
timestamp = timestamp
@@ -175,6 +179,7 @@ class AskbotTestCase(TestCase):
user = None,
parent_post = None,
body_text = 'test comment text',
+ by_email = False,
timestamp = None
):
"""posts and returns a comment to parent post, uses
@@ -187,6 +192,7 @@ class AskbotTestCase(TestCase):
comment = user.post_comment(
parent_post = parent_post,
body_text = body_text,
+ by_email = by_email,
timestamp = timestamp,
)