summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-08-08 10:11:58 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-08-08 10:11:58 -0400
commit4b543178037de42717690b11fdf9fbb7f88d1510 (patch)
tree8ae3f8a2a3f6197eeff483f537976d3bd7c45c7d
parent922c704bee7c79d85eefdf8538edd7e17d02f137 (diff)
downloadaskbot-4b543178037de42717690b11fdf9fbb7f88d1510.tar.gz
askbot-4b543178037de42717690b11fdf9fbb7f88d1510.tar.bz2
askbot-4b543178037de42717690b11fdf9fbb7f88d1510.zip
allow people sharing questions with "foreign" groups
-rw-r--r--askbot/migrations/0134_create_personal_groups_for_all_users.py378
-rw-r--r--askbot/models/__init__.py29
-rw-r--r--askbot/models/post.py1
-rw-r--r--askbot/models/question.py6
-rw-r--r--askbot/models/tag.py5
-rw-r--r--askbot/skins/common/media/js/post.js2
-rw-r--r--askbot/skins/common/media/js/user.js2
-rw-r--r--askbot/tests/__init__.py1
-rw-r--r--askbot/tests/db_api_tests.py26
-rw-r--r--askbot/tests/user_model_tests.py21
-rw-r--r--askbot/views/commands.py2
-rw-r--r--askbot/views/users.py3
12 files changed, 458 insertions, 18 deletions
diff --git a/askbot/migrations/0134_create_personal_groups_for_all_users.py b/askbot/migrations/0134_create_personal_groups_for_all_users.py
new file mode 100644
index 00000000..e1c45ec1
--- /dev/null
+++ b/askbot/migrations/0134_create_personal_groups_for_all_users.py
@@ -0,0 +1,378 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from askbot.utils.console import ProgressBar
+
+def format_group_name(user):
+ """returns name of the personal group
+ given the user object
+ """
+ return '_internal_%s_%d' % (user.username, user.id)
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ message = 'Creating personal group for the users'
+ users = orm['auth.User'].objects.all()
+ for user in ProgressBar(users.iterator(), users.count(), message):
+ group_name = format_group_name(user)
+ group_tag = orm['askbot.Tag'](name=group_name, created_by=user)
+ group_tag.save()
+ group_profile = orm['askbot.GroupProfile'](
+ group_tag=group_tag, is_open=False
+ )
+ group_profile.save()
+ membership = orm['askbot.GroupMembership'](group=group_tag, user=user)
+ membership.save()
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ for user in orm['auth.User'].objects.iterator():
+ group_name = format_group_name(user)
+
+ memberships = orm['askbot.GroupMembership'].objects.filter(
+ user=user,
+ group__name=group_name
+ )
+ memberships.delete()
+
+ group_profiles = orm['askbot.GroupProfile'].objects.filter(
+ group_tag__name=group_name
+ )
+ group_profiles.delete()
+
+ orm['askbot.Tag'].objects.filter(name=group_name).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'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", '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': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ '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.Post']"}),
+ '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'})
+ },
+ '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'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'})
+ },
+ '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.BadgeData']"}),
+ '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'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", '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'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ '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.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': '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_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ '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'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ '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', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'tag'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']"})
+ },
+ '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.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'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.Post']", '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': {'ordering': "('-used_count', 'name')", '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'}),
+ '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'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.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_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ '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': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ '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'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ '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': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", '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'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ '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'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ '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'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ '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': {'ordering': "('name',)", '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']
+ symmetrical = True
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index ac610506..395a5c8e 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -34,6 +34,7 @@ from askbot.models.tag import Tag, MarkedTag
from askbot.models.tag import get_global_group
from askbot.models.tag import get_group_names
from askbot.models.tag import get_groups
+from askbot.models.tag import format_personal_group_name
from askbot.models.user import EmailFeedSetting, ActivityAuditStatus, Activity
from askbot.models.user import GroupMembership, GroupProfile
from askbot.models.post import Post, PostRevision
@@ -1166,6 +1167,7 @@ def user_post_comment(
added_at = timestamp,
by_email = by_email
)
+ comment.add_to_groups([self.get_personal_group()])
parent_post.thread.invalidate_cached_data()
award_badges_signal.send(
@@ -1820,6 +1822,7 @@ def user_post_answer(
is_private = is_private,
by_email = by_email
)
+ answer_post.add_to_groups([self.get_personal_group()])
answer_post.thread.invalidate_cached_data()
award_badges_signal.send(None,
@@ -2197,6 +2200,10 @@ def user_get_groups(self, private=False):
#todo: maybe cache this query
return Tag.group_tags.get_for_user(self, private=private)
+def user_get_personal_group(self):
+ group_name = format_personal_group_name(self)
+ return Tag.group_tags.get(name=group_name)
+
def user_get_foreign_groups(self):
"""returns a query set of groups to which user does not belong"""
#todo: maybe cache this query
@@ -2634,6 +2641,7 @@ User.add_to_class('get_marked_tags', user_get_marked_tags)
User.add_to_class('get_marked_tag_names', user_get_marked_tag_names)
User.add_to_class('get_groups', user_get_groups)
User.add_to_class('get_foreign_groups', user_get_foreign_groups)
+User.add_to_class('get_personal_group', user_get_personal_group)
User.add_to_class('strip_email_signature', user_strip_email_signature)
User.add_to_class('get_groups_membership_info', user_get_groups_membership_info)
User.add_to_class('get_anonymous_name', user_get_anonymous_name)
@@ -3327,6 +3335,24 @@ def add_user_to_global_group(sender, instance, created, **kwargs):
)
+def add_user_to_personal_group(sender, instance, created, **kwargs):
+ """auto-joins user to his/her personal group
+ ``instance`` is an instance of ``User`` class
+ """
+ if created:
+ #todo: groups will indeed need to be separated from tags
+ #so that we can use less complicated naming scheme
+ #in theore here we may have two users that will have
+ #identical group names!!!
+ group_name = format_personal_group_name(instance)
+ group = Tag.group_tags.get_or_create(
+ group_name=group_name, user=instance
+ )
+ instance.edit_group_membership(
+ group=group, user=instance, action='add'
+ )
+
+
def greet_new_user(user, **kwargs):
"""sends welcome email to the newly created user
@@ -3419,6 +3445,7 @@ django_signals.pre_save.connect(make_admin_if_first_user, sender=User)
django_signals.pre_save.connect(calculate_gravatar_hash, sender=User)
django_signals.post_save.connect(add_missing_subscriptions, sender=User)
django_signals.post_save.connect(add_user_to_global_group, sender=User)
+django_signals.post_save.connect(add_user_to_personal_group, sender=User)
django_signals.post_save.connect(record_award_event, sender=Award)
django_signals.post_save.connect(notify_award_message, sender=Award)
django_signals.post_save.connect(record_answer_accepted, sender=Post)
@@ -3494,5 +3521,5 @@ __all__ = [
'get_model',
'get_admins_and_moderators',
'get_group_names',
- 'get_grous'
+ 'get_groups'
]
diff --git a/askbot/models/post.py b/askbot/models/post.py
index 8b27fa5f..e72ff5e4 100644
--- a/askbot/models/post.py
+++ b/askbot/models/post.py
@@ -502,7 +502,6 @@ class Post(models.Model):
#because generic relation needs primary key of the related object
super(self.__class__, self).save(**kwargs)
-
if self.is_comment():
#copy groups from the parent post into the comment
groups = self.parent.groups.all()
diff --git a/askbot/models/question.py b/askbot/models/question.py
index 98353d27..89ef76b6 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -40,7 +40,7 @@ class ThreadQuerySet(models.query.QuerySet):
groups = user.get_groups()
else:
groups = [get_global_group()]
- return self.filter(groups__in=groups)
+ return self.filter(groups__in=groups).distinct()
class ThreadManager(BaseQuerySetManager):
@@ -144,6 +144,10 @@ class ThreadManager(BaseQuerySetManager):
email_address=email_address
)
+ author_group = author.get_personal_group()
+ thread.add_to_groups([author_group])
+ question.add_to_groups([author_group])
+
if is_private or group_id:#add groups to thread and question
thread.make_private(author, group_id=group_id)
else:
diff --git a/askbot/models/tag.py b/askbot/models/tag.py
index b0fd9aac..7f5126c8 100644
--- a/askbot/models/tag.py
+++ b/askbot/models/tag.py
@@ -60,6 +60,11 @@ def filter_accepted_tags(tags):
def filter_suggested_tags(tags):
return filter_tags_by_status(tags, status = Tag.STATUS_SUGGESTED)
+def format_personal_group_name(user):
+ #todo: after migration of groups away from tags,
+ #this function will be moved somewhere else
+ return '_internal_%s_%d' % (user.username, user.id)
+
def is_preapproved_tag_name(tag_name):
"""true if tag name is in the category tree
or any other container of preapproved tags"""
diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js
index 88f16e08..c427334c 100644
--- a/askbot/skins/common/media/js/post.js
+++ b/askbot/skins/common/media/js/post.js
@@ -3847,7 +3847,7 @@ $(document).ready(function() {
url: askbot['urls']['getGroupsList'],
preloadData: true,
minChars: 1,
- useCache: true,
+ useCache: false,
matchInside: true,
maxCacheLength: 100,
delay: 10
diff --git a/askbot/skins/common/media/js/user.js b/askbot/skins/common/media/js/user.js
index e858257d..4795b7d2 100644
--- a/askbot/skins/common/media/js/user.js
+++ b/askbot/skins/common/media/js/user.js
@@ -934,7 +934,7 @@ GroupAdderWidget.prototype.decorate = function(element){
url: askbot['urls']['getGroupsList'],
preloadData: true,
minChars: 1,
- useCache: true,
+ useCache: false,
matchInside: false,
maxCacheLength: 100,
delay: 10
diff --git a/askbot/tests/__init__.py b/askbot/tests/__init__.py
index c20b7f67..905c90df 100644
--- a/askbot/tests/__init__.py
+++ b/askbot/tests/__init__.py
@@ -16,3 +16,4 @@ from askbot.tests.post_model_tests import *
from askbot.tests.thread_model_tests import *
from askbot.tests.reply_by_email_tests import *
from askbot.tests.category_tree_tests import CategoryTreeTests
+from askbot.tests.user_model_tests import UserModelTests
diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py
index c1663835..07590487 100644
--- a/askbot/tests/db_api_tests.py
+++ b/askbot/tests/db_api_tests.py
@@ -454,19 +454,19 @@ class TagAndGroupTests(AskbotTestCase):
self.u1.join_group(group)
q = self.post_question(user=self.u1, is_private=True)
- self.assertEqual(q.groups.count(), 1)
+ self.assertEqual(q.groups.count(), 2)
self.assertEqual(q.groups.filter(name='private').exists(), True)
a = self.post_answer(question=q, user=self.u1, is_private=True)
- self.assertEqual(a.groups.count(), 1)
+ self.assertEqual(a.groups.count(), 2)
self.assertEqual(a.groups.filter(name='private').exists(), True)
qc = self.post_comment(parent_post=q, user=self.u1)#w/o private arg
- self.assertEqual(qc.groups.count(), 1)
+ self.assertEqual(qc.groups.count(), 2)
self.assertEqual(qc.groups.filter(name='private').exists(), True)
qa = self.post_comment(parent_post=a, user=self.u1)#w/o private arg
- self.assertEqual(qa.groups.count(), 1)
+ self.assertEqual(qa.groups.count(), 2)
self.assertEqual(qa.groups.filter(name='private').exists(), True)
def test_global_group_name_setting_changes_group_name(self):
@@ -477,7 +477,7 @@ class TagAndGroupTests(AskbotTestCase):
def test_ask_global_group_by_id_works(self):
group = get_global_group()
q = self.post_question(user=self.u1, group_id=group.id)
- self.assertEqual(q.groups.count(), 1)
+ self.assertEqual(q.groups.count(), 2)
self.assertEqual(q.groups.filter(name=group.name).exists(), True)
def test_making_public_question_private_works(self):
@@ -486,10 +486,10 @@ class TagAndGroupTests(AskbotTestCase):
group = self.create_group(group_name='private', user=self.u1)
self.u1.join_group(group)
self.edit_question(question=question, user=self.u1, is_private=True)
- self.assertEqual(question.groups.count(), 1)
+ self.assertEqual(question.groups.count(), 2)
self.assertEqual(question.groups.filter(id=group.id).count(), 1)
#comment inherits sharing scope
- self.assertEqual(comment.groups.count(), 1)
+ self.assertEqual(comment.groups.count(), 2)
self.assertEqual(comment.groups.filter(id=group.id).count(), 1)
def test_making_public_answer_private_works(self):
@@ -499,10 +499,10 @@ class TagAndGroupTests(AskbotTestCase):
group = self.create_group(group_name='private', user=self.u1)
self.u1.join_group(group)
self.edit_answer(user=self.u1, answer=answer, is_private=True)
- self.assertEqual(answer.groups.count(), 1)
+ self.assertEqual(answer.groups.count(), 2)
self.assertEqual(answer.groups.filter(id=group.id).count(), 1)
#comment inherits the sharing scope
- self.assertEqual(comment.groups.count(), 1)
+ self.assertEqual(comment.groups.count(), 2)
self.assertEqual(comment.groups.filter(id=group.id).count(), 1)
def test_public_question_private_answer_works(self):
@@ -532,7 +532,7 @@ class TagAndGroupTests(AskbotTestCase):
self.u1.join_group(group)
answer = self.post_answer(question=question, user=self.u1)
answer.add_to_groups((group,))
- self.assertEqual(answer.groups.count(), 2)
+ self.assertEqual(answer.groups.count(), 3)
self.assertEqual(answer.thread.posts.get_answers(self.u1).count(), 1)
def test_thread_make_public_recursive(self):
@@ -540,7 +540,7 @@ class TagAndGroupTests(AskbotTestCase):
self.u1.join_group(private_group)
data = self.post_question_answer_and_comments(is_private=True)
- groups = [private_group]
+ groups = [private_group, self.u1.get_personal_group()]
self.assertObjectGroupsEqual(data['thread'], groups)
self.assertObjectGroupsEqual(data['question'], groups)
self.assertObjectGroupsEqual(data['question_comment'], groups)
@@ -550,7 +550,7 @@ class TagAndGroupTests(AskbotTestCase):
data['thread'].make_public(recursive=True)
global_group = get_global_group()
- groups = [global_group, private_group]
+ groups = [global_group, private_group, self.u1.get_personal_group()]
self.assertObjectGroupsEqual(data['thread'], groups)
self.assertObjectGroupsEqual(data['question'], groups)
self.assertObjectGroupsEqual(data['question_comment'], groups)
@@ -565,7 +565,7 @@ class TagAndGroupTests(AskbotTestCase):
thread.add_to_groups([private_group], recursive=True)
global_group = get_global_group()
- groups = [global_group, private_group]
+ groups = [global_group, private_group, self.u1.get_personal_group()]
self.assertObjectGroupsEqual(thread, groups)
self.assertObjectGroupsEqual(data['question'], groups)
self.assertObjectGroupsEqual(data['question_comment'], groups)
diff --git a/askbot/tests/user_model_tests.py b/askbot/tests/user_model_tests.py
new file mode 100644
index 00000000..7a8fd9f2
--- /dev/null
+++ b/askbot/tests/user_model_tests.py
@@ -0,0 +1,21 @@
+from askbot.tests.utils import AskbotTestCase
+from django.contrib.auth.models import User
+from askbot import models
+from askbot.models.tag import format_personal_group_name
+
+class UserModelTests(AskbotTestCase):
+ """test user model"""
+
+ def test_new_user_has_personal_group(self):
+ user = User.objects.create_user('somebody', 'somebody@example.com')
+ group_name = format_personal_group_name(user)
+ group = models.Tag.objects.filter(name=group_name)
+ self.assertEqual(group.count(), 1)
+
+ group_profile = models.GroupProfile.objects.filter(group_tag=group)
+ self.assertEqual(group_profile.count(), 1)
+
+ memberships = models.GroupMembership.objects.filter(
+ group=group, user=user
+ )
+ self.assertEqual(memberships.count(), 1)
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index 64bf8d37..4a5c2682 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -620,6 +620,8 @@ def get_groups_list(request):
deleted = False
).exclude(
name=global_group.name
+ ).exclude(
+ name__startswith='_internal_'
).values_list(
'name', flat = True
)
diff --git a/askbot/views/users.py b/askbot/views/users.py
index 5fb581b8..c0a3a295 100644
--- a/askbot/views/users.py
+++ b/askbot/views/users.py
@@ -443,6 +443,7 @@ def user_stats(request, user, context):
badges.sort(key=operator.itemgetter(1), reverse=True)
user_groups = models.Tag.group_tags.get_for_user(user = user)
+ user_groups = user_groups.exclude(name__startswith='_internal_')
global_group = get_global_group()
user_groups = user_groups.exclude(name=global_group.name)
@@ -996,6 +997,8 @@ def groups(request, id = None, slug = None):
user = request.user
)
+ groups = groups.exclude(name__startswith='_internal_')
+
groups = groups.select_related('group_profile')
user_can_add_groups = request.user.is_authenticated() and \