From 4261942ef2123940a3741bc7b29863fa1518c359 Mon Sep 17 00:00:00 2001 From: Evgeny Fadeev Date: Wed, 23 Jun 2010 01:27:15 -0400 Subject: fixed a bug with response deletion, added a test case and fixed robots.txt url --- askbot/models/__init__.py | 22 +++++++++++- askbot/models/meta.py | 30 ++++++++++++++-- askbot/models/user.py | 1 - askbot/tests.py | 92 ++++++++++++++++++++++++++++++++++++++++++++++- askbot/urls.py | 2 +- askbot/views/readers.py | 76 +++++++++++++++------------------------ 6 files changed, 168 insertions(+), 55 deletions(-) diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index bbda9773..7ed64cd4 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -226,6 +226,24 @@ def flag_post(user, post, timestamp=None, cancel=False): ) auth.onFlaggedItem(flag, post, user, timestamp=timestamp) +def user_increment_response_count(user): + """increment response counter for user + by one + """ + user.response_count += 1 + +def user_decrement_response_count(user): + """decrement response count for the user + by one, log critical error if count would go below zero + but limit decrementation at zero exactly + """ + if user.response_count > 0: + user.response_count -= 1 + else: + logging.critical( + 'response count wanted to go below zero' + ) + User.add_to_class('is_username_taken',classmethod(user_is_username_taken)) User.add_to_class( 'get_q_sel_email_feed_frequency', @@ -241,6 +259,8 @@ User.add_to_class('get_profile_link', get_profile_link) User.add_to_class('get_messages', get_messages) User.add_to_class('delete_messages', delete_messages) User.add_to_class('toggle_favorite_question', toggle_favorite_question) +User.add_to_class('decrement_response_count', user_decrement_response_count) +User.add_to_class('increment_response_count', user_increment_response_count) #todo: move this to askbot/utils ?? def format_instant_notification_body( @@ -379,7 +399,7 @@ def record_post_update_activity( assert(updated_by not in receiving_users) for user in set(receiving_users) | set(newly_mentioned_users): - user.response_count += 1 + user.increment_response_count() user.save() #todo: weird thing is that only comments need the receiving_users diff --git a/askbot/models/meta.py b/askbot/models/meta.py index 00ee60c7..370fefac 100644 --- a/askbot/models/meta.py +++ b/askbot/models/meta.py @@ -1,4 +1,5 @@ import datetime +from django.contrib.contenttypes.models import ContentType from django.db import models from askbot import const from askbot.models import base @@ -192,12 +193,35 @@ class Comment(base.MetaContent, base.UserContent): return self.added_at def delete(self, **kwargs): + """deletes comment and concomitant response activity + records, as well as mention records, while preserving + integrity or response counts for the users + """ #todo: not very good import in models of other models #todo: potentially a circular import from askbot.models.user import Activity - Activity.objects.get_mentions( - mentioned_in = self - ).delete() + comment_content_type = ContentType.objects.get_for_model(self) + comment_id = self.id + + #on these activities decrement response counter + #todo: implement a custom delete method on these + #all this should pack into Activity.responses.filter( somehow ).delete() + response_activity_types = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY + activities = Activity.objects.filter( + content_type = comment_content_type, + object_id = comment_id, + activity_type__in = response_activity_types + ) + for activity in activities: + for user in activity.receiving_users.all(): + user.decrement_response_count() + user.save() + activities.delete() + + #mentions - simply delete + mentions = Activity.objects.get_mentions(mentioned_in = self) + mentions.delete() + super(Comment,self).delete(**kwargs) def get_absolute_url(self): diff --git a/askbot/models/user.py b/askbot/models/user.py index 5fe18858..40445d70 100644 --- a/askbot/models/user.py +++ b/askbot/models/user.py @@ -12,7 +12,6 @@ from django.utils.translation import ugettext as _ from askbot import const from askbot.utils import functions - class ResponseAndMentionActivityManager(models.Manager): def get_query_set(self): response_types = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY diff --git a/askbot/tests.py b/askbot/tests.py index 12eb03a3..dcdf0782 100644 --- a/askbot/tests.py +++ b/askbot/tests.py @@ -129,6 +129,95 @@ class UpdateNotificationTests(TestCase): comment = 'comment33' ) + def post_then_delete_answer_comment(self): + pass + + def post_then_delete_answer(self): + pass + + def post_then_delete_question_comment(self): + pass + + def post_mention_in_question_then_delete(self): + pass + + def post_mention_in_answer_then_delete(self): + pass + + def post_mention_in_question_then_edit_out(self): + pass + + def post_mention_in_answer_then_edit_out(self): + pass + + def test_post_mention_in_question_comment_then_delete(self): + self.reset_response_counts() + time.sleep(1) + timestamp = datetime.datetime.now() + comment = self.question.add_comment( + user = self.u11, + comment = '@user12 howyou doin?', + added_at = timestamp + ) + comment.delete() + notifications = get_re_notif_after(timestamp) + self.assertEqual(len(notifications), 0) + self.reload_users() + self.assertEqual( + [ + self.u11.response_count, + self.u12.response_count, + self.u13.response_count, + self.u14.response_count, + self.u21.response_count, + self.u22.response_count, + self.u23.response_count, + self.u24.response_count, + self.u31.response_count, + self.u32.response_count, + self.u33.response_count, + self.u34.response_count, + ], + [ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + ] + ) + self.reset_response_counts() + time.sleep(1) + timestamp = datetime.datetime.now() + comment = self.answer1.add_comment( + user = self.u21, + comment = 'hey @user22 blah', + added_at = timestamp + ) + comment.delete() + notifications = get_re_notif_after(timestamp) + self.assertEqual(len(notifications), 0) + self.reload_users() + self.assertEqual( + [ + self.u11.response_count, + self.u12.response_count, + self.u13.response_count, + self.u14.response_count, + self.u21.response_count, + self.u22.response_count, + self.u23.response_count, + self.u24.response_count, + self.u31.response_count, + self.u32.response_count, + self.u33.response_count, + self.u34.response_count, + ], + [ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + ] + ) + def test_self_comments(self): self.reset_response_counts() time.sleep(1) @@ -636,7 +725,7 @@ class AnonymousVisitorTests(TestCase): def try_url( url_name, status_code=200, template=None, kwargs={}, redirect_url=None, follow=False, - data = {} + data = {}, ): url = reverse(url_name, kwargs = kwargs) url_info = 'getting url %s' % url @@ -656,6 +745,7 @@ class AnonymousVisitorTests(TestCase): self.assertEqual(r.template[0].name, template) try_url('sitemap') + try_url('feeds', kwargs={'url':'rss'}) try_url('about', template='about.html') try_url('privacy', template='privacy.html') try_url('logout', template='logout.html') diff --git a/askbot/urls.py b/askbot/urls.py index 1a3b59cb..9274f6dc 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -189,7 +189,7 @@ urlpatterns = patterns('', name='read_message' ), url( - r'^feeds/rss/$', + r'^feeds/(?P.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}, name='feeds' diff --git a/askbot/views/readers.py b/askbot/views/readers.py index 07390289..80246d51 100644 --- a/askbot/views/readers.py +++ b/askbot/views/readers.py @@ -332,66 +332,46 @@ def question(request, id):#refactor - long subroutine. display question body, an #2) question view count per user if request.user.is_authenticated(): + + #get response notifications + ACTIVITY_TYPES = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY + ACTIVITY_TYPES += (const.TYPE_ACTIVITY_MENTION,) + response_activities = Activity.objects.filter( + receiving_users = request.user, + activity_type__in = ACTIVITY_TYPES, + ) try: question_view = QuestionView.objects.get( who=request.user, question=question ) - #another task - remove the response alert if it exists - ACTIVITY_TYPES = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY - ACTIVITY_TYPES += (const.TYPE_ACTIVITY_MENTION,) - response_activities = Activity.objects.filter( - receiving_users = request.user, - activity_type__in = ACTIVITY_TYPES, + response_activities = response_activities.filter( active_at__gt = question_view.when ) - - for activity in response_activities: - post = activity.content_object - if hasattr(post, 'get_origin_post'): - if question == post.get_origin_post(): - activity.receiving_users.remove(request.user) - if request.user.response_count > 0: - request.user.response_count -= 1 - request.user.save() - else: - logging.critical( - 'response count wanted to go below zero' - ) - else: - logging.critical( - 'activity content object has no get_origin_post method' - ) - except QuestionView.DoesNotExist: - question_view = QuestionView(who=request.user, question=question) - #todo: cleanup this cut/paste - ACTIVITY_TYPES = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY - ACTIVITY_TYPES += (const.TYPE_ACTIVITY_MENTION,) - response_activities = Activity.objects.filter( - receiving_users = request.user, - activity_type__in = ACTIVITY_TYPES, - ) - - for activity in response_activities: - post = activity.content_object - if hasattr(post, 'get_origin_post'): - if question == post.get_origin_post(): - activity.receiving_users.remove(request.user) - if request.user.response_count > 0: - request.user.response_count -= 1 - request.user.save() - else: - logging.critical( - 'response count wanted to go below zero' + question_view = QuestionView( + who=request.user, + question=question ) - else: - logging.critical( - 'activity content object has no get_origin_post method' - ) question_view.when = datetime.datetime.now() question_view.save() + #filter response activities (already directed to the qurrent user + #as per the query in the beginning of this if branch) + #that refer to the children of the currently + #viewed question and clear them for the current user + for activity in response_activities: + post = activity.content_object + if hasattr(post, 'get_origin_post'): + if question == post.get_origin_post(): + activity.receiving_users.remove(request.user) + request.user.decrement_response_count() + request.user.save() + else: + logging.critical( + 'activity content object has no get_origin_post method' + ) + return render_to_response('question.html', { 'view_name': 'question', 'active_tab': 'questions', -- cgit v1.2.3-1-g7c22