From 01ff8ebe9a55e019e2b8f02bc2336a7c3d3c8d60 Mon Sep 17 00:00:00 2001 From: Evgeny Fadeev Date: Thu, 4 Nov 2010 14:51:47 -0400 Subject: changed Activity model to prepare for some feature changes, bug fix in post flagging --- askbot/auth.py | 11 +- .../0023_auto__add_activityauditstatus.py | 319 ++++++++++++++++++ ..._to_activity_and_denorm_question_on_activity.py | 375 +++++++++++++++++++++ askbot/models/__init__.py | 91 ++--- askbot/models/answer.py | 12 +- askbot/models/meta.py | 2 +- askbot/models/question.py | 10 +- askbot/models/user.py | 43 ++- askbot/tests/on_screen_notification_tests.py | 336 ++++++------------ askbot/views/users.py | 4 +- 10 files changed, 900 insertions(+), 303 deletions(-) create mode 100644 askbot/migrations/0023_auto__add_activityauditstatus.py create mode 100644 askbot/migrations/0024_add_recipients_m2m_to_activity_and_denorm_question_on_activity.py diff --git a/askbot/auth.py b/askbot/auth.py index e0f314c1..4a1602e5 100644 --- a/askbot/auth.py +++ b/askbot/auth.py @@ -69,6 +69,12 @@ def onFlaggedItem(item, post, user, timestamp=None): ) reputation.save() + signals.flag_offensive.send( + sender=post.__class__, + instance=post, + mark_by=user + ) + #todo: These should be updated to work on same revisions. if post.offensive_flag_count == askbot_settings.MIN_FLAGS_TO_HIDE_POST: post.author.reputation = \ @@ -114,11 +120,6 @@ def onFlaggedItem(item, post, user, timestamp=None): #post.deleted_at = timestamp #post.deleted_by = Admin post.save() - signals.flag_offensive.send( - sender=post.__class__, - instance=post, - mark_by=user - ) @transaction.commit_on_success def onAnswerAccept(answer, user, timestamp=None): diff --git a/askbot/migrations/0023_auto__add_activityauditstatus.py b/askbot/migrations/0023_auto__add_activityauditstatus.py new file mode 100644 index 00000000..74f849c8 --- /dev/null +++ b/askbot/migrations/0023_auto__add_activityauditstatus.py @@ -0,0 +1,319 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'ActivityAuditStatus' + db.create_table('askbot_activityauditstatus', ( + ('status', self.gf('django.db.models.fields.SmallIntegerField')(default=0)), + ('activity', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Activity'])), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + )) + db.send_create_signal('askbot', ['ActivityAuditStatus']) + #denorm field to make User.visit_question call quicker + db.add_column(u'activity', 'question', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Question'], null=True), keep_default=False) + + + def backwards(self, orm): + + # Deleting model 'ActivityAuditStatus' + db.delete_column(u'activity', 'question') + db.delete_table('askbot_activityauditstatus') + + + models = { + 'askbot.activity': { + 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"}, + 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null':'True'}), + 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.activityauditstatus': { + 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'}, + 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.anonymousanswer': { + 'Meta': {'object_name': 'AnonymousAnswer'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Question']"}), + 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}), + 'text': ('django.db.models.fields.TextField', [], {}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) + }, + 'askbot.anonymousquestion': { + 'Meta': {'object_name': 'AnonymousQuestion'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}), + 'text': ('django.db.models.fields.TextField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) + }, + 'askbot.answer': { + 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"}, + 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['auth.User']"}), + 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['auth.User']"}), + 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['auth.User']"}), + 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_answers'", 'null': 'True', 'to': "orm['auth.User']"}), + 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['askbot.Question']"}), + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'askbot.answerrevision': { + 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"}, + 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.Answer']"}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'revised_at': ('django.db.models.fields.DateTimeField', [], {}), + 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {}) + }, + 'askbot.award': { + 'Meta': {'object_name': 'Award', 'db_table': "u'award'"}, + 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.Badge']"}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"}) + }, + 'askbot.badge': { + 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"}, + 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "'Award'", 'to': "orm['auth.User']"}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}), + 'type': ('django.db.models.fields.SmallIntegerField', [], {}) + }, + 'askbot.comment': { + 'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '2048'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['auth.User']"}) + }, + 'askbot.emailfeedsetting': { + 'Meta': {'object_name': 'EmailFeedSetting'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}), + 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"}) + }, + 'askbot.favoritequestion': { + 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"}) + }, + 'askbot.flaggeditem': { + 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['auth.User']"}) + }, + 'askbot.markedtag': { + 'Meta': {'object_name': 'MarkedTag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"}) + }, + 'askbot.question': { + 'Meta': {'object_name': 'Question', 'db_table': "u'question'"}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['auth.User']"}), + 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['auth.User']"}), + 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['auth.User']"}), + 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'symmetrical': 'False', 'through': "'FavoriteQuestion'", 'to': "orm['auth.User']"}), + 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'symmetrical': 'False', 'to': "orm['auth.User']"}), + 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['auth.User']"}), + 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['auth.User']"}), + 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_questions'", 'null': 'True', 'to': "orm['auth.User']"}), + 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}), + 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'askbot.questionrevision': { + 'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.Question']"}), + 'revised_at': ('django.db.models.fields.DateTimeField', [], {}), + 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}), + 'text': ('django.db.models.fields.TextField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}) + }, + 'askbot.questionview': { + 'Meta': {'object_name': 'QuestionView'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Question']"}), + 'when': ('django.db.models.fields.DateTimeField', [], {}), + 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"}) + }, + 'askbot.repute': { + 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"}, + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True', 'blank': 'True'}), + 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}), + 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.tag': { + 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"}, + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}), + 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + 'askbot.vote': { + 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'Vote', 'db_table': "u'vote'"}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}), + 'vote': ('django.db.models.fields.SmallIntegerField', [], {}), + 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}) + }, + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}), + 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}), + 'tag_filter_setting': ('django.db.models.fields.CharField', [], {'default': "'ignored'", 'max_length': '16'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['askbot'] diff --git a/askbot/migrations/0024_add_recipients_m2m_to_activity_and_denorm_question_on_activity.py b/askbot/migrations/0024_add_recipients_m2m_to_activity_and_denorm_question_on_activity.py new file mode 100644 index 00000000..42dfcb52 --- /dev/null +++ b/askbot/migrations/0024_add_recipients_m2m_to_activity_and_denorm_question_on_activity.py @@ -0,0 +1,375 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models +from askbot import const + +#some of activities are not related to question, so they are not processed here +APPROPRIATE_ACTIVITIES = ( + const.TYPE_ACTIVITY_ASK_QUESTION, + const.TYPE_ACTIVITY_UPDATE_QUESTION, + const.TYPE_ACTIVITY_DELETE_QUESTION, + const.TYPE_ACTIVITY_UPDATE_TAGS, + const.TYPE_ACTIVITY_ANSWER, + const.TYPE_ACTIVITY_UPDATE_ANSWER, + const.TYPE_ACTIVITY_DELETE_ANSWER, + const.TYPE_ACTIVITY_MARK_ANSWER, + const.TYPE_ACTIVITY_COMMENT_QUESTION, + const.TYPE_ACTIVITY_COMMENT_ANSWER, + const.TYPE_ACTIVITY_MARK_OFFENSIVE, + const.TYPE_ACTIVITY_MENTION, + const.TYPE_ACTIVITY_FAVORITE, +) + +class Migration(DataMigration): + + def forwards(self, orm): + self._orm_for_askbot = orm + #1) fill in audit status values + activities = orm.Activity.objects.exclude(receiving_users=None) + + have_problems = False + errors = set() + bad_ids = list() + for act in activities: + users = act.receiving_users.all() + for user in users: + orm.ActivityAuditStatus(user = user, activity = act).save() + + #2) save question value into the activity + for act in orm.Activity.objects.all(): + if act.activity_type in APPROPRIATE_ACTIVITIES: + try: + act.question = self.get_question_from_generic_relation(act) + act.save() + except Exception, e: + have_problems = True + errors.add(unicode(e)) + bad_ids.append(str(act.id)) + + if have_problems: + print 'Migration is now complete, but there were some errors:' + print '\n'.join(errors) + print 'problematic activity objects are: ' + ','.join(bad_ids) + + def get_orm(self): + return self._orm_for_askbot + + def get_question_from_generic_relation(self, parent): + orm = self.get_orm() + model = parent.content_type.model + id = parent.object_id + #print 'model is ' + model + if model == 'question': + return orm.Question.objects.get(id=id) + elif model == 'answer': + return orm.Answer.objects.get(id=id).question + elif model == 'favoritequestion': + try: + return orm.FavoriteQuestion.objects.get(id=id).question + except orm.FavoriteQuestion.DoesNotExist: + #ignore this issue for now + return None + elif model == 'comment': + comment = orm.Comment.objects.get(id=id) + return self.get_question_from_generic_relation(comment) + else: + print 'dropped migration of activity in %s' % model + return None + + def backwards(self, orm): + orm.ActivityAuditStatus.objects.all().delete() + + + models = { + 'askbot.activity': { + 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"}, + 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null':'True'}), + 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}), + 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "'ActivityAuditStatus'", 'to': "orm['auth.User']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.activityauditstatus': { + 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'}, + 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.anonymousanswer': { + 'Meta': {'object_name': 'AnonymousAnswer'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Question']"}), + 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}), + 'text': ('django.db.models.fields.TextField', [], {}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) + }, + 'askbot.anonymousquestion': { + 'Meta': {'object_name': 'AnonymousQuestion'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}), + 'text': ('django.db.models.fields.TextField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}) + }, + 'askbot.answer': { + 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"}, + 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['auth.User']"}), + 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['auth.User']"}), + 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['auth.User']"}), + 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_answers'", 'null': 'True', 'to': "orm['auth.User']"}), + 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['askbot.Question']"}), + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'askbot.answerrevision': { + 'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"}, + 'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.Answer']"}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'revised_at': ('django.db.models.fields.DateTimeField', [], {}), + 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {}) + }, + 'askbot.award': { + 'Meta': {'object_name': 'Award', 'db_table': "u'award'"}, + 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.Badge']"}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"}) + }, + 'askbot.badge': { + 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"}, + 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "'Award'", 'to': "orm['auth.User']"}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}), + 'type': ('django.db.models.fields.SmallIntegerField', [], {}) + }, + 'askbot.comment': { + 'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '2048'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'html': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '2048'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['auth.User']"}) + }, + 'askbot.emailfeedsetting': { + 'Meta': {'object_name': 'EmailFeedSetting'}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}), + 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"}) + }, + 'askbot.favoritequestion': { + 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"}) + }, + 'askbot.flaggeditem': { + 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['auth.User']"}) + }, + 'askbot.markedtag': { + 'Meta': {'object_name': 'MarkedTag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"}) + }, + 'askbot.question': { + 'Meta': {'object_name': 'Question', 'db_table': "u'question'"}, + 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['auth.User']"}), + 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['auth.User']"}), + 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['auth.User']"}), + 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'symmetrical': 'False', 'through': "'FavoriteQuestion'", 'to': "orm['auth.User']"}), + 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'symmetrical': 'False', 'to': "orm['auth.User']"}), + 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['auth.User']"}), + 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['auth.User']"}), + 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_questions'", 'null': 'True', 'to': "orm['auth.User']"}), + 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}), + 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'askbot.questionrevision': { + 'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['askbot.Question']"}), + 'revised_at': ('django.db.models.fields.DateTimeField', [], {}), + 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}), + 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}), + 'text': ('django.db.models.fields.TextField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}) + }, + 'askbot.questionview': { + 'Meta': {'object_name': 'QuestionView'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Question']"}), + 'when': ('django.db.models.fields.DateTimeField', [], {}), + 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"}) + }, + 'askbot.repute': { + 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"}, + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Question']", 'null': 'True', 'blank': 'True'}), + 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}), + 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'askbot.tag': { + 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"}, + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}), + 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + 'askbot.vote': { + 'Meta': {'unique_together': "(('content_type', 'object_id', 'user'),)", 'object_name': 'Vote', 'db_table': "u'vote'"}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}), + 'vote': ('django.db.models.fields.SmallIntegerField', [], {}), + 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}) + }, + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}), + 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}), + 'tag_filter_setting': ('django.db.models.fields.CharField', [], {'default': "'ignored'", 'max_length': '16'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['askbot'] diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index ccac6b2d..4bb1293b 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -24,7 +24,7 @@ from askbot.models.question import FavoriteQuestion from askbot.models.answer import Answer, AnonymousAnswer, AnswerRevision from askbot.models.tag import Tag, MarkedTag from askbot.models.meta import Vote, Comment, FlaggedItem -from askbot.models.user import Activity, EmailFeedSetting +from askbot.models.user import EmailFeedSetting, ActivityAuditStatus, Activity from askbot.models import signals #from user import AuthKeyUserAssociation from askbot.models.repute import Badge, Award, Repute @@ -980,8 +980,9 @@ def user_visit_question(self, question = None, timestamp = None): ACTIVITY_TYPES = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY ACTIVITY_TYPES += (const.TYPE_ACTIVITY_MENTION,) response_activities = Activity.objects.filter( - receiving_users = self, + recipients = self, activity_type__in = ACTIVITY_TYPES, + question = question ) try: question_view = QuestionView.objects.get( @@ -1000,17 +1001,17 @@ def user_visit_question(self, question = None, timestamp = None): #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(self) - self.decrement_response_count() - else: - logging.critical( - 'activity content object has no get_origin_post method' - ) - self.save() + need_to_save_user = False + + audit_records = ActivityAuditStatus.objects.filter( + activity__in = response_activities, + user = self + ) + if len(audit_records) > 0: + self.decrement_response_count(len(audit_records)) + self.save() + #todo: set status to seen and call update + audit_records.delete() def user_is_username_taken(cls,username): try: @@ -1363,14 +1364,16 @@ def user_increment_response_count(user): """ user.response_count += 1 -def user_decrement_response_count(user): +def user_decrement_response_count(user, amount=1): """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 + assert(amount > 0) + if user.response_count >= amount: + user.response_count -= amount else: + user.response_count = 0 logging.critical( 'response count wanted to go below zero' ) @@ -1541,7 +1544,7 @@ def format_instant_notification_email( def send_instant_notifications_about_activity_in_post( update_activity = None, post = None, - receiving_users = None, + recipients = None, ): """ function called when posts are updated @@ -1549,7 +1552,7 @@ def send_instant_notifications_about_activity_in_post( database hits """ - if receiving_users is None: + if recipients is None: return acceptable_types = const.RESPONSE_ACTIVITY_TYPES_FOR_INSTANT_NOTIFICATIONS @@ -1564,7 +1567,7 @@ def send_instant_notifications_about_activity_in_post( update_type = update_type_map[update_activity.activity_type] origin_post = post.get_origin_post() - for user in receiving_users: + for user in recipients: subject_line, body_text = format_instant_notification_email( to_user = user, @@ -1614,7 +1617,8 @@ def record_post_update_activity( user = updated_by, active_at = timestamp, content_object = post, - activity_type = activity_type + activity_type = activity_type, + question = post.get_origin_post() ) update_activity.save() @@ -1622,23 +1626,23 @@ def record_post_update_activity( #for example for question - all Q&A contributors #are included, for comments only authors of comments and parent #post are included - receiving_users = post.get_response_receivers( + recipients = post.get_response_receivers( exclude_list = [updated_by, ] ) - update_activity.receiving_users.add(*receiving_users) + update_activity.add_recipients(recipients) - assert(updated_by not in receiving_users) + assert(updated_by not in recipients) - for user in set(receiving_users) | set(newly_mentioned_users): + for user in set(recipients) | set(newly_mentioned_users): user.increment_response_count() user.save() - #todo: weird thing is that only comments need the receiving_users + #todo: weird thing is that only comments need the recipients #todo: debug these calls and then uncomment in the repo #argument to this call notification_subscribers = post.get_instant_notification_subscribers( - potential_subscribers = receiving_users, + potential_subscribers = recipients, mentioned_users = newly_mentioned_users, exclude_list = [updated_by, ] ) @@ -1646,7 +1650,7 @@ def record_post_update_activity( send_instant_notifications_about_activity_in_post( update_activity = update_activity, post = post, - receiving_users = notification_subscribers, + recipients = notification_subscribers, ) @@ -1665,7 +1669,7 @@ def record_award_event(instance, created, **kwargs): activity_type=const.TYPE_ACTIVITY_PRIZE ) activity.save() - activity.receiving_users.add(instance.user) + activity.add_recipients([instance.user]) instance.badge.awarded_count += 1 instance.badge.save() @@ -1704,13 +1708,14 @@ def record_answer_accepted(instance, created, **kwargs): user=instance.question.author, active_at=datetime.datetime.now(), content_object=instance, - activity_type=const.TYPE_ACTIVITY_MARK_ANSWER + activity_type=const.TYPE_ACTIVITY_MARK_ANSWER, + question=instance.question ) activity.save() - receiving_users = instance.get_author_list( + recipients = instance.get_author_list( exclude_list = [instance.question.author] ) - activity.receiving_users.add(*receiving_users) + activity.add_recipients(recipients) def update_last_seen(instance, created, **kwargs): @@ -1776,7 +1781,8 @@ def record_delete_question(instance, delete_by, **kwargs): user=delete_by, active_at=datetime.datetime.now(), content_object=instance, - activity_type=activity_type + activity_type=activity_type, + question = instance.get_origin_post() ) #no need to set receiving user here activity.save() @@ -1786,13 +1792,14 @@ def record_flag_offensive(instance, mark_by, **kwargs): user=mark_by, active_at=datetime.datetime.now(), content_object=instance, - activity_type=const.TYPE_ACTIVITY_MARK_OFFENSIVE + activity_type=const.TYPE_ACTIVITY_MARK_OFFENSIVE, + question=instance.get_origin_post() ) activity.save() - receiving_users = instance.get_author_list( + recipients = instance.get_author_list( exclude_list = [mark_by] ) - activity.receiving_users.add(*receiving_users) + activity.add_recipients(recipients) def record_update_tags(question, **kwargs): """ @@ -1802,7 +1809,8 @@ def record_update_tags(question, **kwargs): user=question.author, active_at=datetime.datetime.now(), content_object=question, - activity_type=const.TYPE_ACTIVITY_UPDATE_TAGS + activity_type=const.TYPE_ACTIVITY_UPDATE_TAGS, + question = question ) activity.save() @@ -1815,13 +1823,14 @@ def record_favorite_question(instance, created, **kwargs): user=instance.user, active_at=datetime.datetime.now(), content_object=instance, - activity_type=const.TYPE_ACTIVITY_FAVORITE + activity_type=const.TYPE_ACTIVITY_FAVORITE, + question=instance.question ) activity.save() - receiving_users = instance.question.get_author_list( + recipients = instance.question.get_author_list( exclude_list = [instance.user] ) - activity.receiving_users.add(*receiving_users) + activity.add_recipients(recipients) def record_user_full_updated(instance, **kwargs): activity = Activity( @@ -1872,7 +1881,7 @@ django_signals.post_save.connect(record_answer_accepted, sender=Answer) django_signals.post_save.connect(update_last_seen, sender=Activity) django_signals.post_save.connect(record_vote, sender=Vote) django_signals.post_save.connect( - record_favorite_question, + record_favorite_question, sender=FavoriteQuestion ) django_signals.post_delete.connect(record_cancel_vote, sender=Vote) @@ -1923,6 +1932,7 @@ Award = Award Repute = Repute Activity = Activity +ActivityAuditStatus = ActivityAuditStatus EmailFeedSetting = EmailFeedSetting #AuthKeyUserAssociation = AuthKeyUserAssociation @@ -1950,6 +1960,7 @@ __all__ = [ 'Repute', 'Activity', + 'ActivityAuditStatus', 'EmailFeedSetting', #'AuthKeyUserAssociation', diff --git a/askbot/models/answer.py b/askbot/models/answer.py index 634481d9..0cf5ec5c 100644 --- a/askbot/models/answer.py +++ b/askbot/models/answer.py @@ -169,23 +169,23 @@ class Answer(content.Content, DeletableContent): the response """ assert(exclude_list is not None) - receiving_users = set() - receiving_users.update( + recipients = set() + recipients.update( self.get_author_list( include_comments = True ) ) - receiving_users.update( + recipients.update( self.question.get_author_list( include_comments = True ) ) for answer in self.question.answers.all(): - receiving_users.update(answer.get_author_list()) + recipients.update(answer.get_author_list()) - receiving_users -= set(exclude_list) + recipients -= set(exclude_list) - return list(receiving_users) + return list(recipients) def get_user_vote(self, user): if user.is_anonymous(): diff --git a/askbot/models/meta.py b/askbot/models/meta.py index 8fbb651e..248979ae 100644 --- a/askbot/models/meta.py +++ b/askbot/models/meta.py @@ -248,7 +248,7 @@ class Comment(base.MetaContent, base.UserContent): activity_type__in = response_activity_types ) for activity in activities: - for user in activity.receiving_users.all(): + for user in activity.recipients.all(): user.decrement_response_count() user.save() activities.delete() diff --git a/askbot/models/question.py b/askbot/models/question.py index 81116e0d..ba4237c9 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -452,18 +452,18 @@ class Question(content.Content, DeletableContent): author of the update so the he/she is not notified about the update """ assert(exclude_list != None) - receiving_users = set() - receiving_users.update( + recipients = set() + recipients.update( self.get_author_list( include_comments = True ) ) #do not include answer commenters here for a in self.answers.all(): - receiving_users.update(a.get_author_list()) + recipients.update(a.get_author_list()) - receiving_users -= set(exclude_list) - return receiving_users + recipients -= set(exclude_list) + return recipients def retag(self, retagged_by=None, retagged_at=None, tagnames=None): if None in (retagged_by, retagged_at, tagnames): diff --git a/askbot/models/user.py b/askbot/models/user.py index f0a34551..ad302705 100644 --- a/askbot/models/user.py +++ b/askbot/models/user.py @@ -73,13 +73,12 @@ class ActivityManager(models.Manager): kwargs['is_auditted'] = False mention_activity = Activity(**kwargs) + mention_activity.question = mentioned_in.get_origin_post() mention_activity.save() if mentioned_whom: - if functions.is_iterable(mentioned_whom): - raise NotImplementedError('cannot yet mention multiple people at once') - else: - mention_activity.receiving_users.add(mentioned_whom) + assert(isinstance(mentioned_whom, User)) + mention_activity.add_recipients([mentioned_whom]) return mention_activity @@ -111,9 +110,9 @@ class ActivityManager(models.Manager): if mentioned_whom: if functions.is_iterable(mentioned_whom): - kwargs['receiving_users__in'] = mentioned_whom + kwargs['recipients__in'] = mentioned_whom else: - kwargs['receiving_users__in'] = (mentioned_whom,) + kwargs['recipients__in'] = (mentioned_whom,) if mentioned_in: if functions.is_iterable(mentioned_in): @@ -132,17 +131,38 @@ class ActivityManager(models.Manager): return self.filter(**kwargs) +class ActivityAuditStatus(models.Model): + """bridge "through" relation between activity and users""" + STATUS_NEW = 0 + STATUS_SEEN = 1 + STATUS_CHOICES = ( + (STATUS_NEW, 'new'), + (STATUS_SEEN, 'seen') + ) + user = models.ForeignKey(User) + activity = models.ForeignKey('Activity') + status = models.SmallIntegerField(choices=STATUS_CHOICES, default=STATUS_NEW) + + class Meta: + unique_together = ('user', 'activity') + app_label = 'askbot' + db_table = 'askbot_activityauditstatus' + + class Activity(models.Model): """ We keep some history data for user activities """ user = models.ForeignKey(User) receiving_users = models.ManyToManyField(User, related_name='received_activity') + recipients = models.ManyToManyField(User, through=ActivityAuditStatus, related_name='incoming_activity') activity_type = models.SmallIntegerField(choices = const.TYPE_ACTIVITY) active_at = models.DateTimeField(default=datetime.datetime.now) content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') + #todo: remove this denorm question field when Post model is set up + question = models.ForeignKey('Question', null=True) is_auditted = models.BooleanField(default=False) objects = ActivityManager() @@ -155,9 +175,18 @@ class Activity(models.Model): app_label = 'askbot' db_table = u'activity' + def add_recipients(self, recipients): + """have to use a special method, because django does not allow + auto-adding to M2M with "through" model + """ + for recipient in recipients: + #todo: may optimize for bulk addition + aas = ActivityAuditStatus(user = recipient, activity = self) + aas.save() + def get_mentioned_user(self): assert(self.activity_type == const.TYPE_ACTIVITY_MENTION) - user_qs = self.receiving_users.all() + user_qs = self.recipients.all() user_count = len(user_qs) if user_count == 0: return None diff --git a/askbot/tests/on_screen_notification_tests.py b/askbot/tests/on_screen_notification_tests.py index ea607810..68e51d33 100644 --- a/askbot/tests/on_screen_notification_tests.py +++ b/askbot/tests/on_screen_notification_tests.py @@ -89,6 +89,13 @@ class OnScreenUpdateNotificationTests(TestCase): self.reload_users() #pre-populate askbot with some content + #create a question and two answers, each post gets two comments + #users have two digit codes. What users do in the setup code + #is explained below (x is a variable that takes integer values of [1-3]) + #user x1 makes a post, users x2 and x3 add comments to that post + #users 1x work on question, 2x and 3x on the answers + #users x4 do not do anyting in the setup code + self.question = models.Question.objects.create_new( title = 'test question', author = self.u11, @@ -134,6 +141,27 @@ class OnScreenUpdateNotificationTests(TestCase): comment = 'comment33' ) + def assertResponseCountsEqual(self, counts_vector): + self.reload_users() + self.assertEquals( + [ + 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, + ], + counts_vector + ) + + def post_then_delete_answer_comment(self): pass @@ -167,22 +195,7 @@ class OnScreenUpdateNotificationTests(TestCase): 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, - ], + self.assertResponseCountsEqual( [ 0, 0, 0, 0, 0, 0, 0, 0, @@ -200,22 +213,7 @@ class OnScreenUpdateNotificationTests(TestCase): 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, - ], + self.assertResponseCountsEqual( [ 0, 0, 0, 0, 0, 0, 0, 0, @@ -235,25 +233,10 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set([self.u12, self.u13]), ) - 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, - ], + self.assertResponseCountsEqual( [ 0, 1, 1, 0, 0, 0, 0, 0, @@ -271,25 +254,10 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set([self.u22, self.u23]), ) - 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, - ], + self.assertResponseCountsEqual( [ 0, 0, 0, 0, 0, 1, 1, 0, @@ -309,25 +277,10 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set([self.u12, self.u13]), ) - 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, - ], + self.assertResponseCountsEqual( [ 0, 1, 1, 0, 0, 0, 0, 0, @@ -347,25 +300,10 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set([self.u12, self.u13]), ) - 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, - ], + self.assertResponseCountsEqual( [ 0, 1, 1, 0, 0, 0, 0, 0, @@ -385,25 +323,10 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set([self.u22, self.u23]), ) - 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, - ], + self.assertResponseCountsEqual( [ 0, 0, 0, 0, 0, 1, 1, 0, @@ -411,6 +334,52 @@ class OnScreenUpdateNotificationTests(TestCase): ] ) + def test_responses_clear_after_visit(self): + """user 14 posts comment under question + user 11, 12, 21, and 22 visit the question + user 13 does not + the expected outcome is that 11 and 12 have + 0 responses and 13 still has one + remaining users still have notifications + """ + self.reset_response_counts() + time.sleep(1) + timestamp = datetime.datetime.now() + self.question.add_comment( + user = self.u14, + comment = 'dudududududu', + added_at = timestamp + ) + notifications = get_re_notif_after(timestamp) + self.assertEqual(len(notifications), 1) + self.assertEqual( + set(notifications[0].recipients.all()), + set([self.u11, self.u12, self.u13])#all users are notified + ) + self.assertResponseCountsEqual( + [ + 1, 1, 1, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + ] + ) + self.u11.visit_question(self.question) + self.u12.visit_question(self.question) + notifications = get_re_notif_after(timestamp) + self.assertEqual(len(notifications), 1) + self.assertEqual(#visitors are not notified + set(notifications[0].recipients.all()), + set([self.u13]) + ) + self.assertResponseCountsEqual( + [ + 0, 0, 1, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + ] + ) + + def test_comments_to_post_authors(self): self.question.apply_edit( edited_by = self.u14, @@ -428,25 +397,10 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set([self.u11, self.u13, self.u14]), ) - 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, - ], + self.assertResponseCountsEqual( [ 1, 0, 1, 1, 0, 0, 0, 0, @@ -469,25 +423,10 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set([self.u21, self.u23, self.u24]), ) - 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, - ], + self.assertResponseCountsEqual( [ 0, 0, 0, 0, 1, 0, 1, 1, @@ -511,25 +450,10 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set([self.u11, self.u12, self.u13, self.u21, self.u31]) ) - 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, - ], + self.assertResponseCountsEqual( [ 1, 1, 1, 0, 1, 0, 0, 0, @@ -547,25 +471,10 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set([self.u11, self.u12, self.u13, self.u14, self.u21]) ) - 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, - ], + self.assertResponseCountsEqual( [ 1, 1, 1, 1, 1, 0, 0, 0, @@ -587,7 +496,7 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set( [ self.u11, self.u12, self.u13, @@ -596,22 +505,7 @@ class OnScreenUpdateNotificationTests(TestCase): ] ) ) - 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, - ], + self.assertResponseCountsEqual( [ 1, 1, 1, 0, 1, 1, 1, 0, @@ -633,7 +527,7 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set( [ self.u12, self.u13, @@ -641,22 +535,7 @@ class OnScreenUpdateNotificationTests(TestCase): ] ) ) - 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, - ], + self.assertResponseCountsEqual( [ 0, 1, 1, 0, 1, 0, 0, 0, @@ -675,7 +554,7 @@ class OnScreenUpdateNotificationTests(TestCase): notifications = get_re_notif_after(timestamp) self.assertEqual(len(notifications), 1) self.assertEqual( - set(notifications[0].receiving_users.all()), + set(notifications[0].recipients.all()), set( [ self.u11, self.u12, self.u13, @@ -683,22 +562,7 @@ class OnScreenUpdateNotificationTests(TestCase): ] ) ) - 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, - ], + self.assertResponseCountsEqual( [ 1, 1, 1, 0, 1, 0, 0, 0, diff --git a/askbot/views/users.py b/askbot/views/users.py index 32a2bdcb..0db51705 100644 --- a/askbot/views/users.py +++ b/askbot/views/users.py @@ -704,9 +704,7 @@ def user_responses(request, user): response_list = [] activities = list() - activities = models.Activity.responses_and_mentions.filter( - receiving_users = user - ) + activities = models.Activity.responses_and_mentions.filter(recipients=user) for act in activities: origin_post = act.content_object.get_origin_post() -- cgit v1.2.3-1-g7c22