diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-05-27 02:38:22 -0400 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2012-05-27 02:38:22 -0400 |
commit | 6ca7dd00282cf76edf80e2c003a2876a78981fdb (patch) | |
tree | 2458d103011dbd2fa2fbcab21f06660e29209e81 | |
parent | a3369a5eda129db32009961d75d1624756a4ec29 (diff) | |
download | askbot-6ca7dd00282cf76edf80e2c003a2876a78981fdb.tar.gz askbot-6ca7dd00282cf76edf80e2c003a2876a78981fdb.tar.bz2 askbot-6ca7dd00282cf76edf80e2c003a2876a78981fdb.zip |
test cases for the post approval notifications pass
-rw-r--r-- | askbot/const/__init__.py | 1 | ||||
-rw-r--r-- | askbot/models/__init__.py | 57 | ||||
-rw-r--r-- | askbot/models/post.py | 46 | ||||
-rw-r--r-- | askbot/models/question.py | 2 | ||||
-rw-r--r-- | askbot/skins/default/templates/email/notify_author_about_approved_post.html | 20 | ||||
-rw-r--r-- | askbot/tasks.py | 10 | ||||
-rw-r--r-- | askbot/templatetags/extra_filters_jinja.py | 4 | ||||
-rw-r--r-- | askbot/tests/email_alert_tests.py | 44 | ||||
-rw-r--r-- | askbot/tests/utils.py | 8 |
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, ) |