diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2010-09-22 00:45:40 -0400 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2010-09-22 00:45:40 -0400 |
commit | 4b343ee9542435008543b7a2f63cd0550fb2575a (patch) | |
tree | c8f09b93b85fa9b19991e79c568684943594921d | |
parent | 3cf76880c1dfb6032613b68832a7bee38be6d694 (diff) | |
download | askbot-4b343ee9542435008543b7a2f63cd0550fb2575a.tar.gz askbot-4b343ee9542435008543b7a2f63cd0550fb2575a.tar.bz2 askbot-4b343ee9542435008543b7a2f63cd0550fb2575a.zip |
hopefully fixed format of instant emails, made feedback to be sent to moderators and admins, changed comment rendering into div and a small fix to livesearch.js
-rw-r--r-- | askbot/__init__.py | 29 | ||||
-rw-r--r-- | askbot/conf/email.py | 9 | ||||
-rw-r--r-- | askbot/models/__init__.py | 16 | ||||
-rw-r--r-- | askbot/models/content.py | 23 | ||||
-rw-r--r-- | askbot/models/meta.py | 8 | ||||
-rw-r--r-- | askbot/models/question.py | 6 | ||||
-rwxr-xr-x | askbot/skins/default/media/js/com.cnprog.post.js | 4 | ||||
-rw-r--r-- | askbot/skins/default/media/js/live_search.js | 6 | ||||
-rwxr-xr-x | askbot/skins/default/media/style/style.css | 2 | ||||
-rw-r--r-- | askbot/skins/default/templates/instant_notification.html | 7 | ||||
-rw-r--r-- | askbot/skins/default/templates/question.html | 13 | ||||
-rw-r--r-- | askbot/skins/default/templates/questions.html | 8 | ||||
-rw-r--r-- | askbot/startup_tests.py | 4 | ||||
-rw-r--r-- | askbot/tests/email_alert_tests.py | 34 | ||||
-rw-r--r-- | askbot/views/meta.py | 4 | ||||
-rw-r--r-- | askbot/views/readers.py | 14 |
16 files changed, 143 insertions, 44 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py index 0b7e61bb..6c3fac23 100644 --- a/askbot/__init__.py +++ b/askbot/__init__.py @@ -24,6 +24,8 @@ def get_version(): """ return '0.6.11' +#todo: maybe send_mail functions belong to models +#or the future API def send_mail( subject_line = None, body_text = None, @@ -44,9 +46,11 @@ def send_mail( if raise_on_failure is True, exceptions.EmailNotSent is raised """ - #print subject_line - #print body_text + from askbot.conf import settings as askbot_settings + prefix = askbot_settings.EMAIL_SUBJECT_PREFIX.strip() + ' ' try: + assert(subject_line is not None) + subject_line = prefix + subject_line msg = mail.EmailMessage( subject_line, body_text, @@ -62,3 +66,24 @@ def send_mail( logging.critical(unicode(e)) if raise_on_failure == True: raise exceptions.EmailNotSent(unicode(e)) + +def mail_moderators(subject_line, body_text): + """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) + ).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.SMPTException, e: + logging.critical(unicode(e)) + if raise_on_failure == True: + raise exceptions.EmailNotSent(unicode(e)) diff --git a/askbot/conf/email.py b/askbot/conf/email.py index dd3e5bdc..77407d70 100644 --- a/askbot/conf/email.py +++ b/askbot/conf/email.py @@ -67,3 +67,12 @@ settings.register( help_text=_('Use this setting to control gravatar for email-less user') ) ) + +settings.register( + StringValue( + EMAIL, + 'EMAIL_SUBJECT_PREFIX', + default='', + description=_('Prefix for the email subject line'), + ) +) diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index e99672d2..69129813 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -1434,33 +1434,33 @@ def format_instant_notification_email( assert(isinstance(post, Comment)) assert(isinstance(post.content_object, Question)) subject_line = _( - 'new question comment about: "%(title)s"' + 'Re: "%(title)s"' ) % {'title': origin_post.title} elif update_type == 'answer_comment': assert(isinstance(post, Comment)) assert(isinstance(post.content_object, Answer)) subject_line = _( - 'new answer comment about: "%(title)s"' + 'Re: "%(title)s"' ) % {'title': origin_post.title} elif update_type == 'answer_update': assert(isinstance(post, Answer)) subject_line = _( - 'answer modified for: "%(title)s"' + 'Re: "%(title)s"' ) % {'title': origin_post.title} elif update_type == 'new_answer': assert(isinstance(post, Answer)) subject_line = _( - 'new answer for: "%(title)s"' + 'Re: "%(title)s"' ) % {'title': origin_post.title} elif update_type == 'question_update': assert(isinstance(post, Question)) subject_line = _( - 'question modified: "%(title)s"' + 'Question: "%(title)s"' ) % {'title': origin_post.title} elif update_type == 'new_question': assert(isinstance(post, Question)) subject_line = _( - 'new question: "%(title)s"' + 'Question: "%(title)s"' ) % {'title': origin_post.title} else: raise ValueError('unexpected update_type %s' % update_type) @@ -1468,6 +1468,7 @@ def format_instant_notification_email( update_data = { 'update_author_name': from_user.username, 'receiving_user_name': to_user.username, + 'content_preview': post.get_snippet(), 'update_type': update_type, 'post_url': site_url + post.get_absolute_url(), 'origin_post_title': origin_post.title, @@ -1500,6 +1501,7 @@ def send_instant_notifications_about_activity_in_post( 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() for user in receiving_users: subject_line, body_text = format_instant_notification_email( @@ -1515,7 +1517,7 @@ def send_instant_notifications_about_activity_in_post( subject_line = subject_line, body_text = body_text, recipient_list = [user.email], - related_object = post.get_origin_post(), + related_object = origin_post, activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT ) diff --git a/askbot/models/content.py b/askbot/models/content.py index eaba4fd6..636b093e 100644 --- a/askbot/models/content.py +++ b/askbot/models/content.py @@ -6,6 +6,7 @@ from django.contrib.sitemaps import ping_google from django.db import models from askbot.models.meta import Comment, Vote, FlaggedItem from askbot.models.user import EmailFeedSetting +from django.utils import html as html_utils class Content(models.Model): """ @@ -52,6 +53,11 @@ class Content(models.Model): def get_text(self): return self.text + def get_snippet(self): + """returns an abbreviated snippet of the content + """ + return html_utils.strip_tags(self.html)[:120] + ' ...' + def add_comment(self, comment=None, user=None, added_at=None): if added_at is None: added_at = datetime.datetime.now() @@ -68,6 +74,23 @@ class Content(models.Model): comment.parse_and_save(author = user) self.comment_count = self.comment_count + 1 self.save() + + #tried to add this to bump updated question + #in most active list, but it did not work + #becase delayed email updates would be triggered + #for cases where user did not subscribe for them + # + #need to redo the delayed alert sender + # + #origin_post = self.get_origin_post() + #if origin_post == self: + # self.last_activity_at = added_at + # self.last_activity_by = user + #else: + # origin_post.last_activity_at = added_at + # origin_post.last_activity_by = user + # origin_post.save() + return comment def get_instant_notification_subscribers( diff --git a/askbot/models/meta.py b/askbot/models/meta.py index 0da701bc..9aa372cc 100644 --- a/askbot/models/meta.py +++ b/askbot/models/meta.py @@ -1,6 +1,7 @@ import datetime from django.contrib.contenttypes.models import ContentType from django.db import models +from django.utils import html as html_utils from askbot import const from askbot.models import base from askbot.models.user import EmailFeedSetting @@ -99,6 +100,7 @@ class FlaggedItem(base.MetaContent, base.UserContent): def __unicode__(self): return '[%s] flagged at %s' %(self.user, self.flagged_at) +#todo: move this class to content class Comment(base.MetaContent, base.UserContent): comment = models.CharField(max_length = const.COMMENT_HARD_MAX_LENGTH) added_at = models.DateTimeField(default = datetime.datetime.now) @@ -125,6 +127,12 @@ class Comment(base.MetaContent, base.UserContent): def set_text(self, text): self.comment = text + def get_snippet(self): + """returns an abbreviated snippet of the content + todo: remove this if comment model unites with Q&A + """ + return html_utils.strip_tags(self.html)[:120] + ' ...' + def get_owner(self): return self.user diff --git a/askbot/models/question.py b/askbot/models/question.py index a740aac2..c450eed9 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -287,8 +287,10 @@ class Question(content.Content, DeletableContent): similar_questions = self.__class__.objects.filter( tags__in = self.tags.all() ).exclude( - id = self.id - )[:100] + id = self.id, + ).exclude( + deleted = True + ).distinct()[:100] similar_questions = list(similar_questions) output = list() for question in similar_questions: diff --git a/askbot/skins/default/media/js/com.cnprog.post.js b/askbot/skins/default/media/js/com.cnprog.post.js index ae4e5d50..e03053ab 100755 --- a/askbot/skins/default/media/js/com.cnprog.post.js +++ b/askbot/skins/default/media/js/com.cnprog.post.js @@ -593,7 +593,7 @@ function createComments(type) { // {"Id":6,"PostId":38589,"CreationDate":"an hour ago","Text":"hello there!","UserDisplayName":"Jarrod Dixon","UserUrl":"/users/3/jarrod-dixon","DeleteUrl":null} var renderComment = function(jDiv, json) { - var html = '<p id="comment-' + json.id + '" class="comment" style="display:none">' + json.text; + var html = '<div id="comment-' + json.id + '" class="comment" style="display:none">' + json.text; html += json.user_url ? ' - <a href="' + json.user_url + '"' : '<span'; html += ' class="comment-user">' + json.user_display_name + (json.user_url ? '</a>' : '</span>'); html += ' (' + json.comment_age + ')'; @@ -605,7 +605,7 @@ function createComments(type) { if (json.delete_url) { } - html += '</p>'; + html += '</div>'; jDiv.append(html); }; diff --git a/askbot/skins/default/media/js/live_search.js b/askbot/skins/default/media/js/live_search.js index ea429ddd..ec18bb6c 100644 --- a/askbot/skins/default/media/js/live_search.js +++ b/askbot/skins/default/media/js/live_search.js @@ -250,10 +250,10 @@ $(document).ready(function(){ new_list.attr('id', q_list_sel); render_paginator(data['paginator']); set_question_count(data['question_counter']); + render_faces(data['faces']); + render_related_tags(data['related_tags']); + query.focus(); } - render_faces(data['faces']); - render_related_tags(data['related_tags']); - query.focus(); //show new div } diff --git a/askbot/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css index 71cec370..cbdceba9 100755 --- a/askbot/skins/default/media/style/style.css +++ b/askbot/skins/default/media/style/style.css @@ -2362,7 +2362,7 @@ p.space-above { vertical-align: top; } -p.comment { +.comment { border-top: 1px dotted #ccccce; margin: 0; font-size: 11px; diff --git a/askbot/skins/default/templates/instant_notification.html b/askbot/skins/default/templates/instant_notification.html index c958c41b..86556fda 100644 --- a/askbot/skins/default/templates/instant_notification.html +++ b/askbot/skins/default/templates/instant_notification.html @@ -3,14 +3,12 @@ {% blocktrans %}<p>Dear {{receiving_user_name}},</p>{% endblocktrans %} {% if update_type == 'question_comment' %} {% blocktrans %} -<p>{{update_author_name}} left a <a href="%{{post_url}}">new comment</a> -for question "{{origin_post_title}}"</p> +<p>{{update_author_name}} left a <a href="{{post_url}}">new comment</a>:</p> {% endblocktrans %} {% endif %} {% if update_type == 'answer_comment' %} {% blocktrans %} -<p>{{update_author_name}} left a <a href="{{post_url}}">new comment</a> - for an answer to question "{{origin_post_title}}"</p> +<p>{{update_author_name}} left a <a href="{{post_url}}">new comment</a></p> {% endblocktrans %} {% endif %} {% if update_type == 'new_answer' %} @@ -39,6 +37,7 @@ for question "{{origin_post_title}}"</p> {% endif %} <p></p> {% blocktrans %} +<div>{{content_preview}}</div> <p>Please note - you can easily <a href="{{user_subscriptions_url}}">change</a> how often you receive these notifications or unsubscribe. Thank you for your interest in our forum!</p> {% endblocktrans %} diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html index d7bc42fb..73a43d14 100644 --- a/askbot/skins/default/templates/question.html +++ b/askbot/skins/default/templates/question.html @@ -187,9 +187,10 @@ {% post_contributor_info question "original_author" %} {% post_contributor_info question "last_updater" %} </div> + {% spaceless %} <div class="comments-container" id="comments-container-question-{{question.id}}"> {% for comment in question.get_comments|slice:":5" %} - <p class="comment" id="comment-{{comment.id}}"> + <div class="comment" id="comment-{{comment.id}}"> {{comment.html|safe}} - <a class="comment-user" href="{{comment.user.get_profile_url}}">{{comment.user}}</a> {% spaceless %} @@ -200,9 +201,10 @@ title="{% trans "delete this comment" %}"/> {% endif %} {% endspaceless %} - </p> + </div> {% endfor %} </div> + {% endspaceless %} <div class="post-comments" style="margin-bottom:20px"> <input id="can-post-comments-question-{{question.id}}" type="hidden" value="{{ request.user|can_post_comment:question }}"/> {% if request.user|can_post_comment:question or question.comment_count > 5 %} @@ -329,9 +331,10 @@ {% post_contributor_info answer "original_author" %} {% post_contributor_info answer "last_updater" %} </div> + {% spaceless %} <div class="comments-container" id="comments-container-answer-{{answer.id}}"> {% for comment in answer.get_comments|slice:":5" %} - <p id="comment-{{comment.id}}" class="comment"> + <div id="comment-{{comment.id}}" class="comment"> {{comment.html|safe}} - <a class="comment-user" href="{{comment.user.get_profile_url}}">{{comment.user}}</a> {% spaceless %} @@ -342,9 +345,10 @@ title="{% trans "delete this comment" %}"/> {% endif %} {% endspaceless %} - </p> + </div> {% endfor %} </div> + {% endspaceless %} <div class="post-comments" style="margin-bottom:20px"> <input id="can-post-comments-answer-{{answer.id}}" type="hidden" value="{{ request.user|can_post_comment:answer}}"/> {% if request.user|can_post_comment:answer or answer.comment_count > 5 %} @@ -501,7 +505,6 @@ <div class="boxC"> <h3 class="subtitle">{% trans "Related questions" %}</h3> <div class="questions-related"> - {% for question in similar_questions.data %} <p> <a href="{{ question.get_absolute_url }}">{{ question.get_question_title }}</a> diff --git a/askbot/skins/default/templates/questions.html b/askbot/skins/default/templates/questions.html index 36a15ae1..d35336aa 100644 --- a/askbot/skins/default/templates/questions.html +++ b/askbot/skins/default/templates/questions.html @@ -302,9 +302,11 @@ {% cache 600 contributors search_tags scope sort query context.page context.page_size LANGUAGE_CODE %} <div id="contrib-users" class="boxC"> <h3 class="subtitle">{% trans "Contributors" %}</h3> - {% for person in contributors %} - {% gravatar person 48 %} - {% endfor %} + {% spaceless %} + {% for person in contributors %} + {% gravatar person 48 %} + {% endfor %} + {% endspaceless %} </div> {% endcache %} {% endif %} diff --git a/askbot/startup_tests.py b/askbot/startup_tests.py index 6a238965..c6d000a1 100644 --- a/askbot/startup_tests.py +++ b/askbot/startup_tests.py @@ -8,6 +8,10 @@ the main function is run_startup_tests from django.conf import settings from django.core.exceptions import ImproperlyConfigured +#todo: +# +# *validate emails in settings.py + def run_startup_tests(): """main function that runs all startup tests diff --git a/askbot/tests/email_alert_tests.py b/askbot/tests/email_alert_tests.py index 3ce4fc6b..c54f8ad2 100644 --- a/askbot/tests/email_alert_tests.py +++ b/askbot/tests/email_alert_tests.py @@ -4,7 +4,9 @@ import copy from django.conf import settings as django_settings from django.core import management import django.core.mail +from django.core.urlresolvers import reverse from django.test import TestCase +from django.test.client import Client from askbot.tests import utils from askbot import models @@ -680,3 +682,35 @@ class DelayedAlertSubjectLineTests(TestCase): order, sorted(order) ) + +class FeedbackTests(utils.AskbotTestCase): + def setUp(self): + self.create_user(username = 'user1', status='m') + self.create_user(username = 'user2', status='m') + u3 = self.create_user(username = 'user3') + u3.is_superuser = True + u3.save() + + def assert_feedback_works(self): + outbox = django.core.mail.outbox + self.assertEqual(len(outbox), 1) + self.assertEqual(len(outbox[0].recipients()), 3) + + def test_feedback_post_form(self): + client = Client() + data = { + 'email': 'evgeny.fadeev@gmail.com', + 'text': 'hi this is a test case', + 'subject': 'subject line' + } + response = client.post(reverse('feedback'), data) + self.assertEquals(response.status_code, 200) + self.assertEquals(response.template[0].name, 'feedback.html') + + def test_mail_moderators(self): + """tests askbot.mail_moderators() + """ + import askbot + askbot.mail_moderators('subject', 'text') + self.assert_feedback_works() + diff --git a/askbot/views/meta.py b/askbot/views/meta.py index b4a22932..88d9bac7 100644 --- a/askbot/views/meta.py +++ b/askbot/views/meta.py @@ -9,10 +9,10 @@ from django.template import RequestContext from django.http import HttpResponseRedirect, HttpResponse from askbot.forms import FeedbackForm from django.core.urlresolvers import reverse -from django.core.mail import mail_admins from django.utils.translation import ugettext as _ from askbot.utils.forms import get_next_url from askbot.models import Badge, Award +import askbot def about(request): return render_to_response('about.html', context_instance=RequestContext(request)) @@ -37,7 +37,7 @@ def feedback(request): data['message'] = form.cleaned_data['message'] data['name'] = form.cleaned_data.get('name',None) message = render_to_response('feedback_email.txt',data,context_instance=RequestContext(request)) - mail_admins(_('Q&A forum feedback'), message) + askbot.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)) diff --git a/askbot/views/readers.py b/askbot/views/readers.py index 1281918c..6c4e6cce 100644 --- a/askbot/views/readers.py +++ b/askbot/views/readers.py @@ -25,7 +25,6 @@ from django.views.decorators.cache import cache_page from django.core import exceptions as django_exceptions from django.contrib.humanize.templatetags import humanize -from askbot.utils.slug import slugify from askbot.utils.html import sanitize_html #from lxml.html.diff import htmldiff from askbot.utils.diff import textDiff as htmldiff @@ -433,18 +432,7 @@ def question(request, id):#refactor - long subroutine. display question body, an question = get_object_or_404(Question, id=id) try: - path_prefix = r'/%s%s%d/' % ( - settings.ASKBOT_URL, - _('question/'), - question.id - ) - if not request.path.startswith(path_prefix): - logging.critical('bad request path %s' % request.path) - raise Http404 - slug = request.path.replace(path_prefix, '', 1) - logging.debug('have slug %s' % slug) - logging.debug('requestion path is %s' % request.path) - assert(slug == slugify(question.title)) + assert(request.path == question.get_absolute_url()) except AssertionError: logging.debug('no slug match!') return HttpResponseRedirect(question.get_absolute_url()) |