]> git.openstreetmap.org Git - osqa.git/commitdiff
ALteration of the schema to a single content model. As a bonus there is a complete...
authorhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Thu, 15 Apr 2010 22:54:00 +0000 (22:54 +0000)
committerhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Thu, 15 Apr 2010 22:54:00 +0000 (22:54 +0000)
git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@34 0cfe37f9-358a-4d5e-be75-b63607b5c754

69 files changed:
.gitignore
forum/activity.py
forum/forms.py
forum/migrations/0006_auto__add_node__add_field_vote_node__add_field_comment_node__add_field.py [new file with mode: 0644]
forum/migrations/0007_q_and_a_to_node.py [new file with mode: 0644]
forum/migrations/0008_auto__add_noderevision__del_field_vote_object_id__del_field_vote_conte.py [new file with mode: 0644]
forum/migrations/0009_convert_revisions.py [new file with mode: 0644]
forum/migrations/0010_auto__del_questionrevision__del_answerrevision__del_field_answer_vote_.py [new file with mode: 0644]
forum/migrations/0011_auto__add_field_node_active_revision.py [new file with mode: 0644]
forum/migrations/0012_set_active_revision.py [new file with mode: 0644]
forum/migrations/0013_auto__del_anonymousquestion__del_anonymousanswer__add_anonymousnode.py [new file with mode: 0644]
forum/migrations/__init__.py
forum/models/__init__.py
forum/models/answer.py
forum/models/base.py
forum/models/meta.py
forum/models/node.py [new file with mode: 0644]
forum/models/question.py
forum/models/repute.py
forum/models/user.py
forum/skins/default/media/js/osqa.main.js
forum/skins/default/templates/about.html
forum/skins/default/templates/base.html
forum/skins/default/templates/node/accept_button.html [moved from forum/skins/default/templates/question/accept_button.html with 100% similarity]
forum/skins/default/templates/node/comments.html [moved from forum/skins/default/templates/question/comments.html with 85% similarity]
forum/skins/default/templates/node/favorite_mark.html [moved from forum/skins/default/templates/question/favorite_mark.html with 100% similarity]
forum/skins/default/templates/node/post_controls.html [moved from forum/skins/default/templates/question/post_controls.html with 100% similarity]
forum/skins/default/templates/node/revision.html [new file with mode: 0644]
forum/skins/default/templates/node/vote_buttons.html [new file with mode: 0644]
forum/skins/default/templates/osqaadmin/index.html
forum/skins/default/templates/question.html
forum/skins/default/templates/question/vote_buttons.html [deleted file]
forum/skins/default/templates/question_list/item.html
forum/skins/default/templates/revisions_question.html
forum/skins/default/templates/user.html
forum/skins/default/templates/user_email_subscriptions.html [deleted file]
forum/skins/default/templates/user_favorites.html [deleted file]
forum/skins/default/templates/user_recent.html [deleted file]
forum/skins/default/templates/user_tabs.html [deleted file]
forum/skins/default/templates/users/activity.html [new file with mode: 0644]
forum/skins/default/templates/users/edit.html [moved from forum/skins/default/templates/user_edit.html with 100% similarity]
forum/skins/default/templates/users/footer.html [moved from forum/skins/default/templates/user_footer.html with 100% similarity]
forum/skins/default/templates/users/info.html [moved from forum/skins/default/templates/user_info.html with 100% similarity]
forum/skins/default/templates/users/questions.html [new file with mode: 0644]
forum/skins/default/templates/users/recent.html [new file with mode: 0644]
forum/skins/default/templates/users/reputation.html [moved from forum/skins/default/templates/user_reputation.html with 100% similarity]
forum/skins/default/templates/users/responses.html [moved from forum/skins/default/templates/user_responses.html with 100% similarity]
forum/skins/default/templates/users/stats.html [moved from forum/skins/default/templates/user_stats.html with 100% similarity]
forum/skins/default/templates/users/subscriptions.html [moved from forum/skins/default/templates/user_subscriptions.html with 100% similarity]
forum/skins/default/templates/users/tabs.html [new file with mode: 0644]
forum/skins/default/templates/users/users.html [moved from forum/skins/default/templates/users.html with 100% similarity]
forum/skins/default/templates/users/votes.html [moved from forum/skins/default/templates/user_votes.html with 73% similarity]
forum/skins/default/templates/users_questions.html [deleted file]
forum/subscriptions.py
forum/templatetags/extra_tags.py
forum/templatetags/node_tags.py [moved from forum/templatetags/question_page_tags.py with 87% similarity]
forum/templatetags/question_list_tags.py
forum/templatetags/user_tags.py
forum/urls.py
forum/utils/cache.py [deleted file]
forum/utils/odict.py [deleted file]
forum/views/README [deleted file]
forum/views/commands.py
forum/views/decorators.py
forum/views/meta.py
forum/views/readers.py
forum/views/users.py
forum/views/writers.py
settings.py

index a424d31bc11ccd2511fb63da2f005c7bdd4bf82d..8c50942e95c2c01ed243bf81e93ec630e8024738 100644 (file)
@@ -13,3 +13,4 @@ pip-log.txt
 *.zip
 tmp/*
 forum/upfiles/[^R]*
+.svn
index 9c27e12fd9ea90dfdc89af14a68f7dd240722126..1f2d7f081b3afb415108cc64aab5a3e30f743fa7 100644 (file)
@@ -31,20 +31,13 @@ def record_comment_event(instance, created, **kwargs):
 post_save.connect(record_comment_event, sender=Comment)\r
 \r
 \r
-def record_question_revision_event(instance, created, **kwargs):\r
-    if created and instance.revision <> 1:\r
-        activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_QUESTION)\r
+def record_revision_event(instance, created, **kwargs):\r
+    if created and instance.revision <> 1 and instance.node.node_type in ('question', 'answer',):\r
+        activity_type = instance.node == 'question' and TYPE_ACTIVITY_UPDATE_QUESTION or TYPE_ACTIVITY_UPDATE_ANSWER\r
+        activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=activity_type)\r
         activity.save()\r
 \r
-post_save.connect(record_question_revision_event, sender=QuestionRevision)\r
-\r
-\r
-def record_answer_revision_event(instance, created, **kwargs):\r
-    if created and instance.revision <> 1:\r
-        activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_ANSWER)\r
-        activity.save()\r
-\r
-post_save.connect(record_answer_revision_event, sender=AnswerRevision)\r
+post_save.connect(record_revision_event, sender=NodeRevision)\r
 \r
 \r
 def record_award_event(instance, created, **kwargs):\r
index a78f20702a3841937190cff0f251326b975e2f67..93a4d15b9c586f1bea71975c66687db0b8cb6b4d 100644 (file)
@@ -126,27 +126,16 @@ class AskForm(forms.Form):
     tags   = TagNamesField()
     wiki = WikiField()
 
-    openid = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 40, 'class':'openid-input'}))
-    user   = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
-    email  = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
 
 class AnswerForm(forms.Form):
     text   = EditorField()
     wiki   = WikiField()
-    openid = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 40, 'class':'openid-input'}))
-    user   = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
-    email  = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
-    email_notify = EmailNotifyField()
-    def __init__(self, question, user, *args, **kwargs):
+
+    def __init__(self, question, *args, **kwargs):
         super(AnswerForm, self).__init__(*args, **kwargs)
-        self.fields['email_notify'].widget.attrs['id'] = 'question-subscribe-updates';
+
         if question.wiki and settings.WIKI_ON:
             self.fields['wiki'].initial = True
-        if user.is_authenticated():
-            if user in question.followed_by.all():
-                self.fields['email_notify'].initial = True
-                return
-        self.fields['email_notify'].initial = False
 
 
 class CloseForm(forms.Form):
@@ -165,15 +154,17 @@ class RevisionForm(forms.Form):
     """
     revision = forms.ChoiceField(widget=forms.Select(attrs={'style' : 'width:520px'}))
 
-    def __init__(self, post, latest_revision, *args, **kwargs):
+    def __init__(self, post, *args, **kwargs):
         super(RevisionForm, self).__init__(*args, **kwargs)
+
         revisions = post.revisions.all().values_list(
             'revision', 'author__username', 'revised_at', 'summary')
         date_format = '%c'
         self.fields['revision'].choices = [
             (r[0], u'%s - %s (%s) %s' % (r[0], r[1], r[2].strftime(date_format), r[3]))
             for r in revisions]
-        self.fields['revision'].initial = latest_revision.revision
+
+        self.fields['revision'].initial = post.active_revision.revision
 
 class EditQuestionForm(forms.Form):
     title  = TitleField()
@@ -181,11 +172,16 @@ class EditQuestionForm(forms.Form):
     tags   = TagNamesField()
     summary = SummaryField()
 
-    def __init__(self, question, revision, *args, **kwargs):
+    def __init__(self, question, revision=None, *args, **kwargs):
         super(EditQuestionForm, self).__init__(*args, **kwargs)
+
+        if revision is None:
+            revision = question.active_revision
+
         self.fields['title'].initial = revision.title
-        self.fields['text'].initial = revision.text
+        self.fields['text'].initial = revision.body
         self.fields['tags'].initial = revision.tagnames
+            
         # Once wiki mode is enabled, it can't be disabled
         if not question.wiki:
             self.fields['wiki'] = WikiField()
@@ -194,9 +190,13 @@ class EditAnswerForm(forms.Form):
     text = EditorField()
     summary = SummaryField()
 
-    def __init__(self, answer, revision, *args, **kwargs):
+    def __init__(self, answer, revision=None, *args, **kwargs):
         super(EditAnswerForm, self).__init__(*args, **kwargs)
-        self.fields['text'].initial = revision.text
+
+        if revision is None:
+            revision = answer.active_revision
+
+        self.fields['text'].initial = revision.body
 
 class EditUserForm(forms.Form):
     email = forms.EmailField(label=u'Email', help_text=_('this email does not have to be linked to gravatar'), required=True, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
diff --git a/forum/migrations/0006_auto__add_node__add_field_vote_node__add_field_comment_node__add_field.py b/forum/migrations/0006_auto__add_node__add_field_vote_node__add_field_comment_node__add_field.py
new file mode 100644 (file)
index 0000000..bee4368
--- /dev/null
@@ -0,0 +1,433 @@
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+    \r
+    def forwards(self, orm):\r
+        \r
+        # Adding model 'Node'\r
+        db.create_table('forum_node', (\r
+            ('body', self.gf('django.db.models.fields.TextField')()),\r
+            ('vote_up_count', self.gf('django.db.models.fields.IntegerField')(default=0)),\r
+            ('parent', self.gf('django.db.models.fields.related.ForeignKey')(related_name='childs', null=True, to=orm['forum.Node'])),\r
+            ('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='nodes', to=orm['forum.User'])),\r
+            ('deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+            ('title', self.gf('django.db.models.fields.CharField')(max_length=300)),\r
+            ('comment_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),\r
+            ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+            ('deleted_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='deleted_nodes', null=True, to=orm['forum.User'])),\r
+            ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=125)),\r
+            ('node_type', self.gf('django.db.models.fields.CharField')(default='node', max_length=16)),\r
+            ('score', self.gf('django.db.models.fields.IntegerField')(default=0)),\r
+            ('vote_down_count', self.gf('django.db.models.fields.IntegerField')(default=0)),\r
+            ('offensive_flag_count', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),\r
+            ('last_edited_by', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='last_edited_nodes', null=True, to=orm['forum.User'])),\r
+            ('deleted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),\r
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+            ('last_edited_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),\r
+        ))\r
+        db.send_create_signal('forum', ['Node'])\r
+\r
+        # Adding M2M table for field tags on 'Node'\r
+        db.create_table('forum_node_tags', (\r
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),\r
+            ('node', models.ForeignKey(orm['forum.node'], null=False)),\r
+            ('tag', models.ForeignKey(orm['forum.tag'], null=False))\r
+        ))\r
+        db.create_unique('forum_node_tags', ['node_id', 'tag_id'])\r
+\r
+        # Adding field 'Vote.node'\r
+        db.add_column(u'vote', 'node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='votes', null=True, to=orm['forum.Node']), keep_default=False)\r
+\r
+        # Adding field 'Comment.node'\r
+        db.add_column(u'comment', 'node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='comments', null=True, to=orm['forum.Node']), keep_default=False)\r
+\r
+        # Adding field 'Answer.node_ptr'\r
+        db.add_column(u'answer', 'node_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True, null=True), keep_default=False)\r
+\r
+        # Adding field 'FlaggedItem.node'\r
+        db.add_column(u'flagged_item', 'node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='flaggeditems', null=True, to=orm['forum.Node']), keep_default=False)\r
+\r
+        # Adding field 'Question.node_ptr'\r
+        db.add_column(u'question', 'node_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True, null=True), keep_default=False)\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        \r
+        # Deleting model 'Node'\r
+        db.delete_table('forum_node')\r
+\r
+        # Removing M2M table for field tags on 'Node'\r
+        db.delete_table('forum_node_tags')\r
+\r
+        # Deleting field 'Vote.node'\r
+        db.delete_column(u'vote', 'node_id')\r
+\r
+        # Deleting field 'Comment.node'\r
+        db.delete_column(u'comment', 'node_id')\r
+\r
+        # Deleting field 'Answer.node_ptr'\r
+        db.delete_column(u'answer', 'node_ptr_id')\r
+\r
+        # Deleting field 'FlaggedItem.node'\r
+        db.delete_column(u'flagged_item', 'node_id')\r
+\r
+        # Deleting field 'Question.node_ptr'\r
+        db.delete_column(u'question', 'node_ptr_id')\r
+    \r
+    \r
+    models = {\r
+        'auth.group': {\r
+            'Meta': {'object_name': 'Group'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+        },\r
+        'auth.permission': {\r
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+        },\r
+        'auth.user': {\r
+            'Meta': {'object_name': 'User'},\r
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+        },\r
+        'contenttypes.contenttype': {\r
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+        },\r
+        'forum.activity': {\r
+            'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+            'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.anonymousanswer': {\r
+            'Meta': {'object_name': 'AnonymousAnswer'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.anonymousquestion': {\r
+            'Meta': {'object_name': 'AnonymousQuestion'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.answer': {\r
+            'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+            'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.User']"}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'html': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'null': 'True'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.Question']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.answerrevision': {\r
+            'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},\r
+            'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Answer']"}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),\r
+            'text': ('django.db.models.fields.TextField', [], {})\r
+        },\r
+        'forum.authkeyuserassociation': {\r
+            'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.award': {\r
+            'Meta': {'unique_together': "(('content_type', 'object_id', 'user', 'badge'),)", 'object_name': 'Award', 'db_table': "u'award'"},\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.comment': {\r
+            'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_comments'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'liked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'comments_liked'", 'through': "'LikedComment'", 'to': "orm['forum.User']"}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.favoritequestion': {\r
+            'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.flaggeditem': {\r
+            'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.keyvalue': {\r
+            'Meta': {'object_name': 'KeyValue'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'value': ('forum.models.utils.PickledObjectField', [], {})\r
+        },\r
+        'forum.likedcomment': {\r
+            'Meta': {'object_name': 'LikedComment'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'comment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Comment']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.markedtag': {\r
+            'Meta': {'object_name': 'MarkedTag'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.node': {\r
+            'Meta': {'object_name': 'Node'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'childs'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.question': {\r
+            'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['forum.User']"}),\r
+            'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+            'favourite_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'to': "orm['forum.User']"}),\r
+            'html': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['forum.User']"}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'null': 'True'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscriptions'", 'through': "'QuestionSubscription'", 'to': "orm['forum.User']"}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.questionrevision': {\r
+            'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Question']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.questionsubscription': {\r
+            'Meta': {'object_name': 'QuestionSubscription'},\r
+            'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 14, 1, 28, 41, 733000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.repute': {\r
+            'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.subscriptionsettings': {\r
+            'Meta': {'object_name': 'SubscriptionSettings'},\r
+            'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+            'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+            'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.tag': {\r
+            'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.user': {\r
+            'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+            'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+            'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+            'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+            'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+            'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+        },\r
+        'forum.validationhash': {\r
+            'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+            'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 15, 1, 28, 41, 976000)'}),\r
+            'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.vote': {\r
+            'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+        }\r
+    }\r
+    \r
+    complete_apps = ['forum']\r
diff --git a/forum/migrations/0007_q_and_a_to_node.py b/forum/migrations/0007_q_and_a_to_node.py
new file mode 100644 (file)
index 0000000..0e283e0
--- /dev/null
@@ -0,0 +1,549 @@
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import DataMigration\r
+from django.db import models\r
+from forum.migrations import ProgressBar\r
+\r
+class Migration(DataMigration):\r
+    \r
+    def forwards(self, orm):\r
+        #Converting questions\r
+        question_count = orm.Question.objects.all().count()\r
+        print "\nConverting %d questions:" % question_count\r
+        progress = ProgressBar(question_count)\r
+\r
+        question_id_map = {}\r
+\r
+        for q in orm.Question.objects.order_by('id'):\r
+            node = orm.Node(\r
+                node_type='question',\r
+                author=q.author,\r
+                added_at=q.added_at,\r
+                score=q.score,\r
+                vote_up_count=q.vote_up_count,\r
+                vote_down_count=q.vote_down_count,\r
+                offensive_flag_count=q.offensive_flag_count,\r
+                last_edited_at=q.last_edited_at,\r
+                last_edited_by=q.last_edited_by,\r
+                title=q.title,\r
+                body=q.html,\r
+                deleted=q.deleted,\r
+                deleted_by=q.deleted_by,\r
+                deleted_at=q.deleted_at,\r
+                tagnames=q.tagnames,\r
+                comment_count=q.comment_count,\r
+            )\r
+\r
+            node.save()\r
+            q.node_ptr = node\r
+            q.save()\r
+            node.tags = q.tags.all()\r
+\r
+            question_id_map[q.id] = node\r
+            progress.update()\r
+\r
+        print "\n...done\n"\r
+\r
+        #Converting answers\r
+        answer_count = orm.Answer.objects.all().count()\r
+        print "Converting %d answers:" % answer_count\r
+        progress = ProgressBar(answer_count)\r
+\r
+        answer_id_map = {}\r
+\r
+        for a in orm.Answer.objects.order_by('id'):\r
+            node = orm.Node(\r
+                node_type='answer',\r
+                parent=question_id_map[a.question.id],\r
+                author=a.author,\r
+                added_at=a.added_at,\r
+                score=a.score,\r
+                vote_up_count=a.vote_up_count,\r
+                vote_down_count=a.vote_down_count,\r
+                offensive_flag_count=a.offensive_flag_count,\r
+                last_edited_at=a.last_edited_at,\r
+                last_edited_by=a.last_edited_by,\r
+                body=a.html,\r
+                deleted=a.deleted,\r
+                deleted_by=a.deleted_by,\r
+                deleted_at=a.deleted_at,\r
+                comment_count=a.comment_count,\r
+            )\r
+\r
+            node.save()\r
+            a.node_ptr = node\r
+            a.save()\r
+            answer_id_map[a.id] = node\r
+            progress.update()\r
+\r
+        print "\n...done\n"\r
+\r
+        ctypes = dict([(ct.name, ct.id) for ct in orm['contenttypes.ContentType'].objects.all()])\r
+\r
+        #Converting votes\r
+        vote_count = orm.Vote.objects.all().count()\r
+        print "Converting %d vote references:" % vote_count\r
+        progress = ProgressBar(vote_count)\r
+        orfan_count = 0\r
+\r
+        for v in orm.Vote.objects.all():\r
+            node = (v.content_type.id == ctypes['question']) and question_id_map.get(v.object_id, None) \\r
+                                                             or answer_id_map.get(v.object_id, None)\r
+\r
+            if node:\r
+                v.node = node\r
+                v.save()\r
+            else:\r
+                v.delete()\r
+                orfan_count += 1\r
+\r
+            progress.update()\r
+\r
+        if orfan_count:\r
+            print "Deleted %d orfan votes"\r
+\r
+        print "\n...done\n"\r
+\r
+        #Converting flags\r
+        flag_count = orm.FlaggedItem.objects.all().count()\r
+        print "Converting %d flag references:" % flag_count\r
+        progress = ProgressBar(flag_count)\r
+        orfan_count = 0\r
+\r
+        for f in orm.FlaggedItem.objects.all():\r
+            node = (f.content_type.id == ctypes['question']) and question_id_map.get(f.object_id, None) \\r
+                                                             or answer_id_map.get(f.object_id, None)\r
+\r
+            if node:\r
+                f.node = node\r
+                f.save()\r
+            else:\r
+                f.delete()\r
+                orfan_count += 1\r
+\r
+            progress.update()\r
+\r
+        if orfan_count:\r
+            print "Deleted %d orfan votes"\r
+\r
+        print "\n...done\n"\r
+\r
+        #Converting comments\r
+        comment_count = orm.Comment.objects.all().count()\r
+        print "Converting %d comment references:" % comment_count\r
+        progress = ProgressBar(comment_count)\r
+        orfan_count = 0\r
+\r
+        for c in orm.Comment.objects.all():\r
+            node = (c.content_type.id == ctypes['question']) and question_id_map.get(c.object_id, None) \\r
+                                                             or answer_id_map.get(c.object_id, None)\r
+\r
+            if node:\r
+                c.node = node\r
+                c.save()\r
+            else:\r
+                c.delete()\r
+                orfan_count += 1\r
+\r
+            progress.update()\r
+\r
+        if orfan_count:\r
+            print "Deleted %d orfan comments"\r
+\r
+        print "\n...done\n"\r
+\r
+\r
+        #Converting awards\r
+        awards = orm.Award.objects.filter(content_type__id__in=(ctypes['question'], ctypes['answer']))\r
+        award_count = awards.count()\r
+        print "Converting %d award references:" % award_count\r
+        progress = ProgressBar(award_count)\r
+\r
+        for a in awards:\r
+            node = (a.content_type.id == ctypes['question']) and question_id_map.get(a.object_id, None) \\r
+                                                             or answer_id_map.get(a.object_id, None)\r
+\r
+            if node:\r
+                a.object_id = node.id\r
+                a.save()\r
+\r
+            progress.update()\r
+\r
+        print "\n...done\n"\r
+\r
+\r
+        #Converting activity\r
+        activities = orm.Activity.objects.filter(content_type__id__in=(ctypes['question'], ctypes['answer']))\r
+        activity_count = activities.count()\r
+        print "Converting %d activity references:" % activity_count\r
+        progress = ProgressBar(activity_count)\r
+\r
+        for a in activities:\r
+            node = (a.content_type.id == ctypes['question']) and question_id_map.get(a.object_id, None) \\r
+                                                             or answer_id_map.get(a.object_id, None)\r
+\r
+            if node:\r
+                a.object_id = node.id\r
+                a.save()\r
+\r
+            progress.update()\r
+\r
+        print "\n...done\n"\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        "Write your backwards methods here."\r
+    \r
+    models = {\r
+        'auth.group': {\r
+            'Meta': {'object_name': 'Group'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+        },\r
+        'auth.permission': {\r
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+        },\r
+        'auth.user': {\r
+            'Meta': {'object_name': 'User'},\r
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+        },\r
+        'contenttypes.contenttype': {\r
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+        },\r
+        'forum.activity': {\r
+            'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+            'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.anonymousanswer': {\r
+            'Meta': {'object_name': 'AnonymousAnswer'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.anonymousquestion': {\r
+            'Meta': {'object_name': 'AnonymousQuestion'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.answer': {\r
+            'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+            'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.User']"}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'html': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'null': 'True'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.Question']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.answerrevision': {\r
+            'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},\r
+            'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Answer']"}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),\r
+            'text': ('django.db.models.fields.TextField', [], {})\r
+        },\r
+        'forum.authkeyuserassociation': {\r
+            'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.award': {\r
+            'Meta': {'unique_together': "(('content_type', 'object_id', 'user', 'badge'),)", 'object_name': 'Award', 'db_table': "u'award'"},\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.comment': {\r
+            'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_comments'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'liked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'comments_liked'", 'through': "'LikedComment'", 'to': "orm['forum.User']"}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.favoritequestion': {\r
+            'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.flaggeditem': {\r
+            'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.keyvalue': {\r
+            'Meta': {'object_name': 'KeyValue'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'value': ('forum.models.utils.PickledObjectField', [], {})\r
+        },\r
+        'forum.likedcomment': {\r
+            'Meta': {'object_name': 'LikedComment'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'comment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Comment']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.markedtag': {\r
+            'Meta': {'object_name': 'MarkedTag'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.node': {\r
+            'Meta': {'object_name': 'Node'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'childs'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.question': {\r
+            'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['forum.User']"}),\r
+            'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+            'favourite_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'to': "orm['forum.User']"}),\r
+            'html': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['forum.User']"}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'null': 'True'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscriptions'", 'through': "'QuestionSubscription'", 'to': "orm['forum.User']"}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.questionrevision': {\r
+            'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Question']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.questionsubscription': {\r
+            'Meta': {'object_name': 'QuestionSubscription'},\r
+            'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 14, 1, 29, 43, 727000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.repute': {\r
+            'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.subscriptionsettings': {\r
+            'Meta': {'object_name': 'SubscriptionSettings'},\r
+            'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+            'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+            'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.tag': {\r
+            'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.user': {\r
+            'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+            'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+            'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+            'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+            'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+            'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+        },\r
+        'forum.validationhash': {\r
+            'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+            'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 15, 1, 29, 43, 815000)'}),\r
+            'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.vote': {\r
+            'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+        }\r
+    }\r
+    \r
+    complete_apps = ['forum']\r
diff --git a/forum/migrations/0008_auto__add_noderevision__del_field_vote_object_id__del_field_vote_conte.py b/forum/migrations/0008_auto__add_noderevision__del_field_vote_object_id__del_field_vote_conte.py
new file mode 100644 (file)
index 0000000..bb94406
--- /dev/null
@@ -0,0 +1,424 @@
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+    \r
+    def forwards(self, orm):\r
+        \r
+        # Adding model 'NodeRevision'\r
+        db.create_table('forum_noderevision', (\r
+            ('node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='revisions', to=orm['forum.Node'])),\r
+            ('body', self.gf('django.db.models.fields.TextField')()),\r
+            ('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='noderevisions', to=orm['forum.User'])),\r
+            ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=125)),\r
+            ('title', self.gf('django.db.models.fields.CharField')(max_length=300)),\r
+            ('summary', self.gf('django.db.models.fields.CharField')(max_length=300)),\r
+            ('revised_at', self.gf('django.db.models.fields.DateTimeField')()),\r
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+            ('revision', self.gf('django.db.models.fields.PositiveIntegerField')()),\r
+        ))\r
+        db.send_create_signal('forum', ['NodeRevision'])\r
+\r
+        # Deleting field 'Vote.object_id'\r
+        db.delete_column(u'vote', 'object_id')\r
+\r
+        # Deleting field 'Vote.content_type'\r
+        db.delete_column(u'vote', 'content_type_id')\r
+\r
+        # Deleting field 'Comment.object_id'\r
+        db.delete_column(u'comment', 'object_id')\r
+\r
+        # Deleting field 'Comment.content_type'\r
+        db.delete_column(u'comment', 'content_type_id')\r
+\r
+        # Deleting field 'FlaggedItem.object_id'\r
+        db.delete_column(u'flagged_item', 'object_id')\r
+\r
+        # Deleting field 'FlaggedItem.content_type'\r
+        db.delete_column(u'flagged_item', 'content_type_id')\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        \r
+        # Deleting model 'NodeRevision'\r
+        db.delete_table('forum_noderevision')\r
+\r
+        # Adding field 'Vote.object_id'\r
+        db.add_column(u'vote', 'object_id', self.gf('django.db.models.fields.PositiveIntegerField')(default=1), keep_default=False)\r
+\r
+        # Adding field 'Vote.content_type'\r
+        db.add_column(u'vote', 'content_type', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['contenttypes.ContentType']), keep_default=False)\r
+\r
+        # Adding field 'Comment.object_id'\r
+        db.add_column(u'comment', 'object_id', self.gf('django.db.models.fields.PositiveIntegerField')(default=1), keep_default=False)\r
+\r
+        # Adding field 'Comment.content_type'\r
+        db.add_column(u'comment', 'content_type', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['contenttypes.ContentType']), keep_default=False)\r
+\r
+        # Adding field 'FlaggedItem.object_id'\r
+        db.add_column(u'flagged_item', 'object_id', self.gf('django.db.models.fields.PositiveIntegerField')(default=1), keep_default=False)\r
+\r
+        # Adding field 'FlaggedItem.content_type'\r
+        db.add_column(u'flagged_item', 'content_type', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['contenttypes.ContentType']), keep_default=False)\r
+    \r
+    \r
+    models = {\r
+        'auth.group': {\r
+            'Meta': {'object_name': 'Group'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+        },\r
+        'auth.permission': {\r
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+        },\r
+        'auth.user': {\r
+            'Meta': {'object_name': 'User'},\r
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+        },\r
+        'contenttypes.contenttype': {\r
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+        },\r
+        'forum.activity': {\r
+            'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+            'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.anonymousanswer': {\r
+            'Meta': {'object_name': 'AnonymousAnswer'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.anonymousquestion': {\r
+            'Meta': {'object_name': 'AnonymousQuestion'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.answer': {\r
+            'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+            'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.User']"}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'html': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'null': 'True'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.Question']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.answerrevision': {\r
+            'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},\r
+            'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Answer']"}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),\r
+            'text': ('django.db.models.fields.TextField', [], {})\r
+        },\r
+        'forum.authkeyuserassociation': {\r
+            'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.award': {\r
+            'Meta': {'unique_together': "(('content_type', 'object_id', 'user', 'badge'),)", 'object_name': 'Award', 'db_table': "u'award'"},\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.comment': {\r
+            'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_comments'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'liked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'comments_liked'", 'through': "'LikedComment'", 'to': "orm['forum.User']"}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.favoritequestion': {\r
+            'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.flaggeditem': {\r
+            'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.keyvalue': {\r
+            'Meta': {'object_name': 'KeyValue'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'value': ('forum.models.utils.PickledObjectField', [], {})\r
+        },\r
+        'forum.likedcomment': {\r
+            'Meta': {'object_name': 'LikedComment'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'comment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Comment']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.markedtag': {\r
+            'Meta': {'object_name': 'MarkedTag'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.node': {\r
+            'Meta': {'object_name': 'Node'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'childs'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.noderevision': {\r
+            'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.question': {\r
+            'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['forum.User']"}),\r
+            'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+            'favourite_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'to': "orm['forum.User']"}),\r
+            'html': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['forum.User']"}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'null': 'True'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.questionrevision': {\r
+            'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Question']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.questionsubscription': {\r
+            'Meta': {'object_name': 'QuestionSubscription'},\r
+            'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 14, 12, 14, 26, 755000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.repute': {\r
+            'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.subscriptionsettings': {\r
+            'Meta': {'object_name': 'SubscriptionSettings'},\r
+            'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+            'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+            'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.tag': {\r
+            'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.user': {\r
+            'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+            'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+            'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+            'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+            'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+            'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+        },\r
+        'forum.validationhash': {\r
+            'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+            'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 15, 12, 14, 35, 357000)'}),\r
+            'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.vote': {\r
+            'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+        }\r
+    }\r
+    \r
+    complete_apps = ['forum']\r
diff --git a/forum/migrations/0009_convert_revisions.py b/forum/migrations/0009_convert_revisions.py
new file mode 100644 (file)
index 0000000..6b06ed9
--- /dev/null
@@ -0,0 +1,414 @@
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import DataMigration\r
+from django.db import models\r
+from forum.migrations import ProgressBar\r
+\r
+class Migration(DataMigration):\r
+    \r
+    def forwards(self, orm):\r
+        #Converting question revisions\r
+        qr_count = orm.QuestionRevision.objects.all().count()\r
+        print "\nConverting %d question revisions:" % qr_count\r
+        progress = ProgressBar(qr_count)\r
+\r
+        for q in orm.QuestionRevision.objects.order_by('id'):\r
+            revision = orm.NodeRevision(\r
+                node=q.question.node_ptr,\r
+                title=q.title,\r
+                summary=q.summary,\r
+                tagnames=q.tagnames,\r
+                revision=q.revision,\r
+                author=q.author,\r
+                revised_at=q.revised_at,\r
+                body=q.text,\r
+            )\r
+\r
+            revision.save()\r
+            progress.update()\r
+\r
+        print "\n...done\n"\r
+\r
+\r
+        #Converting answer revisions\r
+        ar_count = orm.AnswerRevision.objects.all().count()\r
+        print "\nConverting %d answer revisions:" % ar_count\r
+        progress = ProgressBar(ar_count)\r
+\r
+        for a in orm.AnswerRevision.objects.order_by('id'):\r
+            revision = orm.NodeRevision(\r
+                summary=a.summary,\r
+                node=a.answer.node_ptr,\r
+                revision=a.revision,\r
+                author=a.author,\r
+                revised_at=a.revised_at,\r
+                body=a.text,\r
+            )\r
+\r
+            revision.save()\r
+            progress.update()\r
+\r
+        print "\n...done\n"\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        "Write your backwards methods here."\r
+    \r
+    models = {\r
+        'auth.group': {\r
+            'Meta': {'object_name': 'Group'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+        },\r
+        'auth.permission': {\r
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+        },\r
+        'auth.user': {\r
+            'Meta': {'object_name': 'User'},\r
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+        },\r
+        'contenttypes.contenttype': {\r
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+        },\r
+        'forum.activity': {\r
+            'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+            'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.anonymousanswer': {\r
+            'Meta': {'object_name': 'AnonymousAnswer'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.anonymousquestion': {\r
+            'Meta': {'object_name': 'AnonymousQuestion'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.answer': {\r
+            'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+            'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.User']"}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_answers'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'html': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_answers'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'null': 'True'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answers'", 'to': "orm['forum.Question']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.answerrevision': {\r
+            'Meta': {'object_name': 'AnswerRevision', 'db_table': "u'answer_revision'"},\r
+            'answer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Answer']"}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'answerrevisions'", 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),\r
+            'text': ('django.db.models.fields.TextField', [], {})\r
+        },\r
+        'forum.authkeyuserassociation': {\r
+            'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.award': {\r
+            'Meta': {'unique_together': "(('content_type', 'object_id', 'user', 'badge'),)", 'object_name': 'Award', 'db_table': "u'award'"},\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.comment': {\r
+            'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_comments'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'liked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'comments_liked'", 'through': "'LikedComment'", 'to': "orm['forum.User']"}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.favoritequestion': {\r
+            'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.flaggeditem': {\r
+            'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.keyvalue': {\r
+            'Meta': {'object_name': 'KeyValue'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'value': ('forum.models.utils.PickledObjectField', [], {})\r
+        },\r
+        'forum.likedcomment': {\r
+            'Meta': {'object_name': 'LikedComment'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'comment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Comment']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.markedtag': {\r
+            'Meta': {'object_name': 'MarkedTag'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.node': {\r
+            'Meta': {'object_name': 'Node'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'childs'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.noderevision': {\r
+            'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.question': {\r
+            'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questions'", 'to': "orm['forum.User']"}),\r
+            'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+            'favourite_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_questions'", 'to': "orm['forum.User']"}),\r
+            'html': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['forum.User']"}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'null': 'True'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'questions'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.questionrevision': {\r
+            'Meta': {'object_name': 'QuestionRevision', 'db_table': "u'question_revision'"},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'questionrevisions'", 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Question']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.questionsubscription': {\r
+            'Meta': {'object_name': 'QuestionSubscription'},\r
+            'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 14, 12, 14, 26, 755000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.repute': {\r
+            'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.subscriptionsettings': {\r
+            'Meta': {'object_name': 'SubscriptionSettings'},\r
+            'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+            'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+            'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.tag': {\r
+            'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.user': {\r
+            'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+            'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+            'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+            'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+            'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+            'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+        },\r
+        'forum.validationhash': {\r
+            'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+            'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 15, 12, 14, 35, 357000)'}),\r
+            'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.vote': {\r
+            'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+        }\r
+    }\r
+    \r
+    complete_apps = ['forum']\r
diff --git a/forum/migrations/0010_auto__del_questionrevision__del_answerrevision__del_field_answer_vote_.py b/forum/migrations/0010_auto__del_questionrevision__del_answerrevision__del_field_answer_vote_.py
new file mode 100644 (file)
index 0000000..8baaf67
--- /dev/null
@@ -0,0 +1,576 @@
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+    \r
+    def forwards(self, orm):\r
+        \r
+        # Deleting model 'QuestionRevision'\r
+        db.delete_table(u'question_revision')\r
+\r
+        # Deleting model 'AnswerRevision'\r
+        db.delete_table(u'answer_revision')\r
+\r
+        # Deleting field 'Answer.vote_up_count'\r
+        db.delete_column(u'answer', 'vote_up_count')\r
+\r
+        # Deleting field 'Answer.author'\r
+        db.delete_column(u'answer', 'author_id')\r
+\r
+        # Deleting field 'Answer.deleted'\r
+        db.delete_column(u'answer', 'deleted')\r
+\r
+        # Deleting field 'Answer.question'\r
+        db.delete_column(u'answer', 'question_id')\r
+\r
+        # Deleting field 'Answer.html'\r
+        db.delete_column(u'answer', 'html')\r
+\r
+        # Deleting field 'Answer.offensive_flag_count'\r
+        db.delete_column(u'answer', 'offensive_flag_count')\r
+\r
+        # Deleting field 'Answer.deleted_by'\r
+        db.delete_column(u'answer', 'deleted_by_id')\r
+\r
+        # Deleting field 'Answer.comment_count'\r
+        db.delete_column(u'answer', 'comment_count')\r
+\r
+        # Deleting field 'Answer.score'\r
+        db.delete_column(u'answer', 'score')\r
+\r
+        # Deleting field 'Answer.vote_down_count'\r
+        db.delete_column(u'answer', 'vote_down_count')\r
+\r
+        # Deleting field 'Answer.added_at'\r
+        db.delete_column(u'answer', 'added_at')\r
+\r
+        # Deleting field 'Answer.last_edited_by'\r
+        db.delete_column(u'answer', 'last_edited_by_id')\r
+\r
+        # Deleting field 'Answer.deleted_at'\r
+        db.delete_column(u'answer', 'deleted_at')\r
+\r
+        # Deleting field 'Answer.id'\r
+        db.delete_column(u'answer', 'id')\r
+\r
+        # Deleting field 'Answer.last_edited_at'\r
+        db.delete_column(u'answer', 'last_edited_at')\r
+\r
+        # Changing field 'Answer.node_ptr'\r
+        db.alter_column(u'answer', 'node_ptr_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True))\r
+        db.create_primary_key(u'answer', ['node_ptr_id'])\r
+\r
+        # Deleting field 'Question.vote_up_count'\r
+        db.delete_column(u'question', 'vote_up_count')\r
+\r
+        # Deleting field 'Question.offensive_flag_count'\r
+        db.delete_column(u'question', 'offensive_flag_count')\r
+\r
+        # Deleting field 'Question.summary'\r
+        db.delete_column(u'question', 'summary')\r
+\r
+        # Deleting field 'Question.id'\r
+        db.delete_column(u'question', 'id')\r
+\r
+        # Deleting field 'Question.deleted_at'\r
+        db.delete_column(u'question', 'deleted_at')\r
+\r
+        # Deleting field 'Question.score'\r
+        db.delete_column(u'question', 'score')\r
+\r
+        # Deleting field 'Question.author'\r
+        db.delete_column(u'question', 'author_id')\r
+\r
+        # Deleting field 'Question.comment_count'\r
+        db.delete_column(u'question', 'comment_count')\r
+\r
+        # Deleting field 'Question.html'\r
+        db.delete_column(u'question', 'html')\r
+\r
+        # Deleting field 'Question.vote_down_count'\r
+        db.delete_column(u'question', 'vote_down_count')\r
+\r
+        # Deleting field 'Question.last_edited_by'\r
+        db.delete_column(u'question', 'last_edited_by_id')\r
+\r
+        # Deleting field 'Question.deleted'\r
+        db.delete_column(u'question', 'deleted')\r
+\r
+        # Deleting field 'Question.tagnames'\r
+        db.delete_column(u'question', 'tagnames')\r
+\r
+        # Deleting field 'Question.title'\r
+        db.delete_column(u'question', 'title')\r
+\r
+        # Deleting field 'Question.added_at'\r
+        db.delete_column(u'question', 'added_at')\r
+\r
+        # Deleting field 'Question.deleted_by'\r
+        db.delete_column(u'question', 'deleted_by_id')\r
+\r
+        # Deleting field 'Question.last_edited_at'\r
+        db.delete_column(u'question', 'last_edited_at')\r
+\r
+        # Removing M2M table for field followed_by on 'Question'\r
+        db.delete_table('question_followed_by')\r
+\r
+        # Removing M2M table for field tags on 'Question'\r
+        db.delete_table('question_tags')\r
+\r
+        # Changing field 'Question.node_ptr'\r
+        db.alter_column(u'question', 'node_ptr_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True))\r
+        db.create_primary_key(u'question', ['node_ptr_id'])        \r
+    \r
+    \r
+    def backwards(self, orm):\r
+        \r
+        # Adding model 'QuestionRevision'\r
+        db.create_table(u'question_revision', (\r
+            ('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='questionrevisions', to=orm['forum.User'])),\r
+            ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=125)),\r
+            ('text', self.gf('django.db.models.fields.TextField')()),\r
+            ('title', self.gf('django.db.models.fields.CharField')(max_length=300)),\r
+            ('question', self.gf('django.db.models.fields.related.ForeignKey')(related_name='revisions', to=orm['forum.Question'])),\r
+            ('revised_at', self.gf('django.db.models.fields.DateTimeField')()),\r
+            ('summary', self.gf('django.db.models.fields.CharField')(max_length=300, blank=True)),\r
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+            ('revision', self.gf('django.db.models.fields.PositiveIntegerField')()),\r
+        ))\r
+        db.send_create_signal('forum', ['QuestionRevision'])\r
+\r
+        # Adding model 'AnswerRevision'\r
+        db.create_table(u'answer_revision', (\r
+            ('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='answerrevisions', to=orm['forum.User'])),\r
+            ('text', self.gf('django.db.models.fields.TextField')()),\r
+            ('revised_at', self.gf('django.db.models.fields.DateTimeField')()),\r
+            ('summary', self.gf('django.db.models.fields.CharField')(max_length=300, blank=True)),\r
+            ('answer', self.gf('django.db.models.fields.related.ForeignKey')(related_name='revisions', to=orm['forum.Answer'])),\r
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+            ('revision', self.gf('django.db.models.fields.PositiveIntegerField')()),\r
+        ))\r
+        db.send_create_signal('forum', ['AnswerRevision'])\r
+\r
+        # Adding field 'Answer.vote_up_count'\r
+        db.add_column(u'answer', 'vote_up_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Answer.author'\r
+        db.add_column(u'answer', 'author', self.gf('django.db.models.fields.related.ForeignKey')(default=1, related_name='answers', to=orm['forum.User']), keep_default=False)\r
+\r
+        # Adding field 'Answer.deleted'\r
+        db.add_column(u'answer', 'deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+        # Adding field 'Answer.question'\r
+        db.add_column(u'answer', 'question', self.gf('django.db.models.fields.related.ForeignKey')(default=1, related_name='answers', to=orm['forum.Question']), keep_default=False)\r
+\r
+        # Adding field 'Answer.html'\r
+        db.add_column(u'answer', 'html', self.gf('django.db.models.fields.TextField')(default=1), keep_default=False)\r
+\r
+        # Adding field 'Answer.offensive_flag_count'\r
+        db.add_column(u'answer', 'offensive_flag_count', self.gf('django.db.models.fields.SmallIntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Answer.deleted_by'\r
+        db.add_column(u'answer', 'deleted_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='deleted_answers', null=True, to=orm['forum.User'], blank=True), keep_default=False)\r
+\r
+        # Adding field 'Answer.comment_count'\r
+        db.add_column(u'answer', 'comment_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Answer.score'\r
+        db.add_column(u'answer', 'score', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Answer.vote_down_count'\r
+        db.add_column(u'answer', 'vote_down_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Answer.added_at'\r
+        db.add_column(u'answer', 'added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now), keep_default=False)\r
+\r
+        # Adding field 'Answer.last_edited_by'\r
+        db.add_column(u'answer', 'last_edited_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='last_edited_answers', null=True, to=orm['forum.User'], blank=True), keep_default=False)\r
+\r
+        # Adding field 'Answer.deleted_at'\r
+        db.add_column(u'answer', 'deleted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)\r
+\r
+        # Adding field 'Answer.id'\r
+        db.add_column(u'answer', 'id', self.gf('django.db.models.fields.AutoField')(default=1, primary_key=True), keep_default=False)\r
+\r
+        # Adding field 'Answer.last_edited_at'\r
+        db.add_column(u'answer', 'last_edited_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)\r
+\r
+        # Changing field 'Answer.node_ptr'\r
+        db.alter_column(u'answer', 'node_ptr_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True, null=True))\r
+\r
+        # Adding field 'Question.vote_up_count'\r
+        db.add_column(u'question', 'vote_up_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Question.offensive_flag_count'\r
+        db.add_column(u'question', 'offensive_flag_count', self.gf('django.db.models.fields.SmallIntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Question.summary'\r
+        db.add_column(u'question', 'summary', self.gf('django.db.models.fields.CharField')(default=1, max_length=180), keep_default=False)\r
+\r
+        # Adding field 'Question.id'\r
+        db.add_column(u'question', 'id', self.gf('django.db.models.fields.AutoField')(default=1, primary_key=True), keep_default=False)\r
+\r
+        # Adding field 'Question.deleted_at'\r
+        db.add_column(u'question', 'deleted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)\r
+\r
+        # Adding field 'Question.score'\r
+        db.add_column(u'question', 'score', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Question.author'\r
+        db.add_column(u'question', 'author', self.gf('django.db.models.fields.related.ForeignKey')(default=1, related_name='questions', to=orm['forum.User']), keep_default=False)\r
+\r
+        # Adding field 'Question.comment_count'\r
+        db.add_column(u'question', 'comment_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Question.html'\r
+        db.add_column(u'question', 'html', self.gf('django.db.models.fields.TextField')(default=1), keep_default=False)\r
+\r
+        # Adding field 'Question.vote_down_count'\r
+        db.add_column(u'question', 'vote_down_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+        # Adding field 'Question.last_edited_by'\r
+        db.add_column(u'question', 'last_edited_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='last_edited_questions', null=True, to=orm['forum.User'], blank=True), keep_default=False)\r
+\r
+        # Adding field 'Question.deleted'\r
+        db.add_column(u'question', 'deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+        # Adding field 'Question.tagnames'\r
+        db.add_column(u'question', 'tagnames', self.gf('django.db.models.fields.CharField')(default=1, max_length=125), keep_default=False)\r
+\r
+        # Adding field 'Question.title'\r
+        db.add_column(u'question', 'title', self.gf('django.db.models.fields.CharField')(default=1, max_length=300), keep_default=False)\r
+\r
+        # Adding field 'Question.added_at'\r
+        db.add_column(u'question', 'added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now), keep_default=False)\r
+\r
+        # Adding field 'Question.deleted_by'\r
+        db.add_column(u'question', 'deleted_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='deleted_questions', null=True, to=orm['forum.User'], blank=True), keep_default=False)\r
+\r
+        # Adding field 'Question.last_edited_at'\r
+        db.add_column(u'question', 'last_edited_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)\r
+\r
+        # Adding M2M table for field followed_by on 'Question'\r
+        db.create_table(u'question_followed_by', (\r
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),\r
+            ('question', models.ForeignKey(orm['forum.question'], null=False)),\r
+            ('user', models.ForeignKey(orm['forum.user'], null=False))\r
+        ))\r
+        db.create_unique(u'question_followed_by', ['question_id', 'user_id'])\r
+\r
+        # Adding M2M table for field tags on 'Question'\r
+        db.create_table(u'question_tags', (\r
+            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),\r
+            ('question', models.ForeignKey(orm['forum.question'], null=False)),\r
+            ('tag', models.ForeignKey(orm['forum.tag'], null=False))\r
+        ))\r
+        db.create_unique(u'question_tags', ['question_id', 'tag_id'])\r
+\r
+        # Changing field 'Question.node_ptr'\r
+        db.alter_column(u'question', 'node_ptr_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True, null=True))\r
+    \r
+    \r
+    models = {\r
+        'auth.group': {\r
+            'Meta': {'object_name': 'Group'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+        },\r
+        'auth.permission': {\r
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+        },\r
+        'auth.user': {\r
+            'Meta': {'object_name': 'User'},\r
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+        },\r
+        'contenttypes.contenttype': {\r
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+        },\r
+        'forum.activity': {\r
+            'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+            'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.anonymousanswer': {\r
+            'Meta': {'object_name': 'AnonymousAnswer'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.anonymousquestion': {\r
+            'Meta': {'object_name': 'AnonymousQuestion'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.answer': {\r
+            'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+            'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.authkeyuserassociation': {\r
+            'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.award': {\r
+            'Meta': {'unique_together': "(('content_type', 'object_id', 'user', 'badge'),)", 'object_name': 'Award', 'db_table': "u'award'"},\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.comment': {\r
+            'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_comments'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'liked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'comments_liked'", 'through': "'LikedComment'", 'to': "orm['forum.User']"}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.favoritequestion': {\r
+            'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.flaggeditem': {\r
+            'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.keyvalue': {\r
+            'Meta': {'object_name': 'KeyValue'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'value': ('forum.models.utils.PickledObjectField', [], {})\r
+        },\r
+        'forum.likedcomment': {\r
+            'Meta': {'object_name': 'LikedComment'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'comment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Comment']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.markedtag': {\r
+            'Meta': {'object_name': 'MarkedTag'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.node': {\r
+            'Meta': {'object_name': 'Node'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'childs'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.noderevision': {\r
+            'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.question': {\r
+            'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+            'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+            'favourite_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True'}),\r
+            'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscriptions'", 'through': "'QuestionSubscription'", 'to': "orm['forum.User']"}),\r
+            'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.questionsubscription': {\r
+            'Meta': {'object_name': 'QuestionSubscription'},\r
+            'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 14, 12, 30, 8, 362000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.repute': {\r
+            'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.subscriptionsettings': {\r
+            'Meta': {'object_name': 'SubscriptionSettings'},\r
+            'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+            'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+            'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.tag': {\r
+            'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.user': {\r
+            'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+            'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+            'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+            'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+            'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+            'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+        },\r
+        'forum.validationhash': {\r
+            'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+            'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 15, 12, 30, 22, 477000)'}),\r
+            'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.vote': {\r
+            'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+        }\r
+    }\r
+    \r
+    complete_apps = ['forum']\r
diff --git a/forum/migrations/0011_auto__add_field_node_active_revision.py b/forum/migrations/0011_auto__add_field_node_active_revision.py
new file mode 100644 (file)
index 0000000..940f37f
--- /dev/null
@@ -0,0 +1,323 @@
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+    \r
+    def forwards(self, orm):\r
+        \r
+        # Adding field 'Node.active_revision'\r
+        db.add_column('forum_node', 'active_revision', self.gf('django.db.models.fields.related.OneToOneField')(related_name='active', unique=True, null=True, to=orm['forum.NodeRevision']), keep_default=False)\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        \r
+        # Deleting field 'Node.active_revision'\r
+        db.delete_column('forum_node', 'active_revision_id')\r
+    \r
+    \r
+    models = {\r
+        'auth.group': {\r
+            'Meta': {'object_name': 'Group'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+        },\r
+        'auth.permission': {\r
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+        },\r
+        'auth.user': {\r
+            'Meta': {'object_name': 'User'},\r
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+        },\r
+        'contenttypes.contenttype': {\r
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+        },\r
+        'forum.activity': {\r
+            'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+            'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.anonymousanswer': {\r
+            'Meta': {'object_name': 'AnonymousAnswer'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.anonymousquestion': {\r
+            'Meta': {'object_name': 'AnonymousQuestion'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.answer': {\r
+            'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+            'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.authkeyuserassociation': {\r
+            'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.award': {\r
+            'Meta': {'unique_together': "(('content_type', 'object_id', 'user', 'badge'),)", 'object_name': 'Award', 'db_table': "u'award'"},\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.comment': {\r
+            'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_comments'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'liked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'comments_liked'", 'through': "'LikedComment'", 'to': "orm['forum.User']"}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.favoritequestion': {\r
+            'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.flaggeditem': {\r
+            'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.keyvalue': {\r
+            'Meta': {'object_name': 'KeyValue'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'value': ('forum.models.utils.PickledObjectField', [], {})\r
+        },\r
+        'forum.likedcomment': {\r
+            'Meta': {'object_name': 'LikedComment'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'comment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Comment']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.markedtag': {\r
+            'Meta': {'object_name': 'MarkedTag'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.node': {\r
+            'Meta': {'object_name': 'Node'},\r
+            'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.noderevision': {\r
+            'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.question': {\r
+            'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+            'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+            'favourite_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True'}),\r
+            'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscriptions'", 'through': "'QuestionSubscription'", 'to': "orm['forum.User']"}),\r
+            'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.questionsubscription': {\r
+            'Meta': {'object_name': 'QuestionSubscription'},\r
+            'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 14, 17, 56, 17, 351000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.repute': {\r
+            'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.subscriptionsettings': {\r
+            'Meta': {'object_name': 'SubscriptionSettings'},\r
+            'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+            'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+            'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.tag': {\r
+            'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.user': {\r
+            'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+            'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+            'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+            'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+            'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+            'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+        },\r
+        'forum.validationhash': {\r
+            'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+            'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 15, 17, 56, 17, 557000)'}),\r
+            'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.vote': {\r
+            'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+        }\r
+    }\r
+    \r
+    complete_apps = ['forum']\r
diff --git a/forum/migrations/0012_set_active_revision.py b/forum/migrations/0012_set_active_revision.py
new file mode 100644 (file)
index 0000000..29e9030
--- /dev/null
@@ -0,0 +1,320 @@
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import DataMigration\r
+from django.db import models\r
+\r
+class Migration(DataMigration):\r
+    \r
+    def forwards(self, orm):\r
+        for n in orm.Node.objects.all():\r
+            n.active_revision = n.revisions.order_by('-id')[0]\r
+            n.save()\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        "Write your backwards methods here."\r
+    \r
+    models = {\r
+        'auth.group': {\r
+            'Meta': {'object_name': 'Group'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+        },\r
+        'auth.permission': {\r
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+        },\r
+        'auth.user': {\r
+            'Meta': {'object_name': 'User'},\r
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+        },\r
+        'contenttypes.contenttype': {\r
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+        },\r
+        'forum.activity': {\r
+            'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+            'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.anonymousanswer': {\r
+            'Meta': {'object_name': 'AnonymousAnswer'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['forum.Question']"}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.anonymousquestion': {\r
+            'Meta': {'object_name': 'AnonymousQuestion'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),\r
+            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'text': ('django.db.models.fields.TextField', [], {}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+        },\r
+        'forum.answer': {\r
+            'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+            'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.authkeyuserassociation': {\r
+            'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.award': {\r
+            'Meta': {'unique_together': "(('content_type', 'object_id', 'user', 'badge'),)", 'object_name': 'Award', 'db_table': "u'award'"},\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.comment': {\r
+            'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_comments'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'liked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'comments_liked'", 'through': "'LikedComment'", 'to': "orm['forum.User']"}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.favoritequestion': {\r
+            'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.flaggeditem': {\r
+            'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.keyvalue': {\r
+            'Meta': {'object_name': 'KeyValue'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'value': ('forum.models.utils.PickledObjectField', [], {})\r
+        },\r
+        'forum.likedcomment': {\r
+            'Meta': {'object_name': 'LikedComment'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'comment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Comment']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.markedtag': {\r
+            'Meta': {'object_name': 'MarkedTag'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.node': {\r
+            'Meta': {'object_name': 'Node'},\r
+            'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.noderevision': {\r
+            'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.question': {\r
+            'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+            'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+            'favourite_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True'}),\r
+            'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscriptions'", 'through': "'QuestionSubscription'", 'to': "orm['forum.User']"}),\r
+            'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.questionsubscription': {\r
+            'Meta': {'object_name': 'QuestionSubscription'},\r
+            'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 14, 17, 56, 41, 918000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.repute': {\r
+            'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.subscriptionsettings': {\r
+            'Meta': {'object_name': 'SubscriptionSettings'},\r
+            'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+            'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+            'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.tag': {\r
+            'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.user': {\r
+            'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+            'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+            'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+            'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+            'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+            'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+        },\r
+        'forum.validationhash': {\r
+            'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+            'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 15, 17, 56, 41, 986000)'}),\r
+            'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.vote': {\r
+            'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+        }\r
+    }\r
+    \r
+    complete_apps = ['forum']\r
diff --git a/forum/migrations/0013_auto__del_anonymousquestion__del_anonymousanswer__add_anonymousnode.py b/forum/migrations/0013_auto__del_anonymousquestion__del_anonymousanswer__add_anonymousnode.py
new file mode 100644 (file)
index 0000000..d203297
--- /dev/null
@@ -0,0 +1,344 @@
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+    \r
+    def forwards(self, orm):\r
+        \r
+        # Deleting model 'AnonymousQuestion'\r
+        db.delete_table('forum_anonymousquestion')\r
+\r
+        # Deleting model 'AnonymousAnswer'\r
+        db.delete_table('forum_anonymousanswer')\r
+\r
+        # Adding model 'AnonymousNode'\r
+        db.create_table('forum_anonymousnode', (\r
+            ('convertible_to', self.gf('django.db.models.fields.CharField')(default='node', max_length=16)),\r
+            ('validation_hash', self.gf('django.db.models.fields.related.ForeignKey')(related_name='anonymous_content', to=orm['forum.Node'])),\r
+            ('node_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True, primary_key=True)),\r
+        ))\r
+        db.send_create_signal('forum', ['AnonymousNode'])\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        \r
+        # Adding model 'AnonymousQuestion'\r
+        db.create_table('forum_anonymousquestion', (\r
+            ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+            ('ip_addr', self.gf('django.db.models.fields.IPAddressField')(max_length=15)),\r
+            ('title', self.gf('django.db.models.fields.CharField')(max_length=300)),\r
+            ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=125)),\r
+            ('text', self.gf('django.db.models.fields.TextField')()),\r
+            ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'], null=True)),\r
+            ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+            ('summary', self.gf('django.db.models.fields.CharField')(max_length=180)),\r
+            ('session_key', self.gf('django.db.models.fields.CharField')(max_length=40)),\r
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+        ))\r
+        db.send_create_signal('forum', ['AnonymousQuestion'])\r
+\r
+        # Adding model 'AnonymousAnswer'\r
+        db.create_table('forum_anonymousanswer', (\r
+            ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+            ('ip_addr', self.gf('django.db.models.fields.IPAddressField')(max_length=15)),\r
+            ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'], null=True)),\r
+            ('text', self.gf('django.db.models.fields.TextField')()),\r
+            ('question', self.gf('django.db.models.fields.related.ForeignKey')(related_name='anonymous_answers', to=orm['forum.Question'])),\r
+            ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+            ('summary', self.gf('django.db.models.fields.CharField')(max_length=180)),\r
+            ('session_key', self.gf('django.db.models.fields.CharField')(max_length=40)),\r
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+        ))\r
+        db.send_create_signal('forum', ['AnonymousAnswer'])\r
+\r
+        # Deleting model 'AnonymousNode'\r
+        db.delete_table('forum_anonymousnode')\r
+    \r
+    \r
+    models = {\r
+        'auth.group': {\r
+            'Meta': {'object_name': 'Group'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+        },\r
+        'auth.permission': {\r
+            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+        },\r
+        'auth.user': {\r
+            'Meta': {'object_name': 'User'},\r
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+        },\r
+        'contenttypes.contenttype': {\r
+            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+        },\r
+        'forum.activity': {\r
+            'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+            'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.anonymousnode': {\r
+            'Meta': {'object_name': 'AnonymousNode', '_ormbases': ['forum.Node']},\r
+            'convertible_to': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'validation_hash': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_content'", 'to': "orm['forum.Node']"})\r
+        },\r
+        'forum.answer': {\r
+            'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+            'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.authkeyuserassociation': {\r
+            'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.award': {\r
+            'Meta': {'unique_together': "(('content_type', 'object_id', 'user', 'badge'),)", 'object_name': 'Award', 'db_table': "u'award'"},\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+            'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.comment': {\r
+            'Meta': {'object_name': 'Comment', 'db_table': "u'comment'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'comment': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_comments'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'liked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'comments_liked'", 'through': "'LikedComment'", 'to': "orm['forum.User']"}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.favoritequestion': {\r
+            'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.flaggeditem': {\r
+            'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.keyvalue': {\r
+            'Meta': {'object_name': 'KeyValue'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'value': ('forum.models.utils.PickledObjectField', [], {})\r
+        },\r
+        'forum.likedcomment': {\r
+            'Meta': {'object_name': 'LikedComment'},\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'comment': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Comment']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.markedtag': {\r
+            'Meta': {'object_name': 'MarkedTag'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.node': {\r
+            'Meta': {'object_name': 'Node'},\r
+            'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.noderevision': {\r
+            'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+            'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+            'body': ('django.db.models.fields.TextField', [], {}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+            'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+            'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+        },\r
+        'forum.question': {\r
+            'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+            'answer_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+            'favourite_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'to': "orm['forum.User']"}),\r
+            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True'}),\r
+            'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscriptions'", 'through': "'QuestionSubscription'", 'to': "orm['forum.User']"}),\r
+            'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        },\r
+        'forum.questionsubscription': {\r
+            'Meta': {'object_name': 'QuestionSubscription'},\r
+            'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 14, 18, 42, 39, 311000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.repute': {\r
+            'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.subscriptionsettings': {\r
+            'Meta': {'object_name': 'SubscriptionSettings'},\r
+            'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+            'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+            'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+            'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.tag': {\r
+            'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+        },\r
+        'forum.user': {\r
+            'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+            'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+            'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+            'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+            'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+            'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+            'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+        },\r
+        'forum.validationhash': {\r
+            'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+            'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 15, 18, 42, 39, 525000)'}),\r
+            'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.vote': {\r
+            'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+            'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+        }\r
+    }\r
+    \r
+    complete_apps = ['forum']\r
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01fd2df0f351f7385e6d5dc5d599dc3c224ab78e 100644 (file)
@@ -0,0 +1,16 @@
+import sys\r
+\r
+class ProgressBar(object):\r
+    def __init__(self, full):\r
+        self.full = full\r
+        self.count = 0\r
+\r
+        self.print_bar(0)\r
+\r
+    def print_bar(self, progress):\r
+        sys.stdout.write("[%s%s] %d%%\r" % ('=' * progress, ' ' * (100 - progress), progress))\r
+        sys.stdout.flush()\r
+\r
+    def update(self):\r
+        self.count += 1\r
+        self.print_bar(int((float(self.count) / float(self.full)) * 100))
\ No newline at end of file
index ef1e84b95ec8dbbf9086c49235aa9c2bcc8df6f3..e8353077b8b6ed327a62bd9a94e1895f63e3920b 100644 (file)
@@ -1,9 +1,10 @@
-from question import Question ,QuestionRevision, AnonymousQuestion, FavoriteQuestion, QuestionSubscription\r
-from answer import Answer, AnonymousAnswer, AnswerRevision\r
+from question import Question ,QuestionRevision, FavoriteQuestion, QuestionSubscription\r
+from answer import Answer, AnswerRevision\r
 from tag import Tag, MarkedTag\r
 from meta import Vote, Comment, FlaggedItem, LikedComment\r
 from user import User, Activity, ValidationHash, AuthKeyUserAssociation, SubscriptionSettings\r
 from repute import Badge, Award, Repute\r
+from node import Node, NodeRevision, NodeMetaClass, AnonymousNode\r
 from utils import KeyValue\r
 \r
 try:\r
@@ -23,8 +24,9 @@ def is_new(sender, instance, **kwargs):
 pre_save.connect(is_new)\r
 \r
 __all__ = [\r
-        'Question', 'QuestionRevision', 'FavoriteQuestion', 'AnonymousQuestion', 'QuestionSubscription',\r
-        'Answer', 'AnswerRevision', 'AnonymousAnswer',\r
+        'Node', 'NodeRevision', 'AnonymousNode', \r
+        'Question', 'FavoriteQuestion', 'QuestionSubscription', 'QuestionRevision',\r
+        'Answer', 'AnswerRevision',\r
         'Tag', 'Comment', 'Vote', 'FlaggedItem', 'MarkedTag', 'LikedComment', 'Badge', 'Award', 'Repute',\r
         'Activity', 'ValidationHash', 'AuthKeyUserAssociation', 'SubscriptionSettings', 'KeyValue', 'User',\r
         ]\r
@@ -36,3 +38,5 @@ for k, v in get_modules_script_classes('models', models.Model).items():
     if not k in __all__:\r
         __all__.append(k)\r
         exec "%s = v" % k\r
+\r
+NodeMetaClass.setup_relations()
\ No newline at end of file
index 85d671a8cadc1afd7b422daf71462b62aa95fab5..bac79af3894863d5e7dc0cd3cf6b9bc0c7c6258d 100644 (file)
@@ -2,49 +2,18 @@ from base import *
 
 from question import Question
 
-class AnswerManager(CachedManager):
-    def create_new(self, question=None, author=None, added_at=None, wiki=False, text='', email_notify=False):
-        answer = Answer(
-            question = question,
-            author = author,
-            added_at = added_at,
-            wiki = wiki,
-            html = text
-        )
-        if answer.wiki:
-            answer.last_edited_by = answer.author
-            answer.last_edited_at = added_at
-            answer.wikified_at = added_at
-
-        answer.save()
-
-        #update question data
-        question.last_activity_at = added_at
-        question.last_activity_by = author
-        question.save()
-
-        AnswerRevision.objects.create(
-            answer     = answer,
-            revision   = 1,
-            author     = author,
-            revised_at = added_at,
-            summary    = CONST['default_version'],
-            text       = text
-        )
-
-
-class Answer(Content):
-    question = models.ForeignKey('Question', related_name='answers')
+class Answer(QandA):
     accepted    = models.BooleanField(default=False)
     accepted_at = models.DateTimeField(null=True, blank=True)
     accepted_by = models.ForeignKey(User, null=True)
 
-
-    objects = AnswerManager()
-
-    class Meta(Content.Meta):
+    class Meta(QandA.Meta):
         db_table = u'answer'
 
+    @property
+    def headline(self):
+        return self.question.headline
+
     def mark_accepted(self, user):
         if not self.accepted and not self.question.answer_accepted:
             self.accepted = True
@@ -71,6 +40,10 @@ class Answer(Content):
         self.question.answer_count = self.question.answer_count + diff
         self.question.save()
 
+    def activate_revision(self, user, revision):
+        super(Answer, self).activate_revision(user, revision)
+        self.question.update_last_activity(user)
+
     def mark_deleted(self, user):
         if super(Answer, self).mark_deleted(user):
             self._update_question_answer_count(-1)
@@ -98,35 +71,6 @@ class Answer(Content):
         return self.html
         
 
-class AnswerRevision(ContentRevision):
-    """A revision of an Answer."""
-    answer     = models.ForeignKey('Answer', related_name='revisions')
-
-    def get_absolute_url(self):
-        return reverse('answer_revisions', kwargs={'id':self.answer.id})
-
-    def get_question_title(self):
-        return self.answer.question.title
-
-    class Meta(ContentRevision.Meta):
-        db_table = u'answer_revision'
-        ordering = ('-revision',)
-
-    def save(self, *args, **kwargs):
-        """Looks up the next available revision number if not set."""
-        if not self.revision:
-            self.revision = AnswerRevision.objects.filter(
-                answer=self.answer).values_list('revision',
-                                                flat=True)[0] + 1
-        super(AnswerRevision, self).save(*args, **kwargs)
-
-class AnonymousAnswer(AnonymousContent):
-    question = models.ForeignKey('Question', related_name='anonymous_answers')
-
-    def publish(self,user):
-        added_at = datetime.datetime.now()
-        #print user.id
-        Answer.objects.create_new(question=self.question,wiki=self.wiki,
-                            added_at=added_at,text=self.text,
-                            author=user)
-        self.delete()
+class AnswerRevision(NodeRevision):
+    class Meta:
+        proxy = True
\ No newline at end of file
index 63ab1eb16b1d8761781bf513e5b458d357f46c15..13eae2279e13bebe4774f01c8c88c4696fb7efa6 100644 (file)
@@ -86,7 +86,7 @@ class UndeletedObjectManager(models.Manager):
     def get_query_set(self):
         return super(UndeletedObjectManager, self).get_query_set().filter(deleted=False)
 
-class MetaContent(BaseModel):
+class GenericContent(BaseModel):
     """
         Base class for Vote, Comment and FlaggedItem
     """
@@ -98,6 +98,24 @@ class MetaContent(BaseModel):
         abstract = True
         app_label = 'forum'
 
+class MetaContent(BaseModel):
+    node = models.ForeignKey('Node', null=True, related_name='%(class)ss')
+
+    def __init__(self, *args, **kwargs):
+        if 'content_object' in kwargs:
+            kwargs['node'] = kwargs['content_object']
+            del kwargs['content_object']
+
+        super (MetaContent, self).__init__(*args, **kwargs)
+    
+    @property
+    def content_object(self):
+        return self.node.leaf
+
+    class Meta:
+        abstract = True
+        app_label = 'forum'
+
 from user import User
 
 class UserContent(models.Model):
@@ -141,77 +159,26 @@ class DeletableContent(models.Model):
             return False
 
 
-class ContentRevision(models.Model):
-    """
-        Base class for QuestionRevision and AnswerRevision
-    """
-    revision   = models.PositiveIntegerField()
-    author     = models.ForeignKey(User, related_name='%(class)ss')
-    revised_at = models.DateTimeField()
-    summary    = models.CharField(max_length=300, blank=True)
-    text       = models.TextField()
-
-    class Meta:
-        abstract = True
-        app_label = 'forum'
-
-
-class AnonymousContent(models.Model):
-    """
-        Base class for AnonymousQuestion and AnonymousAnswer
-    """
-    session_key = models.CharField(max_length=40)  #session id for anonymous questions
-    wiki = models.BooleanField(default=False)
-    added_at = models.DateTimeField(default=datetime.datetime.now)
-    ip_addr = models.IPAddressField(max_length=21) #allow high port numbers
-    author = models.ForeignKey(User,null=True)
-    text = models.TextField()
-    summary = models.CharField(max_length=180)
-
-    class Meta:
-        abstract = True
-        app_label = 'forum'
-
-
 from meta import Comment, Vote, FlaggedItem
-from user import activity_record
-
-class Content(BaseModel, DeletableContent):
-    """
-        Base class for Question and Answer
-    """
-    author               = models.ForeignKey(User, related_name='%(class)ss')
-    added_at             = models.DateTimeField(default=datetime.datetime.now)
+from node import Node, NodeRevision
 
+class QandA(Node):
     wiki                 = models.BooleanField(default=False)
     wikified_at          = models.DateTimeField(null=True, blank=True)
 
-    #locked               = models.BooleanField(default=False)
-    #locked_by            = models.ForeignKey(User, null=True, blank=True, related_name='locked_%(class)ss')
-    #locked_at            = models.DateTimeField(null=True, blank=True)
-
-    score                = models.IntegerField(default=0)
-    vote_up_count        = models.IntegerField(default=0)
-    vote_down_count      = models.IntegerField(default=0)
-
-    comment_count        = models.PositiveIntegerField(default=0)
-    offensive_flag_count = models.SmallIntegerField(default=0)
-
-    last_edited_at       = models.DateTimeField(null=True, blank=True)
-    last_edited_by       = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_%(class)ss')
-
-    html                 = models.TextField()
-    comments             = generic.GenericRelation(Comment)
-    votes                = generic.GenericRelation(Vote)
-    flagged_items        = generic.GenericRelation(FlaggedItem)
-
     class Meta:
         abstract = True
         app_label = 'forum'
 
+    def wikify(self):
+        if not self.wiki:
+            self.wiki = True
+            self.wikified_at = datetime.datetime.now()
+            self.save()
+
     def save(self, *args, **kwargs):
         self.__dict__['score'] = self.__dict__['vote_up_count'] - self.__dict__['vote_down_count']
-        super(Content,self).save(*args, **kwargs)
+        super(QandA,self).save(*args, **kwargs)
 
         try:
             ping_google()
@@ -219,16 +186,4 @@ class Content(BaseModel, DeletableContent):
             logging.debug('problem pinging google did you register you sitemap with google?')
 
 
-    def post_get_last_update_info(self):
-            when = self.added_at
-            who = self.author
-            if self.last_edited_at and self.last_edited_at > when:
-                when = self.last_edited_at
-                who = self.last_edited_by
-            comments = self.comments.all()
-            if len(comments) > 0:
-                for c in comments:
-                    if c.added_at > when:
-                        when = c.added_at
-                        who = c.user
-            return when, who
\ No newline at end of file
+
index 538d6a210265f4c895bf156507cc1f67437b613e..7e8213786f211dacb25bdc6840d10be2d6693d6e 100644 (file)
@@ -22,7 +22,7 @@ class Vote(MetaContent, UserContent):
         return '[%s] voted at %s: %s' %(self.user, self.voted_at, self.vote)
 
     def _update_post_vote_count(self, diff):
-        post = self.content_object
+        post = self.node
         field = self.vote == 1 and 'vote_up_count' or 'vote_down_count'
         post.__dict__[field] = post.__dict__[field] + diff
         post.save()
@@ -62,7 +62,7 @@ class FlaggedItem(MetaContent, UserContent):
         return '[%s] flagged at %s' %(self.user, self.flagged_at)
 
     def _update_post_flag_count(self, diff):
-        post = self.content_object
+        post = self.node
         post.offensive_flag_count = post.offensive_flag_count + diff
         post.save()
 
@@ -89,7 +89,7 @@ class Comment(MetaContent, UserContent, DeletableContent):
         db_table = u'comment'
 
     def _update_post_comment_count(self, diff):
-        post = self.content_object
+        post = self.node.leaf
         post.comment_count = post.comment_count + diff
         post.save()
 
diff --git a/forum/models/node.py b/forum/models/node.py
new file mode 100644 (file)
index 0000000..932452d
--- /dev/null
@@ -0,0 +1,199 @@
+from base import *\r
+from tag import Tag\r
+\r
+import markdown\r
+from django.utils.safestring import mark_safe\r
+from django.utils.html import strip_tags\r
+from forum.utils.html import sanitize_html\r
+\r
+class NodeContent(models.Model):\r
+    title      = models.CharField(max_length=300)\r
+    tagnames   = models.CharField(max_length=125)\r
+    author     = models.ForeignKey(User, related_name='%(class)ss')\r
+    body       = models.TextField()\r
+\r
+    @property\r
+    def html(self):\r
+        return mark_safe(sanitize_html(markdown.markdown(self.body)))\r
+\r
+    @property\r
+    def headline(self):\r
+        return self.title\r
+\r
+    @property\r
+    def summary(self):\r
+        return strip_tags(self.html)[:300]\r
+\r
+    def tagname_list(self):\r
+        if self.tagnames:\r
+            return [name for name in self.tagnames.split(u' ')]\r
+        else:\r
+            return []\r
+\r
+    def tagname_meta_generator(self):\r
+        return u','.join([unicode(tag) for tag in self.tagname_list()])\r
+\r
+    class Meta:\r
+        abstract = True\r
+        app_label = 'forum'\r
+\r
+class NodeMetaClass(models.Model.__metaclass__):\r
+    types = {}\r
+\r
+    def __new__(cls, *args, **kwargs):\r
+        new_cls = super(NodeMetaClass, cls).__new__(cls, *args, **kwargs)\r
+\r
+        if not new_cls._meta.abstract and new_cls.__name__ is not 'Node':\r
+            NodeMetaClass.types[new_cls.__name__.lower()] = new_cls\r
+\r
+        return new_cls\r
+\r
+    @classmethod\r
+    def setup_relations(cls):\r
+        for node_cls in NodeMetaClass.types.values():\r
+            NodeMetaClass.setup_relation(node_cls)        \r
+\r
+    @classmethod\r
+    def setup_relation(cls, node_cls):\r
+        name = node_cls.__name__.lower()\r
+\r
+        def children(self):\r
+            return node_cls.objects.filter(parent=self)\r
+\r
+        def parent(self):\r
+            p = self.__dict__.get('_%s_cache' % name, None)\r
+\r
+            if p is None:\r
+                try:\r
+                    p = self.parent.leaf\r
+                    self.__dict__['_%s_cache' % name] = p\r
+                except Exception, e:\r
+                    pass\r
+\r
+            return p\r
+\r
+        Node.add_to_class(name + 's', property(children))\r
+        Node.add_to_class(name, property(parent))\r
+\r
+\r
+class Node(BaseModel, NodeContent, DeletableContent):\r
+    __metaclass__ = NodeMetaClass\r
+\r
+    node_type            = models.CharField(max_length=16, default='node')\r
+    parent               = models.ForeignKey('Node', related_name='children', null=True)\r
+\r
+    added_at             = models.DateTimeField(default=datetime.datetime.now)\r
+\r
+    tags                 = models.ManyToManyField('Tag', related_name='%(class)ss')\r
+\r
+    score                 = models.IntegerField(default=0)\r
+    vote_up_count         = models.IntegerField(default=0)\r
+    vote_down_count       = models.IntegerField(default=0)\r
+\r
+    comment_count        = models.PositiveIntegerField(default=0)\r
+    offensive_flag_count  = models.SmallIntegerField(default=0)\r
+\r
+    last_edited_at        = models.DateTimeField(null=True, blank=True)\r
+    last_edited_by        = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_%(class)ss')\r
+\r
+    active_revision       = models.OneToOneField('NodeRevision', related_name='active', null=True)\r
+\r
+    @property\r
+    def leaf(self):\r
+        return NodeMetaClass.types[self.node_type].objects.get(id=self.id)\r
+\r
+    def create_revision(self, user, **kwargs):\r
+        revision = NodeRevision(author=user, **kwargs)\r
+        \r
+        if not self.id:\r
+            self.author = user\r
+            self.save()\r
+            revision.revision = 1\r
+        else:\r
+            revision.revision = self.revisions.aggregate(last=models.Max('revision'))['last'] + 1\r
+\r
+        revision.node_id = self.id\r
+        revision.save()\r
+        self.activate_revision(user, revision)\r
+\r
+    def activate_revision(self, user, revision):\r
+        self.title = revision.title\r
+        self.tagnames = revision.tagnames\r
+        self.body = revision.body\r
+        \r
+        self.last_edited_at = datetime.datetime.now()\r
+        self.last_edited_by = user\r
+\r
+        self.active_revision = revision\r
+        self.save()\r
+\r
+    def get_tag_list_if_changed(self):\r
+        dirty = self.get_dirty_fields()\r
+\r
+        if 'tagnames' in dirty:\r
+            new_tags = self.tagname_list()\r
+            old_tags = dirty['tagnames']\r
+\r
+            if old_tags is None or not old_tags:\r
+                old_tags = []\r
+            else:\r
+                old_tags = [name for name in dirty['tagnames'].split(u' ')]\r
+\r
+            tag_list = []\r
+\r
+            for name in new_tags:\r
+                try:\r
+                    tag = Tag.objects.get(name=name)\r
+                except:\r
+                    tag = Tag.objects.create(name=name, created_by=self.last_edited_by or self.author)\r
+\r
+                tag_list.append(tag)\r
+\r
+                if not name in old_tags:\r
+                    tag.used_count = tag.used_count + 1\r
+                    if tag.deleted:\r
+                        tag.unmark_deleted()\r
+                    tag.save()\r
+\r
+            for name in [n for n in old_tags if not n in new_tags]:\r
+                tag = Tag.objects.get(name=name)\r
+                tag.used_count = tag.used_count - 1\r
+                if tag.used_count == 0:\r
+                    tag.mark_deleted(self.last_edited_by or self.author)\r
+                tag.save()\r
+\r
+            return tag_list\r
+\r
+        return None\r
+\r
+    def save(self, *args, **kwargs):\r
+        if not self.id:\r
+            self.node_type = self.__class__.__name__.lower()\r
+            \r
+        tags = self.get_tag_list_if_changed()\r
+        super(Node, self).save(*args, **kwargs)\r
+        if tags is not None: self.tags = tags\r
+\r
+    class Meta:\r
+        app_label = 'forum'\r
+\r
+\r
+class NodeRevision(NodeContent):\r
+    node       = models.ForeignKey(Node, related_name='revisions')\r
+    summary    = models.CharField(max_length=300)\r
+    revision   = models.PositiveIntegerField()\r
+    revised_at = models.DateTimeField(default=datetime.datetime.now)\r
+\r
+    class Meta:\r
+        unique_together = ('node', 'revision')\r
+        app_label = 'forum'\r
+\r
+\r
+from user import ValidationHash\r
+\r
+class AnonymousNode(Node):\r
+    validation_hash = models.ForeignKey(Node, related_name='anonymous_content')\r
+    convertible_to = models.CharField(max_length=16, default='node')\r
+\r
+    class Meta:\r
+        app_label = 'forum'
\ No newline at end of file
index 90bbdff0f5038b8d5bf1fe2bd59cb6e5ca9ad0cd..3bf517c6bedbd09903d76660166d4aa054e38710 100644 (file)
@@ -1,51 +1,15 @@
 from base import *
 from tag import Tag
-
-class QuestionManager(CachedManager):
-    def create_new(self, title=None,author=None,added_at=None, wiki=False,tagnames=None,summary=None, text=None):
-
-        question = Question(
-            title            = title,
-            author           = author,
-            added_at         = added_at,
-            last_activity_at = added_at,
-            last_activity_by = author,
-            wiki             = wiki,
-            tagnames         = tagnames,
-            html             = text,
-            summary          = summary
-        )
-        if question.wiki:
-            question.last_edited_by = question.author
-            question.last_edited_at = added_at
-            question.wikified_at = added_at
-
-        question.save()
-
-        # create the first revision
-        QuestionRevision.objects.create(
-            question   = question,
-            revision   = 1,
-            title      = question.title,
-            author     = author,
-            revised_at = added_at,
-            tagnames   = question.tagnames,
-            summary    = CONST['default_version'],
-            text       = text
-        )
-        return question
+from django.utils.translation import ugettext as _
 
 question_view = django.dispatch.Signal(providing_args=['instance', 'user'])
 
-class Question(Content):
-    title    = models.CharField(max_length=300)
-    tags     = models.ManyToManyField(Tag, related_name='questions')
+class Question(QandA):
     answer_accepted = models.BooleanField(default=False)
     closed          = models.BooleanField(default=False)
     closed_by       = models.ForeignKey(User, null=True, blank=True, related_name='closed_questions')
     closed_at       = models.DateTimeField(null=True, blank=True)
     close_reason    = models.SmallIntegerField(choices=CLOSE_REASONS, null=True, blank=True)
-    followed_by     = models.ManyToManyField(User, related_name='followed_questions')
     subscribers     = models.ManyToManyField(User, related_name='subscriptions', through='QuestionSubscription')
 
     # Denormalised data
@@ -54,16 +18,22 @@ class Question(Content):
     favourite_count      = models.IntegerField(default=0)
     last_activity_at     = models.DateTimeField(default=datetime.datetime.now)
     last_activity_by     = models.ForeignKey(User, related_name='last_active_in_questions')
-    tagnames             = models.CharField(max_length=125)
-    summary              = models.CharField(max_length=180)
-
-    favorited_by         = models.ManyToManyField(User, through='FavoriteQuestion', related_name='favorite_questions') 
 
-    objects = QuestionManager()
+    favorited_by         = models.ManyToManyField(User, through='FavoriteQuestion', related_name='favorite_questions')
 
-    class Meta(Content.Meta):
+    class Meta(QandA.Meta):
         db_table = u'question'
 
+    @property
+    def headline(self):
+        if self.closed:
+            return _('[closed] ') + self.title
+
+        if self.deleted:
+            return _('[deleted] ') + self.title
+
+        return self.title
+
     def delete(self):
         super(Question, self).delete()
         try:
@@ -71,56 +41,14 @@ class Question(Content):
         except Exception:
             logging.debug('problem pinging google did you register you sitemap with google?')
 
-    def get_tag_list_if_changed(self):
-        dirty = self.get_dirty_fields()
-
-        if 'tagnames' in dirty:
-            new_tags = self.tagname_list()
-
-            old_tags = dirty['tagnames']
-            if old_tags is None:
-                old_tags = []
-            else:
-                old_tags = [name for name in dirty['tagnames'].split(u' ')]
-
-            tag_list = []
-
-            for name in new_tags:
-                try:
-                    tag = Tag.objects.get(name=name)
-                except:
-                    tag = Tag.objects.create(name=name, created_by=self.last_edited_by or self.author)
-
-                tag_list.append(tag)
-
-                if not name in old_tags:
-                    tag.used_count = tag.used_count + 1
-                    if tag.deleted:
-                        tag.unmark_deleted()
-                    tag.save()
-
-            for name in [n for n in old_tags if not n in new_tags]:
-                tag = Tag.objects.get(name=name)
-                tag.used_count = tag.used_count - 1
-                if tag.used_count == 0:
-                    tag.mark_deleted(self.last_edited_by or self.author)
-                tag.save()
-
-            return tag_list
-
-        return None
-
-    def save(self, *args, **kwargs):
-        tags = self.get_tag_list_if_changed()
-        super(Question, self).save(*args, **kwargs)
-        if not tags is None: self.tags = tags
-
-    def tagname_list(self):
-        """Creates a list of Tag names from the ``tagnames`` attribute."""
-        return [name for name in self.tagnames.split(u' ')]
+    def update_last_activity(self, user):
+        self.last_activity_by = user
+        self.last_activity_at = datetime.datetime.now()
+        self.save()
 
-    def tagname_meta_generator(self):
-        return u','.join([unicode(tag) for tag in self.tagname_list()])
+    def activate_revision(self, user, revision):
+        super(Question, self).activate_revision(user, revision)
+        self.update_last_activity(user)
 
     @models.permalink    
     def get_absolute_url(self):
@@ -149,19 +77,6 @@ class Question(Content):
     def get_latest_revision(self):
         return self.revisions.all()[0]
 
-    def get_last_update_info(self):
-        when, who = self.post_get_last_update_info()
-
-        answers = self.answers.all()
-        if len(answers) > 0:
-            for a in answers:
-                a_when, a_who = a.post_get_last_update_info()
-                if a_when > when:
-                    when = a_when
-                    who = a_who
-
-        return when, who
-
     def get_related_questions(self, count=10):
         cache_key = '%s.related_questions:%d:%d' % (settings.APP_URL, count, self.id)
         related_list = cache.get(cache_key)
@@ -183,7 +98,6 @@ def question_viewed(instance, **kwargs):
 question_view.connect(question_viewed)
 
 class FavoriteQuestion(models.Model):
-    """A favorite Question of a User."""
     question      = models.ForeignKey('Question')
     user          = models.ForeignKey(User, related_name='user_favorite_questions')
     added_at      = models.DateTimeField(default=datetime.datetime.now)
@@ -218,43 +132,8 @@ class QuestionSubscription(models.Model):
     class Meta:
         app_label = 'forum'
 
-class QuestionRevision(ContentRevision):
-    """A revision of a Question."""
-    question   = models.ForeignKey(Question, related_name='revisions')
-    title      = models.CharField(max_length=300)
-    tagnames   = models.CharField(max_length=125)
 
-    class Meta(ContentRevision.Meta):
-        db_table = u'question_revision'
-        ordering = ('-revision',)
-
-    def get_question_title(self):
-        return self.question.title
-
-    def get_absolute_url(self):
-        #print 'in QuestionRevision.get_absolute_url()'
-        return reverse('question_revisions', args=[self.question.id])
-
-    def save(self, *args, **kwargs):
-        """Looks up the next available revision number."""
-        if not self.revision:
-            self.revision = QuestionRevision.objects.filter(
-                question=self.question).values_list('revision',
-                                                    flat=True)[0] + 1
-        super(QuestionRevision, self).save(*args, **kwargs)
-
-    def __unicode__(self):
-        return u'revision %s of %s' % (self.revision, self.title)
-
-class AnonymousQuestion(AnonymousContent):
-    title = models.CharField(max_length=300)
-    tagnames = models.CharField(max_length=125)
-
-    def publish(self,user):
-        added_at = datetime.datetime.now()
-        Question.objects.create_new(title=self.title, author=user, added_at=added_at,
-                                wiki=self.wiki, tagnames=self.tagnames,
-                                summary=self.summary, text=self.text)
-        self.delete()
-
-from answer import Answer, AnswerManager
+class QuestionRevision(NodeRevision):
+    class Meta:
+        proxy = True
+        
index 6d023adf5ee3d366d62256cff25789868a4a6fc7..40943514a40ba09800ced2c350c6ba18ff8fa4c7 100644 (file)
@@ -55,7 +55,7 @@ class AwardManager(models.Manager):
         ).values('badge_id', 'badge_name', 'badge_description', 'badge_type', 'user_id', 'user_name')
         return awards
 
-class Award(MetaContent, UserContent):
+class Award(GenericContent, UserContent):
     """The awarding of a Badge to a User."""
     badge      = models.ForeignKey('Badge', related_name='award_badge')
     awarded_at = models.DateTimeField(default=datetime.datetime.now)
index 655e17e864a51377f62fda4c6a64369b24e45760..536663143a8851bd5f716c0d7701558a7f8d8cb1 100644 (file)
@@ -216,7 +216,7 @@ class User(BaseModel, DjangoUser):
     class Meta:\r
         app_label = 'forum'\r
 \r
-class Activity(MetaContent):\r
+class Activity(GenericContent):\r
     """\r
     We keep some history data for user activities\r
     """\r
@@ -238,20 +238,16 @@ class Activity(MetaContent):
             activity_record.send(sender=self.activity_type, instance=self)\r
 \r
     @property\r
-    def question(self):\r
-        if self.activity_type == const.TYPE_ACTIVITY_ASK_QUESTION:\r
-            return self.content_object\r
-        elif self.activity_type in (const.TYPE_ACTIVITY_ANSWER,\r
+    def node(self):\r
+        if self.activity_type in (const.TYPE_ACTIVITY_ANSWER, const.TYPE_ACTIVITY_ASK_QUESTION,\r
                 const.TYPE_ACTIVITY_MARK_ANSWER, const.TYPE_ACTIVITY_UPDATE_QUESTION):\r
-            return self.content_object.question\r
-        elif self.activity_type == const.TYPE_ACTIVITY_COMMENT_QUESTION:\r
-            return self.content_object.content_object\r
-        elif self.activity_type == const.TYPE_ACTIVITY_COMMENT_ANSWER:\r
-            return self.content_object.content_object.question\r
-        elif self.activity_type == const.TYPE_ACTIVITY_UPDATE_ANSWER:\r
-            return self.content_object.content_object.answer.question\r
-        else:\r
-            raise NotImplementedError()\r
+            return self.content_object\r
+\r
+        if self.activity_type in (const.TYPE_ACTIVITY_COMMENT_QUESTION,\r
+                const.TYPE_ACTIVITY_COMMENT_ANSWER, const.TYPE_ACTIVITY_UPDATE_ANSWER):\r
+            return self.content_object.node.leaf\r
+            \r
+        raise NotImplementedError()\r
 \r
     @property\r
     def type_as_string(self):\r
@@ -262,13 +258,15 @@ class Activity(MetaContent):
         elif self.activity_type  == const.TYPE_ACTIVITY_MARK_ANSWER:\r
             return _("marked an answer")\r
         elif self.activity_type  == const.TYPE_ACTIVITY_UPDATE_QUESTION:\r
-            return _("edited")\r
+            return _("edited a question")\r
         elif self.activity_type == const.TYPE_ACTIVITY_COMMENT_QUESTION:\r
-            return _("commented")\r
+            return _("commented a question")\r
         elif self.activity_type == const.TYPE_ACTIVITY_COMMENT_ANSWER:\r
             return _("commented an answer")\r
         elif self.activity_type == const.TYPE_ACTIVITY_UPDATE_ANSWER:\r
             return _("edited an answer")\r
+        elif self.activity_type == const.TYPE_ACTIVITY_PRIZE:\r
+            return _("received badge")\r
         else:\r
             raise NotImplementedError()\r
 \r
index a3ea374a58cf9e5245fcb60c0c508287aa6f2ec1..d929a16fb5a4c515f7771c73f37aea5c9c5922d9 100644 (file)
@@ -1,12 +1,12 @@
 var response_commands = {\r
-    update_post_score: function(type, id, inc) {\r
-        var $score_board = $('#' + type + '-' + id + '-score');\r
+    update_post_score: function(id, inc) {\r
+        var $score_board = $('#post-' + id + '-score');\r
         $score_board.html(parseInt($score_board.html()) + inc)\r
     },\r
 \r
-    update_user_post_vote: function(type, id, vote_type) {\r
-        var $upvote_button = $('#' + type + '-' + id + '-upvote');\r
-        var $downvote_button = $('#' + type + '-' + id + '-downvote');\r
+    update_user_post_vote: function(id, vote_type) {\r
+        var $upvote_button = $('#post-' + id + '-upvote');\r
+        var $downvote_button = $('#post-' + id + '-downvote');\r
 \r
         $upvote_button.removeClass('on');\r
         $downvote_button.removeClass('on');\r
@@ -89,9 +89,9 @@ var response_commands = {
         });\r
     },\r
 \r
-    insert_comment: function(post_type, post_id, comment_id, comment, username, profile_url, delete_url) {\r
-        var $container = $('#comments-container-' + post_type + '-' + post_id);\r
-        var skeleton = $('#new-comment-skeleton-' + post_type + '-' + post_id).html().toString();\r
+    insert_comment: function(post_id, comment_id, comment, username, profile_url, delete_url) {\r
+        var $container = $('#comments-container-' + post_id);\r
+        var skeleton = $('#new-comment-skeleton-' + post_id).html().toString();\r
 \r
         skeleton = skeleton.replace(new RegExp('%ID%', 'g'), comment_id)\r
                 .replace(new RegExp('%COMMENT%', 'g'), comment)\r
index b81e7fa4ad883d0d282244ba148fe403f80ba841..f591d1a0aa21f7428a93aefa690c33ba9f509471 100644 (file)
@@ -1,6 +1,7 @@
 {% extends "base_content.html" %}
 <!-- template about.html -->
 {% load i18n %}
+{% load markup %}
 {% block title %}{% spaceless %}{% trans "About" %}{% endspaceless %}{% endblock %}
 
 {% block content %}
@@ -8,7 +9,7 @@
 {% trans "About" %}
 </div>
 <div class="content">
-{{ text|safe }}
+{{ text|markdown }}
 </div>
 {% endblock %}
 <!-- end template about.html -->
index 1bad79630ac2ad7ccc4e4527f20565361cfcee50..ab8e99d6f99a6048052d36002ec9d1b71de8b7a4 100644 (file)
@@ -24,7 +24,7 @@
             var osqaSkin = '{{settings.OSQA_SKIN}}';
         /* ]] */
         </script>
-        <script type='text/javascript' src='{% media  "/media/js/osqa.main.min.js" %}'></script>
+        <script type='text/javascript' src='{% media  "/media/js/osqa.main.js" %}'></script>
         {% if user_messages %}
         <style type="text/css">
             body { margin-top:2.4em; }
similarity index 85%
rename from forum/skins/default/templates/question/comments.html
rename to forum/skins/default/templates/node/comments.html
index 3c417fa4c84842a099de86feee2d1dcd5241f81e..022f19ca1e3a282298191a7bd73dd13cb3a941f0 100644 (file)
@@ -1,7 +1,7 @@
 {% load extra_tags %}\r
 {% load i18n %}\r
 \r
-<div class="comments-container" id="comments-container-{{ post_type }}-{{ post.id }}">\r
+<div class="comments-container" id="comments-container-{{ post.id }}">\r
     {% for comment in comments %}\r
         <table class="comment{% if not comment.top_scorer %} not_top_scorer{% endif %}" id="comment-{{comment.id}}">\r
             <tr>\r
@@ -34,7 +34,7 @@
         </table>\r
     {% endfor %}\r
 </div>\r
-<div id="comment-tools-{{ post_type }}-{{ post.id }}" class="comment-tools">\r
+<div id="comment-tools-{{ post.id }}" class="comment-tools">\r
     <img src="/m/default/media/images/gray-up-arrow-h18px.png" />\r
     {% ifnotequal showing total %}\r
         <span class="comments-showing">\r
     {% endif %}\r
 </div>\r
 {% if can_comment %}\r
-<div id="comment-{{ post_type }}-{{ post.id }}-form-container" class="comment-form-container">\r
-    <form id="comment-{{ post_type }}-{{ post.id }}-form" method="post" action="{% url comment post_type=post_type,id=post.id %}">\r
+<div id="comment-{{ post.id }}-form-container" class="comment-form-container">\r
+    <form id="comment-{{ post.id }}-form" method="post" action="{% url comment id=post.id %}">\r
         <div class="comment-form-widgets-container">\r
             <textarea name="comment"></textarea>\r
             <input type="submit" value="{% trans " add comment" %}" />\r
         </div>\r
-        <span id="comment-{{ post_type }}-{{ post.id }}-chars-left" class="comment-chars-left">\r
+        <span id="comment-{{ post.id }}-chars-left" class="comment-chars-left">\r
             {% blocktrans %}\r
                 have <span class="comments-char-left-count">{{ max_length }}</span> characters left\r
             {% endblocktrans %}\r
         </span>\r
-        <script type="text/html" class="new-comment-skeleton" id="new-comment-skeleton-{{ post_type }}-{{ post.id }}">\r
+        <script type="text/html" class="new-comment-skeleton" id="new-comment-skeleton-{{ post.id }}">\r
             <table class="comment" id="comment-%ID%" style="display: none">\r
                 <tr>\r
                     <td rowspan="2" class="comment-score" id="comment-%ID%-score"></td>\r
diff --git a/forum/skins/default/templates/node/revision.html b/forum/skins/default/templates/node/revision.html
new file mode 100644 (file)
index 0000000..c189204
--- /dev/null
@@ -0,0 +1,11 @@
+{% spaceless %}\r
+    {% if title %}<h1>{{ title }}</h1>{% endif %}\r
+    <div class="text">{{ html }}</div>\r
+    {% if tags %}\r
+        <div class="tags">\r
+            {% for tag in tags %}\r
+            <a class="post-tag">{{ tag }}</a>\r
+            {% endfor %}\r
+        </div>\r
+    {% endif %}\r
+{% endspaceless %}
\ No newline at end of file
diff --git a/forum/skins/default/templates/node/vote_buttons.html b/forum/skins/default/templates/node/vote_buttons.html
new file mode 100644 (file)
index 0000000..9b95d60
--- /dev/null
@@ -0,0 +1,12 @@
+{% load i18n %}\r
+\r
+<a id="post-{{ post.id }}-upvote" title="{% trans "I like this post (click again to cancel)" %}"\r
+    class="ajax-command post-vote up {% ifequal user_vote "up" %} on{% endifequal %}"\r
+     href="{% url vote_post id=post.id,vote_type='up' %}" rel="nofollow"> </a>\r
+<div id="post-{{ post.id }}-score" class="post-score"\r
+    title="{% trans "current number of votes" %}">\r
+    {{ post.score }}\r
+</div>\r
+<a id="post-{{ post.id }}-downvote" title="{% trans "I dont like this post (click again to cancel)" %}"\r
+    class="ajax-command post-vote down{% ifequal user_vote "down" %} on{% endifequal %}"\r
+     href="{% url vote_post id=post.id,vote_type='down' %}" rel="nofollow"> </a>
\ No newline at end of file
index e9a8bf56ad02432cee420719ba7bb652c3c1721e..5385da65794e7823ef131f64c3e1b1354671cf44 100644 (file)
@@ -1,10 +1,7 @@
 {% extends "osqaadmin/base.html" %}\r
 \r
 {% load i18n %}\r
-\r
-{% block adminjs %}\r
\r
-{% endblock %}\r
+{% load user_tags %}\r
 \r
 {% block subtitle %}\r
     {% trans "Dashboard" %}\r
                 <h3>{% trans "Recent activity" %}</h3>\r
                 <table width="100%">\r
                 {% for activity in recent_activity %}\r
-                <tr>\r
-                    <td>\r
-                        {{ activity.user.get_profile_link }} {{ activity.type_as_string }} {% trans "on" %} <a href="{{ activity.question.get_absolute_url }}">{{ activity.question.title }}</a><br />\r
-                        <sub>{{ activity.active_at|date }}, {{ activity.active_at|time }}</sub>\r
-                    </td>\r
-                </tr>\r
+                    {% activity_item activity %}\r
                 {% endfor %}\r
                 </table>\r
             </td>\r
index d878fb04cad9deb8d8b4d973164c12c0028f2279..7a265c6370f318be29cd4e1355458df72a262da5 100644 (file)
@@ -1,6 +1,6 @@
 {% extends "base.html" %}\r
 <!-- question.html -->\r
-{% load question_page_tags %}\r
+{% load node_tags %}\r
 {% load extra_tags %}\r
 {% load extra_filters %}\r
 {% load smart_if %}\r
diff --git a/forum/skins/default/templates/question/vote_buttons.html b/forum/skins/default/templates/question/vote_buttons.html
deleted file mode 100644 (file)
index 78dfd0b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{% load i18n %}\r
-\r
-<a id="{{ post_type }}-{{ post.id }}-upvote" title="{% trans "I like this post (click again to cancel)" %}"\r
-    class="ajax-command post-vote up {% ifequal user_vote "up" %} on{% endifequal %}"\r
-     href="{% url vote_post post_type=post_type,id=post.id,vote_type='up' %}" rel="nofollow"> </a>\r
-<div id="{{ post_type }}-{{ post.id }}-score" class="post-score"\r
-    title="{% trans "current number of votes" %}">\r
-    {{ post.score }}\r
-</div>\r
-<a id="{{ post_type }}-{{ post.id }}-downvote" title="{% trans "I dont like this post (click again to cancel)" %}"\r
-    class="ajax-command post-vote down{% ifequal user_vote "down" %} on{% endifequal %}"\r
-     href="{% url vote_post post_type=post_type,id=post.id,vote_type='down' %}" rel="nofollow"> </a>
\ No newline at end of file
index e57391415ca4bfaab31db9ada2afdfbaa5c96055..e4998488d35816d89c946697ec5480e176a1901a 100644 (file)
@@ -9,7 +9,7 @@
             <div class="item-count">{{question.score|intcomma}}</div>\r
             <div>{% trans "votes" %}</div>\r
         </div >\r
-        <div {% if question.answer_accepted %}title="{% trans "this answer has been accepted to be correct" %}"{% endif %} class="status {% if question.answer_accepted %}answered-accepted{% endif %} {% ifequal question.answer_count 0 %}unanswered{% endifequal %}{% ifnotequal question.answer_count 0 %}answered{% endifnotequal %}">\r
+        <div {% if question.answer_accepted %}title="{% trans "this question has an accepted answer" %}"{% endif %} class="status {% if question.answer_accepted %}answered-accepted{% endif %} {% ifequal question.answer_count 0 %}unanswered{% endifequal %}{% ifnotequal question.answer_count 0 %}answered{% endifnotequal %}">\r
             <div class="item-count">{{question.answer_count|intcomma}}</div>\r
             <div>{% trans "answers" %}</div>\r
         </div>\r
@@ -19,7 +19,7 @@
         </div>\r
     </div>\r
 \r
-    <h2><a title="{{question.summary.split|join:" "}}" href="{{ question.get_absolute_url }}">{{question.title}}</a></h2>\r
+    <h2><a title="{{ question.summary }}" href="{{ question.get_absolute_url }}">{{question.headline}}</a></h2>\r
     <div class="userinfo">\r
         <span class="relativetime" title="{{question.last_activity_at}}">{% diff_date question.last_activity_at %}</span>\r
         {% if question.last_activity_by %}{% user_signature question.last_activity_by signature_type %}{% endif %}\r
index 0cda6d45938c93d8cc1ac43eb6a22e81f9b4e821..3d0747874fdae32e31c1764dfdfc76172faee264 100644 (file)
@@ -1,6 +1,5 @@
 {% extends "base_content.html" %}
-<!-- revisions_question.html -->
-<!--somehow very similar to revisions_answer.html-->
+
 {% load extra_tags %}
 {% load i18n %}
 {% load extra_filters %}
@@ -39,7 +38,7 @@
     <div id="revisions">
     {% for revision in revisions %}
       <div class="revision">
-        <div id="rev-header-{{ revision.revision }}" class="header {% ifequal post.author_id revision.author_id %}author{% endifequal %}">
+        <div id="rev-header-{{ revision.inst.revision }}" class="header {% ifequal post.author revision.inst.author %}author{% endifequal %}">
           <div class="header-controls">
             <table width="100%">
                 <tr>
                                                                 src="{% media  "/media/images/expander-arrow-show.gif" %}"
                                                                 alt="{% trans "click to hide/show revision" %}"/>
                     </td>
-                    <td width="30px" style="vertical-align:middle"><span class="revision-number" title="{% trans "revision" %} {{ revision.revision }}">{{ revision.revision }}</span></td>
+                    <td width="30px" style="vertical-align:middle"><span class="revision-number" title="{% trans "revision" %} {{ revision.inst.revision }}">{{ revision.inst.revision }}</span></td>
                     <td width="200px" style="vertical-align:middle">
-                        {% if revision.summary %}
                         <div class="summary"><span>{{ revision.summary }}</span></div>
-                        {% endif %}
-                        {% if request.user|can_edit_post:post %}
-                        <a href="{% url edit_question post.id %}?revision={{ revision.revision }}">{% trans "edit" %}</a>
-                        {% endif %}
-  
                     </td>
                     <td align="right">
                         <div class="revision-mark" >
-                            {% post_contributor_info revision %}
+                            {% post_contributor_info revision.inst %}
                         </div>
                     </td>
                 </tr>
@@ -67,7 +60,7 @@
             </table>
           </div>
         </div>
-        <div id="rev-body-{{ revision.revision }}" class="diff body">
+        <div id="rev-body-{{ revision.inst.revision }}" class="diff body">
             {{ revision.diff|safe }}
         </div>
       </div>
@@ -78,4 +71,3 @@
 
 {% block endjs %}
 {% endblock %}
-<!-- end revisions_question.html -->
index ad71505094ccecb595f546f7cd581ead7c95ae23..c1998f82060582153f94679165e25a7b17e8f8b1 100644 (file)
 {% endblock %}
 {% block content %}
     <div id="mainbar-full">
-        {% include "user_info.html" %}
-        {% include "user_tabs.html" %}
+        {% include "users/info.html" %}
+        {% include "users/tabs.html" %}
         {% block usercontent %}
         {% endblock %}
-        {%comment%}{% include "user_footer.html" %}{%endcomment%}
+        {%comment%}{% include "users/footer.html" %}{%endcomment%}
        </div>
 {% endblock %}<!-- end user.html -->
diff --git a/forum/skins/default/templates/user_email_subscriptions.html b/forum/skins/default/templates/user_email_subscriptions.html
deleted file mode 100644 (file)
index c0204cb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-{% extends "user.html" %}
-<!-- user_email_subscriptions.html -->
-{% load i18n %}
-{% load extra_tags %}
-{% load humanize %}
-
-{% block usercontent %}
-    <h2>{% trans "Email subscription settings" %}</h2>
-    <p class="message">{% trans "email subscription settings info" %}</p>
-    <div class='inline-block'>
-    {% if action_status %}
-    <p class="action-status"><span>{{action_status}}</span></p>
-    {% endif %}
-    <form method="POST"> 
-        {% include "edit_user_email_feeds_form.html" %}
-        <table class='form-as-table'>
-        {{tag_filter_selection_form}}
-        </table>
-        <div class="submit-row text-align-right">
-            <input type="submit" class="submit" name="save" value="{% trans "Update" %}"/>
-            <input type="submit" class="submit" name="stop_email" value="{% trans "Stop sending email" %}"/>
-        </div>
-    </form>
-    </div>
-{% endblock %}
-<!-- end user_email_subscriptions.html -->
diff --git a/forum/skins/default/templates/user_favorites.html b/forum/skins/default/templates/user_favorites.html
deleted file mode 100644 (file)
index 9db01e9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{% extends "user.html" %}
-<!-- user_favorites.html -->
-{% load extra_tags %}
-{% load humanize %}
-{% block usercontent %}
-               {% include "users_questions.html" %}
-{% endblock %}
-<!-- end user_favorites.html -->
diff --git a/forum/skins/default/templates/user_recent.html b/forum/skins/default/templates/user_recent.html
deleted file mode 100644 (file)
index b704ab2..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-{% extends "user.html" %}
-<!-- user_recent.html -->
-{% load extra_tags %}
-{% load humanize %}
-{% block usercontent %}
-        <div style="padding-top:5px;font-size:13px;">
-        {% for act in activities %}
-            <div style="clear:both;line-height:20px" >
-                <div style="width:180px;float:left">{% diff_date act.time 3 %}</div>
-                <div style="width:150px;float:left">
-                <span class="user-action-{{ act.type_id }}">{{ act.type }}</span>
-                </div>
-                <div style="float:left;overflow:hidden;">
-                    {% ifequal act.type_id 7 %}
-                    <a href="{{act.badge.get_absolute_url}}" title="{{ act.badge.get_type_display }} : {{ act.badge.description }}" class="medal"><span class="badge{{ act.badge.type }}">&#9679;</span>&nbsp;{{ act.badge.name }}</a>
-                    {% else %}
-                    <span class="post-type-{{ act.type_id }}"><a href="{{ act.title_link }}">{{ act.title }}</a></span>
-                    {% if act.summary %}<span class="revision-summary">{{ act.summary }}</span>{% endif %}
-                    {% endifequal %}
-                    <div style="height:5px"></div>
-                </div>
-            </div>
-        {% endfor %}
-        </div>
-{% endblock %}
-<!-- end user_recent.html -->
diff --git a/forum/skins/default/templates/user_tabs.html b/forum/skins/default/templates/user_tabs.html
deleted file mode 100644 (file)
index 0248efd..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<!-- user_tabs.html -->
-{% load extra_filters %}
-{% load i18n %}
-<div class="tabBar">
-    <div class="tabsA">
-        <a id="stats" {% ifequal tab_name "stats" %}class="on"{% endifequal %} 
-                       title="{% trans "User profile" %}" href="/users/{{ view_user.id }}/{{ view_user.username|slugify }}/?sort=stats">{% trans "overview" %}</a>
-        <a id="recent" {% ifequal tab_name "recent" %}class="on"{% endifequal %} 
-                       title="{% trans "recent activity" %}" href="/users/{{ view_user.id }}/{{ view_user.username|slugify }}?sort=recent">{% trans "recent activity" %}</a>
-        {% ifequal request.user view_user %}
-        <a id="responses" {% ifequal tab_name "responses" %}class="on"{% endifequal %} 
-                       title="{% trans "comments and answers to others questions" %}" 
-                       href="/users/{{ view_user.id }}/{{ view_user.username|slugify }}?sort=responses">{% trans "responses" %}</a>
-        {% endifequal %}
-        <a id="reputation" {% ifequal tab_name "reputation" %}class="on"{% endifequal %} 
-                       title="{% trans "graph of user reputation" %}" 
-                       href="/users/{{ view_user.id }}/{{ view_user.username|slugify }}?sort=reputation">{% trans "reputation history" %}</a>
-        {% ifequal request.user view_user %}
-        <a id="votes" {% ifequal tab_name "votes" %}class="on"{% endifequal %} 
-                       title="{% trans "user vote record" %}" href="/users/{{ view_user.id }}/{{ view_user.username|slugify }}?sort=votes">{% trans "casted votes" %}</a>
-        {% endifequal %}
-        <a id="favorites" {% ifequal tab_name "favorites" %}class="on"{% endifequal %} 
-                       title="{% trans "questions that user selected as his/her favorite" %}"
-                       href="/users/{{ view_user.id }}/{{ view_user.username|slugify }}?sort=favorites">{% trans "favorites" %}</a>
-        {% ifequal request.user view_user %}
-        <a id="email_subscriptions" {% ifequal tab_name "subscriptions" %}class="on"{% endifequal %} 
-                       title="{% trans "email subscription settings" %}" 
-                       href="/users/{{ view_user.id }}/{{ view_user.username|slugify }}?sort=subscriptions">{% trans "subscriptions" %}</a>
-        {% endifequal %}  
-    </div>
-</div>
-<!-- end user_tabs.html -->
diff --git a/forum/skins/default/templates/users/activity.html b/forum/skins/default/templates/users/activity.html
new file mode 100644 (file)
index 0000000..39aa9bf
--- /dev/null
@@ -0,0 +1,18 @@
+{% load extra_tags %}\r
+{% load humanize %}\r
+\r
+<div style="clear:both;line-height:20px" >\r
+    <div style="width:180px;float:left">{% diff_date active_at 3 %}</div>\r
+    <div style="width:150px;float:left">\r
+    <span class="user-action-{{ type }}">{{ description }}</span>\r
+    </div>\r
+    <div style="float:left;overflow:hidden;">\r
+        {% if badge %}\r
+        <a href="{{ url }}" title="{{ title }}" class="medal"><span class="badge{{ badge_type }}">&#9679;</span>&nbsp;{{ title }}</a>\r
+        {% else %}\r
+        <span class="post-type-{{ type }}"><a href="{{ url }}">{{ title }}</a></span>\r
+            {% if revision %}<span class="revision-summary">{{ summary }}</span>{% endif %}\r
+        {% endif %}\r
+        <div style="height:5px"></div>\r
+    </div>\r
+</div>
\ No newline at end of file
diff --git a/forum/skins/default/templates/users/questions.html b/forum/skins/default/templates/users/questions.html
new file mode 100644 (file)
index 0000000..cff9e84
--- /dev/null
@@ -0,0 +1,11 @@
+{% extends "user.html" %}
+
+{% load extra_tags %}
+{% load question_list_tags %}
+{% block usercontent %}
+<div class="user-stats-table">
+    {% for question in questions %}
+        {% question_list_item question favorite_count=yes signature_type=badges %}
+    {% endfor %}
+</div>
+{% endblock %}
diff --git a/forum/skins/default/templates/users/recent.html b/forum/skins/default/templates/users/recent.html
new file mode 100644 (file)
index 0000000..fc30634
--- /dev/null
@@ -0,0 +1,12 @@
+{% extends "user.html" %}
+
+{% load extra_tags %}
+{% load user_tags %}
+{% block usercontent %}
+        <div style="padding-top:5px;font-size:13px;">
+        {% for act in activities %}
+            {% activity_item act %}   
+        {% endfor %}
+        </div>
+{% endblock %}
+
diff --git a/forum/skins/default/templates/users/tabs.html b/forum/skins/default/templates/users/tabs.html
new file mode 100644 (file)
index 0000000..0e0bfb0
--- /dev/null
@@ -0,0 +1,27 @@
+{% load extra_filters %}
+{% load i18n %}
+{% with view_user.username|slugify as user_slug %}
+<div class="tabBar">
+    <div class="tabsA">
+        <a id="stats" {% ifequal tab_name "stats" %}class="on"{% endifequal %} 
+                       title="{% trans "User profile" %}" href="{% url user_profile id=view_user.id,slug=user_slug %}">{% trans "overview" %}</a>
+        <a id="recent" {% ifequal tab_name "recent" %}class="on"{% endifequal %} 
+                       title="{% trans "recent activity" %}" href="{% url user_recent id=view_user.id,slug=user_slug %}">{% trans "recent activity" %}</a>
+        <a id="reputation" {% ifequal tab_name "reputation" %}class="on"{% endifequal %}
+                       title="{% trans "graph of user reputation" %}" 
+                       href="{% url user_reputation id=view_user.id,slug=user_slug %}">{% trans "reputation history" %}</a>
+        {% ifequal request.user view_user %}
+        <a id="votes" {% ifequal tab_name "votes" %}class="on"{% endifequal %} 
+                       title="{% trans "user vote record" %}" href="{% url user_votes id=view_user.id,slug=user_slug %}">{% trans "casted votes" %}</a>
+        {% endifequal %}
+        <a id="favorites" {% ifequal tab_name "favorites" %}class="on"{% endifequal %} 
+                       title="{% trans "questions that user selected as his/her favorite" %}"
+                       href="{% url user_favorites id=view_user.id,slug=user_slug %}">{% trans "favorites" %}</a>
+        {% ifequal request.user view_user %}
+        <a id="email_subscriptions" {% ifequal tab_name "subscriptions" %}class="on"{% endifequal %} 
+                       title="{% trans "email subscription settings" %}" 
+                       href="{% url user_subscriptions id=view_user.id,slug=user_slug %}">{% trans "subscriptions" %}</a>
+        {% endifequal %}  
+    </div>
+</div>
+{% endwith %}
similarity index 73%
rename from forum/skins/default/templates/user_votes.html
rename to forum/skins/default/templates/users/votes.html
index b402c26039bd3f7e60a010bba4404d1a261cc029..9d187bf221c8e5cedbe1bff6b577f2bf00c50f72 100644 (file)
                 {% endifequal %}
                 </div>
                 <div style="float:left;overflow:hidden;width:750px">
-                    {% ifequal vote.answer_id 0 %}
-                    <span class="question-title-link"><a href="{{ vote.get_absolute_url }}">{{ vote.title }}</a></span>
-                    {% else %}
-                    <span class="answer-title-link" ><a href="{{ vote.get_absolute_url }}#{{ vote.answer_id }}">{{ vote.title }}</a></span>
-                    {% endifequal %}
+                    <span class="{{ vote.node.node_type }}-title-link"><a href="{{ vote.node.leaf.get_absolute_url }}">{{ vote.node.leaf.headline }}</a></span>
                     <div style="height:5px"></div>
                 </div>          
             </div>
diff --git a/forum/skins/default/templates/users_questions.html b/forum/skins/default/templates/users_questions.html
deleted file mode 100644 (file)
index fe1ac45..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-<!-- users_questions.html -->
-{% load extra_tags %}
-{% load extra_filters %}
-{% load humanize %}
-{% load i18n %}
-<div class="user-stats-table">
-    {% for question in questions %}
-        {% if question.favourite_count %}
-            {% if question.favorited_myself %}
-                <div class="favorites-count">
-                    <img title="{% trans "this questions was selected as favorite" %} {{question.favourite_count}} {% trans "number of times" %}" 
-                        alt="{% trans "thumb-up on" %}"
-                                               src="{% media  "/media/images/vote-favorite-on.png" %}"/>
-                    <div><b>{{question.favourite_count|intcomma}}</b></div>
-                </div>
-            {% else %}
-                <div class="favorites-count-off">
-                    <img title="{% trans "this question was selected as favorite" %}{{question.favourite_count}} {% trans "number of times" %}" 
-                        alt="{% trans "thumb-up off" %}"
-                                               src="{% media  "/media/images/vote-favorite-off.png" %}"/>
-                    <div><b>{{question.favourite_count|intcomma}}</b></div>
-                </div>
-            {% endif %}
-        {% else %}
-            <div class="favorites-empty"> </div>
-        {% endif %}
-    <div id="question-summary-{{question.id}}" class="question-summary narrow">
-        <a style="text-decoration: none;" href="{{ question.get_absolute_url }}">
-            <div class="stats">
-                <div class="votes">
-                    <span class="vote-count-post">{{question.vote_count|intcomma}}</span>
-                    {% trans "votes" %}
-                </div >
-                <div title="{% if question.answer_accepted %}{% trans "this answer has been accepted to be correct" %}{% endif %}" class="status {% if question.answer_accepted %}answered-accepted{% endif %} {% ifequal question.answer_count 0 %}unanswered{% endifequal %}{% ifnotequal question.answer_count 0 %}answered{% endifnotequal %}">
-                    <span class="answer-count-post">{{question.answer_count|intcomma}}</span>
-                    {% trans "answers" %}
-                </div>
-                <div class="views">
-                     <span class="views-count-post">{{question.view_count|cnprog_intword|safe}}</span>
-                                        {% trans "views" %}
-                </div>
-            </div>
-        </a>
-        <div class="summary">
-            <div class="question-title">
-                <a title="{{question.summary}}" href="{{ question.get_absolute_url }}">{{question.title}}</a>
-            </div>
-            <div class="tags">
-                {% convert2tagname_list question %}
-                {% for tag in question.tagnames %}
-                                       <!--todo - move trans below to blocktrans -->
-                    <a href="{% url tag_questions tag|urlencode %}" title="{% trans "see questions tagged" %} '{{ tag }}' {% trans "using tags" %}" rel="tag">{{ tag }}</a>
-                {% endfor %}
-            </div>
-            <div class="started">
-                <span class="relativetime" title="{{question.last_activity_at}}">{% diff_date question.last_activity_at %}</span>
-                {% if question.la_username %}
-                    <a href="{% url users %}{{question.la_user_id}}/{{question.la_username}}">{{question.la_username}}</a> {% get_score_badge_by_details question.la_user_reputation question.la_user_gold question.la_user_silver question.la_user_bronze%}
-                {% endif %}
-            </div>
-        </div>
-    </div>
-    <br clear="all"/>
-    {% endfor %}
-</div>
-<!-- end users_questions.html -->
index fb2eae9c8169fe4c1b23a8640116877374b4eb52..4c5725650994f45c2dbc9d8579fc5db812c2884f 100644 (file)
@@ -25,8 +25,10 @@ def apply_default_filters(queryset, excluded_id):
 def create_recipients_dict(usr_list):\r
     return [(s['username'], s['email'], {'username': s['username']}) for s in usr_list]\r
 \r
-def question_posted(sender, instance, **kwargs):\r
-    question = instance.content_object\r
+def question_posted(instance, created, **kwargs):\r
+    if not created: return\r
+\r
+    question = instance\r
 \r
     subscribers = User.objects.values('email', 'username').filter(\r
             Q(subscription_settings__enable_notifications=True, subscription_settings__new_question='i') |\r
@@ -55,11 +57,13 @@ def question_posted(sender, instance, **kwargs):
     for user in new_subscribers:\r
         create_subscription_if_not_exists(question, user)\r
 \r
-activity_record.connect(question_posted, sender=const.TYPE_ACTIVITY_ASK_QUESTION, weak=False)\r
+#post_save.connect(question_posted, sender=Question)\r
+\r
 \r
+def answer_posted(instance, created, **kwargs):\r
+    if not created: return\r
 \r
-def answer_posted(sender, instance, **kwargs):\r
-    answer = instance.content_object\r
+    answer = instance\r
     question = answer.question\r
 \r
     subscribers = question.subscribers.values('email', 'username').filter(\r
@@ -78,7 +82,7 @@ def answer_posted(sender, instance, **kwargs):
     if answer.author.subscription_settings.questions_answered:\r
         create_subscription_if_not_exists(question, answer.author)\r
 \r
-activity_record.connect(answer_posted, sender=const.TYPE_ACTIVITY_ANSWER, weak=False)\r
+post_save.connect(answer_posted, sender=Answer)\r
 \r
 \r
 def comment_posted(sender, instance, **kwargs):\r
index 1317fa4fa69215ce4287109a5f6f236de91ca17a..79d357d1a92e17deae769e1d8cb45bd313f32a62 100644 (file)
@@ -9,7 +9,7 @@ from django import template
 from django.utils.encoding import smart_unicode
 from django.utils.safestring import mark_safe
 from forum.const import *
-from forum.models import Question, Answer, QuestionRevision, AnswerRevision
+from forum.models import Question, Answer, QuestionRevision, AnswerRevision, NodeRevision
 from django.utils.translation import ugettext as _
 from django.utils.translation import ungettext
 from django.utils import simplejson
@@ -131,7 +131,7 @@ def post_contributor_info(post,contributor_type='original_author'):
         post_type = 'question'
     elif isinstance(post,Answer):
         post_type = 'answer'
-    elif isinstance(post,AnswerRevision) or isinstance(post,QuestionRevision):
+    elif isinstance(post,(AnswerRevision, QuestionRevision, NodeRevision)):
         post_type = 'revision'
     return {
         'post':post,
similarity index 87%
rename from forum/templatetags/question_page_tags.py
rename to forum/templatetags/node_tags.py
index 88ac0154a7743ef1dc655c423009c023bec50759..aa82c3953b5fa02e3c7c34e1654a44117b03b4d1 100644 (file)
@@ -7,11 +7,10 @@ from django import template
 \r
 register = template.Library()\r
 \r
-@register.inclusion_tag('question/vote_buttons.html')\r
+@register.inclusion_tag('node/vote_buttons.html')\r
 def vote_buttons(post, user):\r
     context = {\r
         'post': post,\r
-        'post_type': (post.__class__ is Question) and 'question' or 'answer',\r
         'user_vote': 'none'\r
     }\r
 \r
@@ -24,7 +23,7 @@ def vote_buttons(post, user):
 \r
     return context\r
 \r
-@register.inclusion_tag('question/accept_button.html')    \r
+@register.inclusion_tag('node/accept_button.html')\r
 def accept_button(answer, user):\r
     return {\r
         'can_accept': user.is_authenticated() and user.can_accept_answer(answer),\r
@@ -32,7 +31,7 @@ def accept_button(answer, user):
         'user': user\r
     }\r
 \r
-@register.inclusion_tag('question/favorite_mark.html')\r
+@register.inclusion_tag('node/favorite_mark.html')\r
 def favorite_mark(question, user):\r
     try:\r
         FavoriteQuestion.objects.get(question=question, user=user)\r
@@ -47,7 +46,7 @@ def favorite_mark(question, user):
 def post_control(text, url, command=False, title=""):\r
     return {'text': text, 'url': url, 'command': command, 'title': title}\r
 \r
-@register.inclusion_tag('question/post_controls.html')\r
+@register.inclusion_tag('node/post_controls.html')\r
 def post_controls(post, user):\r
     controls = []\r
 \r
@@ -79,7 +78,7 @@ def post_controls(post, user):
 \r
     return {'controls': controls}\r
 \r
-@register.inclusion_tag('question/comments.html')\r
+@register.inclusion_tag('node/comments.html')\r
 def comments(post, user):\r
     all_comments = post.comments.filter(deleted=False).order_by('added_at')\r
 \r
@@ -115,9 +114,8 @@ def comments(post, user):
     return {\r
         'comments': comments,\r
         'post': post,\r
-        'post_type': (post.__class__ is Question) and 'question' or 'answer',\r
         'can_comment': user.can_comment(post),\r
         'max_length': 300,\r
         'showing': showing,\r
         'total': len(all_comments),\r
-    }
\ No newline at end of file
+    }\r
index 72f888b14730d155f726d549fefeded8209112ba..e9b80322eb180240af555098e6e97113d081a07b 100644 (file)
@@ -33,7 +33,7 @@ def question_sort_tabs(sort_context):
 @register.inclusion_tag('question_list/related_tags.html')\r
 def question_list_related_tags(questions):\r
     if len(questions):\r
-        return {'tags': Tag.objects.filter(questions__id__in=[q.id for q in questions]).distinct()}\r
+        return {'tags': Tag.objects.filter(nodes__id__in=[q.id for q in questions]).distinct()}\r
     else:\r
         return {'tags': False}\r
 \r
index c880c231d36e7a0e0641a126f117d3f37b573b78..f50917a161304c6924ee8dd6ed307c22eab09c93 100644 (file)
@@ -1,4 +1,6 @@
 from django import template\r
+from django.utils.translation import ugettext as _\r
+from forum import const\r
 \r
 register = template.Library()\r
 \r
@@ -23,3 +25,50 @@ def user_signature(parser, token):
         raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]\r
 \r
     return UserSignatureNode(user, format)\r
+\r
+\r
+class ActivityNode(template.Node):\r
+    template = template.loader.get_template('users/activity.html')\r
+\r
+    def __init__(self, activity):\r
+        self.activity = template.Variable(activity)\r
+\r
+    def render(self, context):\r
+        activity = self.activity.resolve(context)\r
+\r
+        context = {\r
+            'active_at': activity.active_at,\r
+            'description': activity.type_as_string,\r
+            'type': activity.activity_type,\r
+        }\r
+\r
+        try:\r
+            if activity.activity_type == const.TYPE_ACTIVITY_PRIZE:\r
+                context['badge'] = True\r
+                context['title'] = activity.content_object.badge.name\r
+                context['url'] = activity.content_object.badge.get_absolute_url()\r
+                context['badge_type'] = activity.content_object.badge.type\r
+            else:\r
+                context['title'] = activity.node.headline\r
+                context['url'] = activity.node.get_absolute_url()\r
+\r
+            if activity.activity_type in (const.TYPE_ACTIVITY_UPDATE_ANSWER, const.TYPE_ACTIVITY_UPDATE_QUESTION):\r
+                context['revision'] = True\r
+                context['summary'] = activity.content_object.summary or \\r
+                        _('Revision n. %(rev_number)d') % {'rev_number': activity.content_object.revision}\r
+        except Exception, e:\r
+            import sys, traceback\r
+            traceback.print_exc(file=sys.stdout)\r
+            pass\r
+\r
+\r
+        return self.template.render(template.Context(context))\r
+\r
+@register.tag\r
+def activity_item(parser, token):\r
+    try:\r
+        tag_name, activity = token.split_contents()\r
+    except ValueError:\r
+        raise template.TemplateSyntaxError, "%r tag requires exactly one arguments" % token.contents.split()[0]\r
+\r
+    return ActivityNode(activity)\r
index ba5440f18571e3e5ccb546275fb0cf5931cabd6f..653c6a7df274271600dca581b2024174b0c60cb3 100644 (file)
@@ -38,7 +38,7 @@ urlpatterns = patterns('',
     url(r'^%s$' % _('privacy/'), app.meta.privacy, name='privacy'),
     url(r'^%s$' % _('logout/'), app.meta.logout, name='logout'),
     url(r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('edit/')), app.writers.edit_answer, name='edit_answer'),
-    url(r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('revisions/')), app.readers.answer_revisions, name='answer_revisions'),
+    url(r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('revisions/')), app.readers.revisions, name='answer_revisions'),
     url(r'^%s$' % _('questions/'), app.readers.questions, name='questions'),
     url(r'^%s%s$' % (_('questions/'), _('ask/')), app.writers.ask, name='ask'),
     url(r'^%s%s$' % (_('questions/'), _('unanswered/')), app.readers.unanswered, name='unanswered'),
@@ -47,9 +47,9 @@ urlpatterns = patterns('',
     url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')), app.commands.reopen, name='reopen'),
     url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('answer/')), app.writers.answer, name='answer'),
 
-    url(r'^%s(?P<post_type>[a-z]+)/(?P<id>\d+)/(?P<vote_type>[a-z]+)/' % _('vote/'), app.commands.vote_post, name='vote_post'),
+    url(r'^%s(?P<id>\d+)/(?P<vote_type>[a-z]+)/' % _('vote/'), app.commands.vote_post, name='vote_post'),
     url(r'^%s(?P<id>\d+)/$' % _('like_comment/'), app.commands.like_comment, name="like_comment"),
-    url(r'^%s(?P<post_type>[a-z]+)/(?P<id>\d+)/' % _('comment/'), app.commands.comment, name='comment'),
+    url(r'^%s(?P<id>\d+)/' % _('comment/'), app.commands.comment, name='comment'),
     url(r'^%s(?P<id>\d+)/$' % _('delete_comment/'), app.commands.delete_comment, name="delete_comment"),
     url(r'^%s(?P<id>\d+)/$' % _('accept_answer/'), app.commands.accept_answer, name="accept_answer"),
     url(r'^%s(?P<id>\d+)/$' % _('mark_favorite/'), app.commands.mark_favorite, name="mark_favorite"),
@@ -57,7 +57,7 @@ urlpatterns = patterns('',
     url(r'^%s(?P<post_type>[a-z]+)/(?P<id>\d+)/' % _('delete/'), app.commands.delete_post, name='delete_post'),
     url(r'^%s(?P<id>\d+)/$' % _('subscribe/'), app.commands.subscribe, name="subscribe"),
 
-    url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')), app.readers.question_revisions, name='question_revisions'),
+    url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')), app.readers.revisions, name='question_revisions'),
     url(r'^%s$' % _('command/'), app.commands.ajax_command, name='call_ajax'),
 
     #place general question item in the end of other operations
@@ -82,7 +82,14 @@ urlpatterns = patterns('',
     url(r'^%s$' % _('users/'),app.users.users, name='users'),
     url(r'^%s(?P<id>\d+)/$' % _('moderate-user/'), app.users.moderate_user, name='moderate_user'),
     url(r'^%s(?P<id>\d+)/%s$' % (_('users/'), _('edit/')), app.users.edit_user, name='edit_user'),
-    url(r'^%s(?P<id>\d+)/(?P<slug>.+)/$' % _('users/'), app.users.user, name='user_profile'),
+
+    url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('subscriptions/')), app.users.user_subscriptions, name='user_subscriptions'),
+    url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('favorites/')), app.users.user_favorites, name='user_favorites'),
+    url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('reputation/')), app.users.user_reputation, name='user_reputation'),
+    url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('votes/')), app.users.user_votes, name='user_votes'),
+    url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('recent/')), app.users.user_recent, name='user_recent'),
+    url(r'^%s(?P<id>\d+)/(?P<slug>.+)/$' % _('users/'), app.users.user_stats, name='user_profile'),
+    
     url(r'^%s$' % _('badges/'),app.meta.badges, name='badges'),
     url(r'^%s(?P<id>\d+)//*' % _('badges/'), app.meta.badge, name='badge'),
     url(r'^%s%s$' % (_('messages/'), _('markread/')),app.commands.read_message, name='read_message'),
diff --git a/forum/utils/cache.py b/forum/utils/cache.py
deleted file mode 100644 (file)
index 6341392..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-"""Utilities for working with Django Models."""
-import itertools
-
-from django.contrib.contenttypes.models import ContentType
-
-from forum.utils.lists import flatten
-
-def fetch_model_dict(model, ids, fields=None):
-    """
-    Fetches a dict of model details for model instances with the given
-    ids, keyed by their id.
-
-    If a fields list is given, a dict of details will be retrieved for
-    each model, otherwise complete model instances will be retrieved.
-
-    Any fields list given shouldn't contain the primary key attribute for
-    the model, as this can be determined from its Options.
-    """
-    if fields is None:
-        return model._default_manager.in_bulk(ids)
-    else:
-        id_attr = model._meta.pk.attname
-        return dict((obj[id_attr], obj) for obj
-            in model._default_manager.filter(id__in=ids).values(
-                *itertools.chain((id_attr,), fields)))
-
-def populate_foreign_key_caches(model, objects_to_populate, fields=None):
-    """
-    Populates caches for the given related Model in instances of objects
-    which have a ForeignKey relationship to it, specified as a list of
-    (object list, related attribute name list) two-tuples.
-
-    If a list of field names is given, only the given fields will be
-    looked up and related object caches will be populated with a dict of
-    the specified fields. Otherwise, complete model instances will be
-    retrieved.
-    """
-    # Get all related object ids for the appropriate fields
-    related_object_ids = []
-    for objects, attrs in objects_to_populate:
-        related_object_ids.append(tuple(tuple(getattr(obj, '%s_id' % attr)
-                                              for attr in attrs)
-                                  for obj in objects))
-    unique_ids = tuple(set(pk for pk in flatten(related_object_ids) if pk))
-    related_objects = fetch_model_dict(model, unique_ids, fields)
-
-    # Fill related object caches
-    for (objects, attrs), related_ids in itertools.izip(objects_to_populate,
-                                                        related_object_ids):
-        for obj, related_ids_for_obj in itertools.izip(objects,
-                                                       related_ids):
-            for attr, related_object in itertools.izip(attrs, (related_objects.get(pk, None)
-                                                               for pk in related_ids_for_obj)):
-                setattr(obj, '_%s_cache' % attr, related_object)
-
-def populate_content_object_caches(generic_related_objects, model_fields=None):
-    """
-    Retrieves ``ContentType`` and content objects for the given list of
-    items which use a generic relation, grouping the retrieval of content
-    objects by model to reduce the number of queries executed.
-
-    This results in ``number_of_content_types + 1`` queries rather than
-    the ``number_of_generic_reL_objects * 2`` queries you'd get by
-    iterating over the list and accessing each item's object attribute.
-
-    If a dict mapping model classes to field names is given, only the
-    given fields will be looked up for each model specified and the
-    object cache will be populated with a dict of the specified fields.
-    Otherwise, complete model instances will be retrieved.
-    """
-    if model_fields is None:
-        model_fields = {}
-
-    # Group content object ids by their content type ids
-    ids_by_content_type = {}
-    for obj in generic_related_objects:
-        ids_by_content_type.setdefault(obj.content_type_id,
-                                       []).append(obj.object_id)
-
-    # Retrieve content types and content objects in bulk
-    content_types = ContentType.objects.in_bulk(ids_by_content_type.keys())
-    for content_type_id, ids in ids_by_content_type.iteritems():
-        model = content_types[content_type_id].model_class()
-        objects[content_type_id] = fetch_model_dict(
-            model, tuple(set(ids)), model_fields.get(model, None))
-
-    # Set content types and content objects in the appropriate cache
-    # attributes, so accessing the 'content_type' and 'object' attributes
-    # on each object won't result in further database hits.
-    for obj in generic_related_objects:
-        obj._object_cache = objects[obj.content_type_id][obj.object_id]
-        obj._content_type_cache = content_types[obj.content_type_id]
diff --git a/forum/utils/odict.py b/forum/utils/odict.py
deleted file mode 100644 (file)
index 2c8391d..0000000
+++ /dev/null
@@ -1,1399 +0,0 @@
-# odict.py
-# An Ordered Dictionary object
-# Copyright (C) 2005 Nicola Larosa, Michael Foord
-# E-mail: nico AT tekNico DOT net, fuzzyman AT voidspace DOT org DOT uk
-
-# This software is licensed under the terms of the BSD license.
-# http://www.voidspace.org.uk/python/license.shtml
-# Basically you're free to copy, modify, distribute and relicense it,
-# So long as you keep a copy of the license with it.
-
-# Documentation at http://www.voidspace.org.uk/python/odict.html
-# For information about bugfixes, updates and support, please join the
-# Pythonutils mailing list:
-# http://groups.google.com/group/pythonutils/
-# Comments, suggestions and bug reports welcome.
-
-"""A dict that keeps keys in insertion order"""
-from __future__ import generators
-
-__author__ = ('Nicola Larosa <nico-NoSp@m-tekNico.net>,'
-    'Michael Foord <fuzzyman AT voidspace DOT org DOT uk>')
-
-__docformat__ = "restructuredtext en"
-
-__revision__ = '$Id: odict.py 129 2005-09-12 18:15:28Z teknico $'
-
-__version__ = '0.2.2'
-
-__all__ = ['OrderedDict', 'SequenceOrderedDict']
-
-import sys
-INTP_VER = sys.version_info[:2]
-if INTP_VER < (2, 2):
-    raise RuntimeError("Python v.2.2 or later required")
-
-import types, warnings
-
-class OrderedDict(dict):
-    """
-    A class of dictionary that keeps the insertion order of keys.
-    
-    All appropriate methods return keys, items, or values in an ordered way.
-    
-    All normal dictionary methods are available. Update and comparison is
-    restricted to other OrderedDict objects.
-    
-    Various sequence methods are available, including the ability to explicitly
-    mutate the key ordering.
-    
-    __contains__ tests:
-    
-    >>> d = OrderedDict(((1, 3),))
-    >>> 1 in d
-    1
-    >>> 4 in d
-    0
-    
-    __getitem__ tests:
-    
-    >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[2]
-    1
-    >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[4]
-    Traceback (most recent call last):
-    KeyError: 4
-    
-    __len__ tests:
-    
-    >>> len(OrderedDict())
-    0
-    >>> len(OrderedDict(((1, 3), (3, 2), (2, 1))))
-    3
-    
-    get tests:
-    
-    >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-    >>> d.get(1)
-    3
-    >>> d.get(4) is None
-    1
-    >>> d.get(4, 5)
-    5
-    >>> d
-    OrderedDict([(1, 3), (3, 2), (2, 1)])
-    
-    has_key tests:
-    
-    >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-    >>> d.has_key(1)
-    1
-    >>> d.has_key(4)
-    0
-    """
-
-    def __init__(self, init_val=(), strict=False):
-        """
-        Create a new ordered dictionary. Cannot init from a normal dict,
-        nor from kwargs, since items order is undefined in those cases.
-        
-        If the ``strict`` keyword argument is ``True`` (``False`` is the
-        default) then when doing slice assignment - the ``OrderedDict`` you are
-        assigning from *must not* contain any keys in the remaining dict.
-        
-        >>> OrderedDict()
-        OrderedDict([])
-        >>> OrderedDict({1: 1})
-        Traceback (most recent call last):
-        TypeError: undefined order, cannot get items from dict
-        >>> OrderedDict({1: 1}.items())
-        OrderedDict([(1, 1)])
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d
-        OrderedDict([(1, 3), (3, 2), (2, 1)])
-        >>> OrderedDict(d)
-        OrderedDict([(1, 3), (3, 2), (2, 1)])
-        """
-        self.strict = strict
-        dict.__init__(self)
-        if isinstance(init_val, OrderedDict):
-            self._sequence = init_val.keys()
-            dict.update(self, init_val)
-        elif isinstance(init_val, dict):
-            # we lose compatibility with other ordered dict types this way
-            raise TypeError('undefined order, cannot get items from dict')
-        else:
-            self._sequence = []
-            self.update(init_val)
-
-### Special methods ###
-
-    def __delitem__(self, key):
-        """
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> del d[3]
-        >>> d
-        OrderedDict([(1, 3), (2, 1)])
-        >>> del d[3]
-        Traceback (most recent call last):
-        KeyError: 3
-        >>> d[3] = 2
-        >>> d
-        OrderedDict([(1, 3), (2, 1), (3, 2)])
-        >>> del d[0:1]
-        >>> d
-        OrderedDict([(2, 1), (3, 2)])
-        """
-        if isinstance(key, types.SliceType):
-            # FIXME: efficiency?
-            keys = self._sequence[key]
-            for entry in keys:
-                dict.__delitem__(self, entry)
-            del self._sequence[key]
-        else:
-            # do the dict.__delitem__ *first* as it raises
-            # the more appropriate error
-            dict.__delitem__(self, key)
-            self._sequence.remove(key)
-
-    def __eq__(self, other):
-        """
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d == OrderedDict(d)
-        True
-        >>> d == OrderedDict(((1, 3), (2, 1), (3, 2)))
-        False
-        >>> d == OrderedDict(((1, 0), (3, 2), (2, 1)))
-        False
-        >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
-        False
-        >>> d == dict(d)
-        False
-        >>> d == False
-        False
-        """
-        if isinstance(other, OrderedDict):
-            # FIXME: efficiency?
-            #   Generate both item lists for each compare
-            return (self.items() == other.items())
-        else:
-            return False
-
-    def __lt__(self, other):
-        """
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
-        >>> c < d
-        True
-        >>> d < c
-        False
-        >>> d < dict(c)
-        Traceback (most recent call last):
-        TypeError: Can only compare with other OrderedDicts
-        """
-        if not isinstance(other, OrderedDict):
-            raise TypeError('Can only compare with other OrderedDicts')
-        # FIXME: efficiency?
-        #   Generate both item lists for each compare
-        return (self.items() < other.items())
-
-    def __le__(self, other):
-        """
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
-        >>> e = OrderedDict(d)
-        >>> c <= d
-        True
-        >>> d <= c
-        False
-        >>> d <= dict(c)
-        Traceback (most recent call last):
-        TypeError: Can only compare with other OrderedDicts
-        >>> d <= e
-        True
-        """
-        if not isinstance(other, OrderedDict):
-            raise TypeError('Can only compare with other OrderedDicts')
-        # FIXME: efficiency?
-        #   Generate both item lists for each compare
-        return (self.items() <= other.items())
-
-    def __ne__(self, other):
-        """
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d != OrderedDict(d)
-        False
-        >>> d != OrderedDict(((1, 3), (2, 1), (3, 2)))
-        True
-        >>> d != OrderedDict(((1, 0), (3, 2), (2, 1)))
-        True
-        >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
-        False
-        >>> d != dict(d)
-        True
-        >>> d != False
-        True
-        """
-        if isinstance(other, OrderedDict):
-            # FIXME: efficiency?
-            #   Generate both item lists for each compare
-            return not (self.items() == other.items())
-        else:
-            return True
-
-    def __gt__(self, other):
-        """
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
-        >>> d > c
-        True
-        >>> c > d
-        False
-        >>> d > dict(c)
-        Traceback (most recent call last):
-        TypeError: Can only compare with other OrderedDicts
-        """
-        if not isinstance(other, OrderedDict):
-            raise TypeError('Can only compare with other OrderedDicts')
-        # FIXME: efficiency?
-        #   Generate both item lists for each compare
-        return (self.items() > other.items())
-
-    def __ge__(self, other):
-        """
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
-        >>> e = OrderedDict(d)
-        >>> c >= d
-        False
-        >>> d >= c
-        True
-        >>> d >= dict(c)
-        Traceback (most recent call last):
-        TypeError: Can only compare with other OrderedDicts
-        >>> e >= d
-        True
-        """
-        if not isinstance(other, OrderedDict):
-            raise TypeError('Can only compare with other OrderedDicts')
-        # FIXME: efficiency?
-        #   Generate both item lists for each compare
-        return (self.items() >= other.items())
-
-    def __repr__(self):
-        """
-        Used for __repr__ and __str__
-        
-        >>> r1 = repr(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
-        >>> r1
-        "OrderedDict([('a', 'b'), ('c', 'd'), ('e', 'f')])"
-        >>> r2 = repr(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
-        >>> r2
-        "OrderedDict([('a', 'b'), ('e', 'f'), ('c', 'd')])"
-        >>> r1 == str(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
-        True
-        >>> r2 == str(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
-        True
-        """
-        return '%s([%s])' % (self.__class__.__name__, ', '.join(
-            ['(%r, %r)' % (key, self[key]) for key in self._sequence]))
-
-    def __setitem__(self, key, val):
-        """
-        Allows slice assignment, so long as the slice is an OrderedDict
-        >>> d = OrderedDict()
-        >>> d['a'] = 'b'
-        >>> d['b'] = 'a'
-        >>> d[3] = 12
-        >>> d
-        OrderedDict([('a', 'b'), ('b', 'a'), (3, 12)])
-        >>> d[:] = OrderedDict(((1, 2), (2, 3), (3, 4)))
-        >>> d
-        OrderedDict([(1, 2), (2, 3), (3, 4)])
-        >>> d[::2] = OrderedDict(((7, 8), (9, 10)))
-        >>> d
-        OrderedDict([(7, 8), (2, 3), (9, 10)])
-        >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)))
-        >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
-        >>> d
-        OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
-        >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)), strict=True)
-        >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
-        >>> d
-        OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
-        
-        >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)), strict=True)
-        >>> a[3] = 4
-        >>> a
-        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> a
-        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)])
-        Traceback (most recent call last):
-        ValueError: slice assignment must be from unique keys
-        >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)))
-        >>> a[3] = 4
-        >>> a
-        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> a
-        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> a
-        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> a[::-1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> a
-        OrderedDict([(3, 4), (2, 3), (1, 2), (0, 1)])
-        
-        >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> d[:1] = 3
-        Traceback (most recent call last):
-        TypeError: slice assignment requires an OrderedDict
-        
-        >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
-        >>> d[:1] = OrderedDict([(9, 8)])
-        >>> d
-        OrderedDict([(9, 8), (1, 2), (2, 3), (3, 4)])
-        """
-        if isinstance(key, types.SliceType):
-            if not isinstance(val, OrderedDict):
-                # FIXME: allow a list of tuples?
-                raise TypeError('slice assignment requires an OrderedDict')
-            keys = self._sequence[key]
-            # NOTE: Could use ``range(*key.indices(len(self._sequence)))``
-            indexes = range(len(self._sequence))[key]
-            if key.step is None:
-                # NOTE: new slice may not be the same size as the one being
-                #   overwritten !
-                # NOTE: What is the algorithm for an impossible slice?
-                #   e.g. d[5:3]
-                pos = key.start or 0
-                del self[key]
-                newkeys = val.keys()
-                for k in newkeys:
-                    if k in self:
-                        if self.strict:
-                            raise ValueError('slice assignment must be from '
-                                'unique keys')
-                        else:
-                            # NOTE: This removes duplicate keys *first*
-                            #   so start position might have changed?
-                            del self[k]
-                self._sequence = (self._sequence[:pos] + newkeys +
-                    self._sequence[pos:])
-                dict.update(self, val)
-            else:
-                # extended slice - length of new slice must be the same
-                # as the one being replaced
-                if len(keys) != len(val):
-                    raise ValueError('attempt to assign sequence of size %s '
-                        'to extended slice of size %s' % (len(val), len(keys)))
-                # FIXME: efficiency?
-                del self[key]
-                item_list = zip(indexes, val.items())
-                # smallest indexes first - higher indexes not guaranteed to
-                # exist
-                item_list.sort()
-                for pos, (newkey, newval) in item_list:
-                    if self.strict and newkey in self:
-                        raise ValueError('slice assignment must be from unique'
-                            ' keys')
-                    self.insert(pos, newkey, newval)
-        else:
-            if key not in self:
-                self._sequence.append(key)
-            dict.__setitem__(self, key, val)
-
-    def __getitem__(self, key):
-        """
-        Allows slicing. Returns an OrderedDict if you slice.
-        >>> b = OrderedDict([(7, 0), (6, 1), (5, 2), (4, 3), (3, 4), (2, 5), (1, 6)])
-        >>> b[::-1]
-        OrderedDict([(1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1), (7, 0)])
-        >>> b[2:5]
-        OrderedDict([(5, 2), (4, 3), (3, 4)])
-        >>> type(b[2:4])
-        <class '__main__.OrderedDict'>
-        """
-        if isinstance(key, types.SliceType):
-            # FIXME: does this raise the error we want?
-            keys = self._sequence[key]
-            # FIXME: efficiency?
-            return OrderedDict([(entry, self[entry]) for entry in keys])
-        else:
-            return dict.__getitem__(self, key)
-
-    __str__ = __repr__
-
-    def __setattr__(self, name, value):
-        """
-        Implemented so that accesses to ``sequence`` raise a warning and are
-        diverted to the new ``setkeys`` method.
-        """
-        if name == 'sequence':
-            warnings.warn('Use of the sequence attribute is deprecated.'
-                ' Use the keys method instead.', DeprecationWarning)
-            # NOTE: doesn't return anything
-            self.setkeys(value)
-        else:
-            # FIXME: do we want to allow arbitrary setting of attributes?
-            #   Or do we want to manage it?
-            object.__setattr__(self, name, value)
-
-    def __getattr__(self, name):
-        """
-        Implemented so that access to ``sequence`` raises a warning.
-        
-        >>> d = OrderedDict()
-        >>> d.sequence
-        []
-        """
-        if name == 'sequence':
-            warnings.warn('Use of the sequence attribute is deprecated.'
-                ' Use the keys method instead.', DeprecationWarning)
-            # NOTE: Still (currently) returns a direct reference. Need to
-            #   because code that uses sequence will expect to be able to
-            #   mutate it in place.
-            return self._sequence
-        else:
-            # raise the appropriate error
-            raise AttributeError("OrderedDict has no '%s' attribute" % name)
-
-    def __deepcopy__(self, memo):
-        """
-        To allow deepcopy to work with OrderedDict.
-        
-        >>> from copy import deepcopy
-        >>> a = OrderedDict([(1, 1), (2, 2), (3, 3)])
-        >>> a['test'] = {}
-        >>> b = deepcopy(a)
-        >>> b == a
-        True
-        >>> b is a
-        False
-        >>> a['test'] is b['test']
-        False
-        """
-        from copy import deepcopy
-        return self.__class__(deepcopy(self.items(), memo), self.strict)
-
-
-### Read-only methods ###
-
-    def copy(self):
-        """
-        >>> OrderedDict(((1, 3), (3, 2), (2, 1))).copy()
-        OrderedDict([(1, 3), (3, 2), (2, 1)])
-        """
-        return OrderedDict(self)
-
-    def items(self):
-        """
-        ``items`` returns a list of tuples representing all the 
-        ``(key, value)`` pairs in the dictionary.
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.items()
-        [(1, 3), (3, 2), (2, 1)]
-        >>> d.clear()
-        >>> d.items()
-        []
-        """
-        return zip(self._sequence, self.values())
-
-    def keys(self):
-        """
-        Return a list of keys in the ``OrderedDict``.
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.keys()
-        [1, 3, 2]
-        """
-        return self._sequence[:]
-
-    def values(self, values=None):
-        """
-        Return a list of all the values in the OrderedDict.
-        
-        Optionally you can pass in a list of values, which will replace the
-        current list. The value list must be the same len as the OrderedDict.
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.values()
-        [3, 2, 1]
-        """
-        return [self[key] for key in self._sequence]
-
-    def iteritems(self):
-        """
-        >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iteritems()
-        >>> ii.next()
-        (1, 3)
-        >>> ii.next()
-        (3, 2)
-        >>> ii.next()
-        (2, 1)
-        >>> ii.next()
-        Traceback (most recent call last):
-        StopIteration
-        """
-        def make_iter(self=self):
-            keys = self.iterkeys()
-            while True:
-                key = keys.next()
-                yield (key, self[key])
-        return make_iter()
-
-    def iterkeys(self):
-        """
-        >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iterkeys()
-        >>> ii.next()
-        1
-        >>> ii.next()
-        3
-        >>> ii.next()
-        2
-        >>> ii.next()
-        Traceback (most recent call last):
-        StopIteration
-        """
-        return iter(self._sequence)
-
-    __iter__ = iterkeys
-
-    def itervalues(self):
-        """
-        >>> iv = OrderedDict(((1, 3), (3, 2), (2, 1))).itervalues()
-        >>> iv.next()
-        3
-        >>> iv.next()
-        2
-        >>> iv.next()
-        1
-        >>> iv.next()
-        Traceback (most recent call last):
-        StopIteration
-        """
-        def make_iter(self=self):
-            keys = self.iterkeys()
-            while True:
-                yield self[keys.next()]
-        return make_iter()
-
-### Read-write methods ###
-
-    def clear(self):
-        """
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.clear()
-        >>> d
-        OrderedDict([])
-        """
-        dict.clear(self)
-        self._sequence = []
-
-    def pop(self, key, *args):
-        """
-        No dict.pop in Python 2.2, gotta reimplement it
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.pop(3)
-        2
-        >>> d
-        OrderedDict([(1, 3), (2, 1)])
-        >>> d.pop(4)
-        Traceback (most recent call last):
-        KeyError: 4
-        >>> d.pop(4, 0)
-        0
-        >>> d.pop(4, 0, 1)
-        Traceback (most recent call last):
-        TypeError: pop expected at most 2 arguments, got 3
-        """
-        if len(args) > 1:
-            raise TypeError, ('pop expected at most 2 arguments, got %s' %
-                (len(args) + 1))
-        if key in self:
-            val = self[key]
-            del self[key]
-        else:
-            try:
-                val = args[0]
-            except IndexError:
-                raise KeyError(key)
-        return val
-
-    def popitem(self, i=-1):
-        """
-        Delete and return an item specified by index, not a random one as in
-        dict. The index is -1 by default (the last item).
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.popitem()
-        (2, 1)
-        >>> d
-        OrderedDict([(1, 3), (3, 2)])
-        >>> d.popitem(0)
-        (1, 3)
-        >>> OrderedDict().popitem()
-        Traceback (most recent call last):
-        KeyError: 'popitem(): dictionary is empty'
-        >>> d.popitem(2)
-        Traceback (most recent call last):
-        IndexError: popitem(): index 2 not valid
-        """
-        if not self._sequence:
-            raise KeyError('popitem(): dictionary is empty')
-        try:
-            key = self._sequence[i]
-        except IndexError:
-            raise IndexError('popitem(): index %s not valid' % i)
-        return (key, self.pop(key))
-
-    def setdefault(self, key, defval = None):
-        """
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.setdefault(1)
-        3
-        >>> d.setdefault(4) is None
-        True
-        >>> d
-        OrderedDict([(1, 3), (3, 2), (2, 1), (4, None)])
-        >>> d.setdefault(5, 0)
-        0
-        >>> d
-        OrderedDict([(1, 3), (3, 2), (2, 1), (4, None), (5, 0)])
-        """
-        if key in self:
-            return self[key]
-        else:
-            self[key] = defval
-            return defval
-
-    def update(self, from_od):
-        """
-        Update from another OrderedDict or sequence of (key, value) pairs
-        
-        >>> d = OrderedDict(((1, 0), (0, 1)))
-        >>> d.update(OrderedDict(((1, 3), (3, 2), (2, 1))))
-        >>> d
-        OrderedDict([(1, 3), (0, 1), (3, 2), (2, 1)])
-        >>> d.update({4: 4})
-        Traceback (most recent call last):
-        TypeError: undefined order, cannot get items from dict
-        >>> d.update((4, 4))
-        Traceback (most recent call last):
-        TypeError: cannot convert dictionary update sequence element "4" to a 2-item sequence
-        """
-        if isinstance(from_od, OrderedDict):
-            for key, val in from_od.items():
-                self[key] = val
-        elif isinstance(from_od, dict):
-            # we lose compatibility with other ordered dict types this way
-            raise TypeError('undefined order, cannot get items from dict')
-        else:
-            # FIXME: efficiency?
-            # sequence of 2-item sequences, or error
-            for item in from_od:
-                try:
-                    key, val = item
-                except TypeError:
-                    raise TypeError('cannot convert dictionary update'
-                        ' sequence element "%s" to a 2-item sequence' % item)
-                self[key] = val
-
-    def rename(self, old_key, new_key):
-        """
-        Rename the key for a given value, without modifying sequence order.
-        
-        For the case where new_key already exists this raise an exception,
-        since if new_key exists, it is ambiguous as to what happens to the
-        associated values, and the position of new_key in the sequence.
-        
-        >>> od = OrderedDict()
-        >>> od['a'] = 1
-        >>> od['b'] = 2
-        >>> od.items()
-        [('a', 1), ('b', 2)]
-        >>> od.rename('b', 'c')
-        >>> od.items()
-        [('a', 1), ('c', 2)]
-        >>> od.rename('c', 'a')
-        Traceback (most recent call last):
-        ValueError: New key already exists: 'a'
-        >>> od.rename('d', 'b')
-        Traceback (most recent call last):
-        KeyError: 'd'
-        """
-        if new_key == old_key:
-            # no-op
-            return
-        if new_key in self:
-            raise ValueError("New key already exists: %r" % new_key)
-        # rename sequence entry
-        value = self[old_key] 
-        old_idx = self._sequence.index(old_key)
-        self._sequence[old_idx] = new_key
-        # rename internal dict entry
-        dict.__delitem__(self, old_key)
-        dict.__setitem__(self, new_key, value)
-
-    def setitems(self, items):
-        """
-        This method allows you to set the items in the dict.
-        
-        It takes a list of tuples - of the same sort returned by the ``items``
-        method.
-        
-        >>> d = OrderedDict()
-        >>> d.setitems(((3, 1), (2, 3), (1, 2)))
-        >>> d
-        OrderedDict([(3, 1), (2, 3), (1, 2)])
-        """
-        self.clear()
-        # FIXME: this allows you to pass in an OrderedDict as well :-)
-        self.update(items)
-
-    def setkeys(self, keys):
-        """
-        ``setkeys`` all ows you to pass in a new list of keys which will
-        replace the current set. This must contain the same set of keys, but
-        need not be in the same order.
-        
-        If you pass in new keys that don't match, a ``KeyError`` will be
-        raised.
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.keys()
-        [1, 3, 2]
-        >>> d.setkeys((1, 2, 3))
-        >>> d
-        OrderedDict([(1, 3), (2, 1), (3, 2)])
-        >>> d.setkeys(['a', 'b', 'c'])
-        Traceback (most recent call last):
-        KeyError: 'Keylist is not the same as current keylist.'
-        """
-        # FIXME: Efficiency? (use set for Python 2.4 :-)
-        # NOTE: list(keys) rather than keys[:] because keys[:] returns
-        #   a tuple, if keys is a tuple.
-        kcopy = list(keys)
-        kcopy.sort()
-        self._sequence.sort()
-        if kcopy != self._sequence:
-            raise KeyError('Keylist is not the same as current keylist.')
-        # NOTE: This makes the _sequence attribute a new object, instead
-        #       of changing it in place.
-        # FIXME: efficiency?
-        self._sequence = list(keys)
-
-    def setvalues(self, values):
-        """
-        You can pass in a list of values, which will replace the
-        current list. The value list must be the same len as the OrderedDict.
-        
-        (Or a ``ValueError`` is raised.)
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.setvalues((1, 2, 3))
-        >>> d
-        OrderedDict([(1, 1), (3, 2), (2, 3)])
-        >>> d.setvalues([6])
-        Traceback (most recent call last):
-        ValueError: Value list is not the same length as the OrderedDict.
-        """
-        if len(values) != len(self):
-            # FIXME: correct error to raise?
-            raise ValueError('Value list is not the same length as the '
-                'OrderedDict.')
-        self.update(zip(self, values))
-
-### Sequence Methods ###
-
-    def index(self, key):
-        """
-        Return the position of the specified key in the OrderedDict.
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.index(3)
-        1
-        >>> d.index(4)
-        Traceback (most recent call last):
-        ValueError: list.index(x): x not in list
-        """
-        return self._sequence.index(key)
-
-    def insert(self, index, key, value):
-        """
-        Takes ``index``, ``key``, and ``value`` as arguments.
-        
-        Sets ``key`` to ``value``, so that ``key`` is at position ``index`` in
-        the OrderedDict.
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.insert(0, 4, 0)
-        >>> d
-        OrderedDict([(4, 0), (1, 3), (3, 2), (2, 1)])
-        >>> d.insert(0, 2, 1)
-        >>> d
-        OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2)])
-        >>> d.insert(8, 8, 1)
-        >>> d
-        OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2), (8, 1)])
-        """
-        if key in self:
-            # FIXME: efficiency?
-            del self[key]
-        self._sequence.insert(index, key)
-        dict.__setitem__(self, key, value)
-
-    def reverse(self):
-        """
-        Reverse the order of the OrderedDict.
-        
-        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
-        >>> d.reverse()
-        >>> d
-        OrderedDict([(2, 1), (3, 2), (1, 3)])
-        """
-        self._sequence.reverse()
-
-    def sort(self, *args, **kwargs):
-        """
-        Sort the key order in the OrderedDict.
-        
-        This method takes the same arguments as the ``list.sort`` method on
-        your version of Python.
-        
-        >>> d = OrderedDict(((4, 1), (2, 2), (3, 3), (1, 4)))
-        >>> d.sort()
-        >>> d
-        OrderedDict([(1, 4), (2, 2), (3, 3), (4, 1)])
-        """
-        self._sequence.sort(*args, **kwargs)
-
-class Keys(object):
-    # FIXME: should this object be a subclass of list?
-    """
-    Custom object for accessing the keys of an OrderedDict.
-    
-    Can be called like the normal ``OrderedDict.keys`` method, but also
-    supports indexing and sequence methods.
-    """
-
-    def __init__(self, main):
-        self._main = main
-
-    def __call__(self):
-        """Pretend to be the keys method."""
-        return self._main._keys()
-
-    def __getitem__(self, index):
-        """Fetch the key at position i."""
-        # NOTE: this automatically supports slicing :-)
-        return self._main._sequence[index]
-
-    def __setitem__(self, index, name):
-        """
-        You cannot assign to keys, but you can do slice assignment to re-order
-        them.
-        
-        You can only do slice assignment if the new set of keys is a reordering
-        of the original set.
-        """
-        if isinstance(index, types.SliceType):
-            # FIXME: efficiency?
-            # check length is the same
-            indexes = range(len(self._main._sequence))[index]
-            if len(indexes) != len(name):
-                raise ValueError('attempt to assign sequence of size %s '
-                    'to slice of size %s' % (len(name), len(indexes)))
-            # check they are the same keys
-            # FIXME: Use set
-            old_keys = self._main._sequence[index]
-            new_keys = list(name)
-            old_keys.sort()
-            new_keys.sort()
-            if old_keys != new_keys:
-                raise KeyError('Keylist is not the same as current keylist.')
-            orig_vals = [self._main[k] for k in name]
-            del self._main[index]
-            vals = zip(indexes, name, orig_vals)
-            vals.sort()
-            for i, k, v in vals:
-                if self._main.strict and k in self._main:
-                    raise ValueError('slice assignment must be from '
-                        'unique keys')
-                self._main.insert(i, k, v)
-        else:
-            raise ValueError('Cannot assign to keys')
-
-    ### following methods pinched from UserList and adapted ###
-    def __repr__(self): return repr(self._main._sequence)
-
-    # FIXME: do we need to check if we are comparing with another ``Keys``
-    #   object? (like the __cast method of UserList)
-    def __lt__(self, other): return self._main._sequence <  other
-    def __le__(self, other): return self._main._sequence <= other
-    def __eq__(self, other): return self._main._sequence == other
-    def __ne__(self, other): return self._main._sequence != other
-    def __gt__(self, other): return self._main._sequence >  other
-    def __ge__(self, other): return self._main._sequence >= other
-    # FIXME: do we need __cmp__ as well as rich comparisons?
-    def __cmp__(self, other): return cmp(self._main._sequence, other)
-
-    def __contains__(self, item): return item in self._main._sequence
-    def __len__(self): return len(self._main._sequence)
-    def __iter__(self): return self._main.iterkeys()
-    def count(self, item): return self._main._sequence.count(item)
-    def index(self, item, *args): return self._main._sequence.index(item, *args)
-    def reverse(self): self._main._sequence.reverse()
-    def sort(self, *args, **kwds): self._main._sequence.sort(*args, **kwds)
-    def __mul__(self, n): return self._main._sequence*n
-    __rmul__ = __mul__
-    def __add__(self, other): return self._main._sequence + other
-    def __radd__(self, other): return other + self._main._sequence
-
-    ## following methods not implemented for keys ##
-    def __delitem__(self, i): raise TypeError('Can\'t delete items from keys')
-    def __iadd__(self, other): raise TypeError('Can\'t add in place to keys')
-    def __imul__(self, n): raise TypeError('Can\'t multiply keys in place')
-    def append(self, item): raise TypeError('Can\'t append items to keys')
-    def insert(self, i, item): raise TypeError('Can\'t insert items into keys')
-    def pop(self, i=-1): raise TypeError('Can\'t pop items from keys')
-    def remove(self, item): raise TypeError('Can\'t remove items from keys')
-    def extend(self, other): raise TypeError('Can\'t extend keys')
-
-class Items(object):
-    """
-    Custom object for accessing the items of an OrderedDict.
-    
-    Can be called like the normal ``OrderedDict.items`` method, but also
-    supports indexing and sequence methods.
-    """
-
-    def __init__(self, main):
-        self._main = main
-
-    def __call__(self):
-        """Pretend to be the items method."""
-        return self._main._items()
-
-    def __getitem__(self, index):
-        """Fetch the item at position i."""
-        if isinstance(index, types.SliceType):
-            # fetching a slice returns an OrderedDict
-            return self._main[index].items()
-        key = self._main._sequence[index]
-        return (key, self._main[key])
-
-    def __setitem__(self, index, item):
-        """Set item at position i to item."""
-        if isinstance(index, types.SliceType):
-            # NOTE: item must be an iterable (list of tuples)
-            self._main[index] = OrderedDict(item)
-        else:
-            # FIXME: Does this raise a sensible error?
-            orig = self._main.keys[index]
-            key, value = item
-            if self._main.strict and key in self and (key != orig):
-                raise ValueError('slice assignment must be from '
-                        'unique keys')
-            # delete the current one
-            del self._main[self._main._sequence[index]]
-            self._main.insert(index, key, value)
-
-    def __delitem__(self, i):
-        """Delete the item at position i."""
-        key = self._main._sequence[i]
-        if isinstance(i, types.SliceType):
-            for k in key:
-                # FIXME: efficiency?
-                del self._main[k]
-        else:
-            del self._main[key]
-
-    ### following methods pinched from UserList and adapted ###
-    def __repr__(self): return repr(self._main.items())
-
-    # FIXME: do we need to check if we are comparing with another ``Items``
-    #   object? (like the __cast method of UserList)
-    def __lt__(self, other): return self._main.items() <  other
-    def __le__(self, other): return self._main.items() <= other
-    def __eq__(self, other): return self._main.items() == other
-    def __ne__(self, other): return self._main.items() != other
-    def __gt__(self, other): return self._main.items() >  other
-    def __ge__(self, other): return self._main.items() >= other
-    def __cmp__(self, other): return cmp(self._main.items(), other)
-
-    def __contains__(self, item): return item in self._main.items()
-    def __len__(self): return len(self._main._sequence) # easier :-)
-    def __iter__(self): return self._main.iteritems()
-    def count(self, item): return self._main.items().count(item)
-    def index(self, item, *args): return self._main.items().index(item, *args)
-    def reverse(self): self._main.reverse()
-    def sort(self, *args, **kwds): self._main.sort(*args, **kwds)
-    def __mul__(self, n): return self._main.items()*n
-    __rmul__ = __mul__
-    def __add__(self, other): return self._main.items() + other
-    def __radd__(self, other): return other + self._main.items()
-
-    def append(self, item):
-        """Add an item to the end."""
-        # FIXME: this is only append if the key isn't already present
-        key, value = item
-        self._main[key] = value
-
-    def insert(self, i, item):
-        key, value = item
-        self._main.insert(i, key, value)
-
-    def pop(self, i=-1):
-        key = self._main._sequence[i]
-        return (key, self._main.pop(key))
-
-    def remove(self, item):
-        key, value = item
-        try:
-            assert value == self._main[key]
-        except (KeyError, AssertionError):
-            raise ValueError('ValueError: list.remove(x): x not in list')
-        else:
-            del self._main[key]
-
-    def extend(self, other):
-        # FIXME: is only a true extend if none of the keys already present
-        for item in other:
-            key, value = item
-            self._main[key] = value
-
-    def __iadd__(self, other):
-        self.extend(other)
-
-    ## following methods not implemented for items ##
-
-    def __imul__(self, n): raise TypeError('Can\'t multiply items in place')
-
-class Values(object):
-    """
-    Custom object for accessing the values of an OrderedDict.
-    
-    Can be called like the normal ``OrderedDict.values`` method, but also
-    supports indexing and sequence methods.
-    """
-
-    def __init__(self, main):
-        self._main = main
-
-    def __call__(self):
-        """Pretend to be the values method."""
-        return self._main._values()
-
-    def __getitem__(self, index):
-        """Fetch the value at position i."""
-        if isinstance(index, types.SliceType):
-            return [self._main[key] for key in self._main._sequence[index]]
-        else:
-            return self._main[self._main._sequence[index]]
-
-    def __setitem__(self, index, value):
-        """
-        Set the value at position i to value.
-        
-        You can only do slice assignment to values if you supply a sequence of
-        equal length to the slice you are replacing.
-        """
-        if isinstance(index, types.SliceType):
-            keys = self._main._sequence[index]
-            if len(keys) != len(value):
-                raise ValueError('attempt to assign sequence of size %s '
-                    'to slice of size %s' % (len(name), len(keys)))
-            # FIXME: efficiency?  Would be better to calculate the indexes
-            #   directly from the slice object
-            # NOTE: the new keys can collide with existing keys (or even
-            #   contain duplicates) - these will overwrite
-            for key, val in zip(keys, value):
-                self._main[key] = val
-        else:
-            self._main[self._main._sequence[index]] = value
-
-    ### following methods pinched from UserList and adapted ###
-    def __repr__(self): return repr(self._main.values())
-
-    # FIXME: do we need to check if we are comparing with another ``Values``
-    #   object? (like the __cast method of UserList)
-    def __lt__(self, other): return self._main.values() <  other
-    def __le__(self, other): return self._main.values() <= other
-    def __eq__(self, other): return self._main.values() == other
-    def __ne__(self, other): return self._main.values() != other
-    def __gt__(self, other): return self._main.values() >  other
-    def __ge__(self, other): return self._main.values() >= other
-    def __cmp__(self, other): return cmp(self._main.values(), other)
-
-    def __contains__(self, item): return item in self._main.values()
-    def __len__(self): return len(self._main._sequence) # easier :-)
-    def __iter__(self): return self._main.itervalues()
-    def count(self, item): return self._main.values().count(item)
-    def index(self, item, *args): return self._main.values().index(item, *args)
-
-    def reverse(self):
-        """Reverse the values"""
-        vals = self._main.values()
-        vals.reverse()
-        # FIXME: efficiency
-        self[:] = vals
-
-    def sort(self, *args, **kwds):
-        """Sort the values."""
-        vals = self._main.values()
-        vals.sort(*args, **kwds)
-        self[:] = vals
-
-    def __mul__(self, n): return self._main.values()*n
-    __rmul__ = __mul__
-    def __add__(self, other): return self._main.values() + other
-    def __radd__(self, other): return other + self._main.values()
-
-    ## following methods not implemented for values ##
-    def __delitem__(self, i): raise TypeError('Can\'t delete items from values')
-    def __iadd__(self, other): raise TypeError('Can\'t add in place to values')
-    def __imul__(self, n): raise TypeError('Can\'t multiply values in place')
-    def append(self, item): raise TypeError('Can\'t append items to values')
-    def insert(self, i, item): raise TypeError('Can\'t insert items into values')
-    def pop(self, i=-1): raise TypeError('Can\'t pop items from values')
-    def remove(self, item): raise TypeError('Can\'t remove items from values')
-    def extend(self, other): raise TypeError('Can\'t extend values')
-
-class SequenceOrderedDict(OrderedDict):
-    """
-    Experimental version of OrderedDict that has a custom object for ``keys``,
-    ``values``, and ``items``.
-    
-    These are callable sequence objects that work as methods, or can be
-    manipulated directly as sequences.
-    
-    Test for ``keys``, ``items`` and ``values``.
-    
-    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
-    >>> d
-    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
-    >>> d.keys
-    [1, 2, 3]
-    >>> d.keys()
-    [1, 2, 3]
-    >>> d.setkeys((3, 2, 1))
-    >>> d
-    SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
-    >>> d.setkeys((1, 2, 3))
-    >>> d.keys[0]
-    1
-    >>> d.keys[:]
-    [1, 2, 3]
-    >>> d.keys[-1]
-    3
-    >>> d.keys[-2]
-    2
-    >>> d.keys[0:2] = [2, 1]
-    >>> d
-    SequenceOrderedDict([(2, 3), (1, 2), (3, 4)])
-    >>> d.keys.reverse()
-    >>> d.keys
-    [3, 1, 2]
-    >>> d.keys = [1, 2, 3]
-    >>> d
-    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
-    >>> d.keys = [3, 1, 2]
-    >>> d
-    SequenceOrderedDict([(3, 4), (1, 2), (2, 3)])
-    >>> a = SequenceOrderedDict()
-    >>> b = SequenceOrderedDict()
-    >>> a.keys == b.keys
-    1
-    >>> a['a'] = 3
-    >>> a.keys == b.keys
-    0
-    >>> b['a'] = 3
-    >>> a.keys == b.keys
-    1
-    >>> b['b'] = 3
-    >>> a.keys == b.keys
-    0
-    >>> a.keys > b.keys
-    0
-    >>> a.keys < b.keys
-    1
-    >>> 'a' in a.keys
-    1
-    >>> len(b.keys)
-    2
-    >>> 'c' in d.keys
-    0
-    >>> 1 in d.keys
-    1
-    >>> [v for v in d.keys]
-    [3, 1, 2]
-    >>> d.keys.sort()
-    >>> d.keys
-    [1, 2, 3]
-    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)), strict=True)
-    >>> d.keys[::-1] = [1, 2, 3]
-    >>> d
-    SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
-    >>> d.keys[:2]
-    [3, 2]
-    >>> d.keys[:2] = [1, 3]
-    Traceback (most recent call last):
-    KeyError: 'Keylist is not the same as current keylist.'
-
-    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
-    >>> d
-    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
-    >>> d.values
-    [2, 3, 4]
-    >>> d.values()
-    [2, 3, 4]
-    >>> d.setvalues((4, 3, 2))
-    >>> d
-    SequenceOrderedDict([(1, 4), (2, 3), (3, 2)])
-    >>> d.values[::-1]
-    [2, 3, 4]
-    >>> d.values[0]
-    4
-    >>> d.values[-2]
-    3
-    >>> del d.values[0]
-    Traceback (most recent call last):
-    TypeError: Can't delete items from values
-    >>> d.values[::2] = [2, 4]
-    >>> d
-    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
-    >>> 7 in d.values
-    0
-    >>> len(d.values)
-    3
-    >>> [val for val in d.values]
-    [2, 3, 4]
-    >>> d.values[-1] = 2
-    >>> d.values.count(2)
-    2
-    >>> d.values.index(2)
-    0
-    >>> d.values[-1] = 7
-    >>> d.values
-    [2, 3, 7]
-    >>> d.values.reverse()
-    >>> d.values
-    [7, 3, 2]
-    >>> d.values.sort()
-    >>> d.values
-    [2, 3, 7]
-    >>> d.values.append('anything')
-    Traceback (most recent call last):
-    TypeError: Can't append items to values
-    >>> d.values = (1, 2, 3)
-    >>> d
-    SequenceOrderedDict([(1, 1), (2, 2), (3, 3)])
-    
-    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
-    >>> d
-    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
-    >>> d.items()
-    [(1, 2), (2, 3), (3, 4)]
-    >>> d.setitems([(3, 4), (2 ,3), (1, 2)])
-    >>> d
-    SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
-    >>> d.items[0]
-    (3, 4)
-    >>> d.items[:-1]
-    [(3, 4), (2, 3)]
-    >>> d.items[1] = (6, 3)
-    >>> d.items
-    [(3, 4), (6, 3), (1, 2)]
-    >>> d.items[1:2] = [(9, 9)]
-    >>> d
-    SequenceOrderedDict([(3, 4), (9, 9), (1, 2)])
-    >>> del d.items[1:2]
-    >>> d
-    SequenceOrderedDict([(3, 4), (1, 2)])
-    >>> (3, 4) in d.items
-    1
-    >>> (4, 3) in d.items
-    0
-    >>> len(d.items)
-    2
-    >>> [v for v in d.items]
-    [(3, 4), (1, 2)]
-    >>> d.items.count((3, 4))
-    1
-    >>> d.items.index((1, 2))
-    1
-    >>> d.items.index((2, 1))
-    Traceback (most recent call last):
-    ValueError: list.index(x): x not in list
-    >>> d.items.reverse()
-    >>> d.items
-    [(1, 2), (3, 4)]
-    >>> d.items.reverse()
-    >>> d.items.sort()
-    >>> d.items
-    [(1, 2), (3, 4)]
-    >>> d.items.append((5, 6))
-    >>> d.items
-    [(1, 2), (3, 4), (5, 6)]
-    >>> d.items.insert(0, (0, 0))
-    >>> d.items
-    [(0, 0), (1, 2), (3, 4), (5, 6)]
-    >>> d.items.insert(-1, (7, 8))
-    >>> d.items
-    [(0, 0), (1, 2), (3, 4), (7, 8), (5, 6)]
-    >>> d.items.pop()
-    (5, 6)
-    >>> d.items
-    [(0, 0), (1, 2), (3, 4), (7, 8)]
-    >>> d.items.remove((1, 2))
-    >>> d.items
-    [(0, 0), (3, 4), (7, 8)]
-    >>> d.items.extend([(1, 2), (5, 6)])
-    >>> d.items
-    [(0, 0), (3, 4), (7, 8), (1, 2), (5, 6)]
-    """
-
-    def __init__(self, init_val=(), strict=True):
-        OrderedDict.__init__(self, init_val, strict=strict)
-        self._keys = self.keys
-        self._values = self.values
-        self._items = self.items
-        self.keys = Keys(self)
-        self.values = Values(self)
-        self.items = Items(self)
-        self._att_dict = {
-            'keys': self.setkeys,
-            'items': self.setitems,
-            'values': self.setvalues,
-        }
-
-    def __setattr__(self, name, value):
-        """Protect keys, items, and values."""
-        if not '_att_dict' in self.__dict__:
-            object.__setattr__(self, name, value)
-        else:
-            try:
-                fun = self._att_dict[name]
-            except KeyError:
-                OrderedDict.__setattr__(self, name, value)
-            else:
-                fun(value)
-
-if __name__ == '__main__':
-    if INTP_VER < (2, 3):
-        raise RuntimeError("Tests require Python v.2.3 or later")
-    # turn off warnings for tests
-    warnings.filterwarnings('ignore')
-    # run the code tests in doctest format
-    import doctest
-    m = sys.modules.get('__main__')
-    globs = m.__dict__.copy()
-    globs.update({
-        'INTP_VER': INTP_VER,
-    })
-    doctest.testmod(m, globs=globs)
-
diff --git a/forum/views/README b/forum/views/README
deleted file mode 100644 (file)
index 5416f88..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-readers.py - views strictly reading main content: questions, answers, tags and comments
-
-writers.py - views that write main content, with possible reading
-             note: deletion counts as writing in this case
-
-commands.py - data status changing commands, votes, question close/reopen
-
-users.py - user views - user listing and profiles
-
-meta.py - privacy, about, faq, feedback, logout, badges
-
-auth.py - Authentication related views
index 2fb2be4223d3005a44abf610363405ab8dc12896..da8f2c0c3679eac18788af71ca74233d47f263b4 100644 (file)
@@ -62,8 +62,8 @@ class CannotDoubleActionException(Exception):
 
 
 @command
-def vote_post(request, post_type, id, vote_type):
-    post = get_object_or_404(post_type == "question" and Question or Answer, id=id)
+def vote_post(request, id, vote_type):
+    post = get_object_or_404(Node, id=id)
     vote_score = vote_type == 'up' and 1 or -1
     user = request.user
 
@@ -94,13 +94,13 @@ def vote_post(request, post_type, id, vote_type):
         vote_type = 'none'
     except ObjectDoesNotExist:
         #there is no vote yet
-        vote = Vote(user=user, content_object=post, vote=vote_score)
+        vote = Vote(user=user, node=post, vote=vote_score)
         vote.save()
 
     response = {
         'commands': {
-            'update_post_score': [post_type, id, vote.vote * (vote_type == 'none' and -1 or 1)],
-            'update_user_post_vote': [post_type, id, vote_type]
+            'update_post_score': [id, vote.vote * (vote_type == 'none' and -1 or 1)],
+            'update_user_post_vote': [id, vote_type]
         }
     }
 
@@ -218,8 +218,8 @@ def mark_favorite(request, id):
     }
 
 @command
-def comment(request, post_type, id):
-    post = get_object_or_404(post_type == "question" and Question or Answer, id=id)
+def comment(request, id):
+    post = get_object_or_404(Node, id=id)
     user = request.user
 
     if not user.is_authenticated():
@@ -237,7 +237,7 @@ def comment(request, post_type, id):
         if not user.can_comment(post):
             raise NotEnoughRepPointsException( _('comment'))
 
-        comment = Comment(user=user, content_object=post)
+        comment = Comment(user=user, node=post)
 
     comment_text = request.POST.get('comment', '').strip()
 
@@ -251,8 +251,7 @@ def comment(request, post_type, id):
         return {
             'commands': {
                 'insert_comment': [
-                    post_type, id,
-                    comment.id, comment_text, user.username, user.get_profile_url(), reverse('delete_comment', kwargs={'id': comment.id})
+                    id, comment.id, comment_text, user.username, user.get_profile_url(), reverse('delete_comment', kwargs={'id': comment.id})
                 ]
             }
         }
@@ -288,6 +287,8 @@ def accept_answer(request, id):
             accepted.unmark_accepted()
             commands['unmark_accepted'] = [accepted.id]
         except:
+            #import sys, traceback
+            #traceback.print_exc(file=sys.stdout)
             pass
 
         answer.mark_accepted(user)
index da51e1a5b9247a8ab4ff3a9e14871fdfdb9b5b74..cf5f90373288f5b5a7e45dca546a1bb88e0b4e67 100644 (file)
@@ -61,8 +61,8 @@ def command(func):
             response = func(request, *args, **kwargs)\r
             response['success'] = True\r
         except Exception, e:\r
-            import sys, traceback\r
-            traceback.print_exc(file=sys.stdout)\r
+            #import sys, traceback\r
+            #traceback.print_exc(file=sys.stdout)\r
 \r
             response = {\r
                 'success': False,\r
index 9172087e4df64b0d177833d903af895c16aa6924..02cfbf77cae19d0c601711a01a3afa60bfe080ac 100644 (file)
@@ -10,16 +10,13 @@ from django.utils.translation import ugettext as _
 from forum.utils.forms import get_next_url
 from forum.models import Badge, Award
 from forum.badges import ALL_BADGES
-from markdown2 import Markdown
 from forum import settings
 
 def favicon(request):
     return HttpResponseRedirect(str(settings.APP_FAVICON))
 
 def about(request):
-    markdowner = Markdown(html4tags=True)
-    text = markdowner.convert(settings.ABOUT_PAGE_TEXT.value)
-    return render_to_response('about.html', {'text': text }, context_instance=RequestContext(request))
+    return render_to_response('about.html', {'text': settings.ABOUT_PAGE_TEXT.value }, context_instance=RequestContext(request))
 
 def faq(request):
     data = {
index 53236d506bf78dd18a0a1dd1baa6301351ed58c4..819384f9e05e31b628bb0816619efc467c872859 100644 (file)
@@ -7,6 +7,7 @@ from django.shortcuts import render_to_response, get_object_or_404
 from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
 from django.core.paginator import Paginator, EmptyPage, InvalidPage
 from django.template import RequestContext
+from django import template
 from django.utils.html import *
 from django.utils import simplejson
 from django.db.models import Q
@@ -20,7 +21,6 @@ from django.template.defaultfilters import slugify
 from django.utils.safestring import mark_safe
 
 from forum.utils.html import sanitize_html
-from markdown2 import Markdown
 from forum.utils.diff import textDiff as htmldiff
 from forum.forms import *
 from forum.models import *
@@ -41,8 +41,6 @@ QUESTIONS_PAGE_SIZE = 30
 # used in answers
 ANSWERS_PAGE_SIZE = 10
 
-markdowner = Markdown(html4tags=True)
-
 #system to display main content
 def _get_tags_cache_json():#service routine used by views requiring tag list in the javascript space
     """returns list of all tags in json format
@@ -192,11 +190,10 @@ def update_question_view_times(request, question):
         request.session['question_view_times'] = {}
 
     last_seen = request.session['question_view_times'].get(question.id,None)
-    updated_when, updated_who = question.get_last_update_info()
 
-    if not last_seen or last_seen < updated_when:
-        question.view_count = question.view_count + 1
+    if not last_seen or last_seen < question.last_activity_at:
         question_view.send(sender=update_question_view_times, instance=question, user=request.user)
+        request.session['question_view_times'][question.id] = datetime.datetime.now()
 
     request.session['question_view_times'][question.id] = datetime.datetime.now()
 
@@ -212,7 +209,7 @@ def question(request, id, slug):
     if question.deleted and not request.user.can_view_deleted_post(question):
         raise Http404
 
-    answer_form = AnswerForm(question,request.user)
+    answer_form = AnswerForm(question)
     answers = request.user.get_visible_answers(question)
 
     if answers is not None:
@@ -254,51 +251,35 @@ def question(request, id, slug):
         }, context_instance=RequestContext(request))
 
 
-QUESTION_REVISION_TEMPLATE = ('<h1>%(title)s</h1>\n'
-                              '<div class="text">%(html)s</div>\n'
-                              '<div class="tags">%(tags)s</div>')
-def question_revisions(request, id):
-    post = get_object_or_404(Question, id=id)
-    revisions = list(post.revisions.all())
-    revisions.reverse()
+REVISION_TEMPLATE = template.loader.get_template('node/revision.html')
+
+def revisions(request, id):
+    post = get_object_or_404(Node, id=id).leaf
+    revisions = list(post.revisions.order_by('revised_at'))
+
+    rev_ctx = []
+
     for i, revision in enumerate(revisions):
-        revision.html = QUESTION_REVISION_TEMPLATE % {
-            'title': revision.title,
-            'html': sanitize_html(markdowner.convert(revision.text)),
-            'tags': ' '.join(['<a class="post-tag">%s</a>' % tag
-                              for tag in revision.tagnames.split(' ')]),
-        }
+        rev_ctx.append(dict(inst=revision, html=REVISION_TEMPLATE.render(template.Context({
+                'title': revision.title,
+                'html': revision.html,
+                'tags': revision.tagname_list(),
+        }))))
+
         if i > 0:
-            revisions[i].diff = htmldiff(revisions[i-1].html, revision.html)
+            rev_ctx[i]['diff'] = mark_safe(htmldiff(rev_ctx[i-1]['html'], rev_ctx[i]['html']))
         else:
-            revisions[i].diff = QUESTION_REVISION_TEMPLATE % {
-                'title': revisions[0].title,
-                'html': sanitize_html(markdowner.convert(revisions[0].text)),
-                'tags': ' '.join(['<a class="post-tag">%s</a>' % tag
-                                 for tag in revisions[0].tagnames.split(' ')]),
-            }
-            revisions[i].summary = _('initial version') 
-    return render_to_response('revisions_question.html', {
-                              'post': post,
-                              'revisions': revisions,
-                              }, context_instance=RequestContext(request))
+            rev_ctx[i]['diff'] = mark_safe(rev_ctx[i]['html'])
 
-ANSWER_REVISION_TEMPLATE = ('<div class="text">%(html)s</div>')
-def answer_revisions(request, id):
-    post = get_object_or_404(Answer, id=id)
-    revisions = list(post.revisions.all())
-    revisions.reverse()
-    for i, revision in enumerate(revisions):
-        revision.html = ANSWER_REVISION_TEMPLATE % {
-            'html': sanitize_html(markdowner.convert(revision.text))
-        }
-        if i > 0:
-            revisions[i].diff = htmldiff(revisions[i-1].html, revision.html)
+        if not (revision.summary):
+            rev_ctx[i]['summary'] = _('Revision n. %(rev_number)d') % {'rev_number': revision.revision}
         else:
-            revisions[i].diff = revisions[i].text
-            revisions[i].summary = _('initial version')
-    return render_to_response('revisions_answer.html', {
+            rev_ctx[i]['summary'] = revision.summary
+            
+    return render_to_response('revisions_question.html', {
                               'post': post,
-                              'revisions': revisions,
+                              'revisions': rev_ctx,
                               }, context_instance=RequestContext(request))
 
+
+
index e3dcc08f2e6ca0110d0e01d58a1d00ec1d1d8faa..501b63a315fba44d4ceb32b758a77892bc7a71e0 100644 (file)
@@ -15,22 +15,10 @@ from django.utils import simplejson
 from django.core.urlresolvers import reverse\r
 from forum.forms import *\r
 from forum.utils.html import sanitize_html\r
-from forum.authentication import user_updated \r
-import time\r
-from django.contrib.contenttypes.models import ContentType\r
+from forum.authentication import user_updated\r
+import decorators\r
 \r
-question_type = ContentType.objects.get_for_model(Question)\r
-answer_type = ContentType.objects.get_for_model(Answer)\r
-comment_type = ContentType.objects.get_for_model(Comment)\r
-question_revision_type = ContentType.objects.get_for_model(QuestionRevision)\r
-answer_revision_type = ContentType.objects.get_for_model(AnswerRevision)\r
-repute_type = ContentType.objects.get_for_model(Repute)\r
-question_type_id = question_type.id\r
-answer_type_id = answer_type.id\r
-comment_type_id = comment_type.id\r
-question_revision_type_id = question_revision_type.id\r
-answer_revision_type_id = answer_revision_type.id\r
-repute_type_id = repute_type.id\r
+import time\r
 \r
 USERS_PAGE_SIZE = 35# refactor - move to some constants file\r
 \r
@@ -64,7 +52,7 @@ def users(request):
     except (EmptyPage, InvalidPage):\r
         users = objects_list.page(objects_list.num_pages)\r
 \r
-    return render_to_response('users.html', {\r
+    return render_to_response('users/users.html', {\r
                                 "users" : users,\r
                                 "suser" : suser,\r
                                 "keywords" : suser,\r
@@ -139,23 +127,38 @@ def edit_user(request, id):
             return HttpResponseRedirect(user.get_profile_url())\r
     else:\r
         form = EditUserForm(user)\r
-    return render_to_response('user_edit.html', {\r
+    return render_to_response('users/edit.html', {\r
                                                 'form' : form,\r
                                                 'gravatar_faq_url' : reverse('faq') + '#gravatar',\r
                                     }, context_instance=RequestContext(request))\r
 \r
-def user_stats(request, user_id, user_view):\r
-    user = get_object_or_404(User, id=user_id)\r
 \r
-    questions = user.questions.filter(deleted=False).order_by('-added_at')\r
-    answers = user.answers.filter(deleted=False).order_by('-added_at')\r
+\r
+def user_view(template, tab_name, tab_description, page_title):\r
+    def decorator(fn):\r
+        def decorated(request, id, slug=None):\r
+            context = fn(request, get_object_or_404(User, id=id))\r
+            context.update({\r
+                "tab_name" : tab_name,\r
+                "tab_description" : tab_description,\r
+                "page_title" : page_title,\r
+            })\r
+            return render_to_response(template, context, context_instance=RequestContext(request))\r
+        return decorated\r
+    return decorator\r
+\r
+\r
+@user_view('users/stats.html', 'stats', _('user profile'), _('user profile overview'))\r
+def user_stats(request, user):\r
+    questions = Question.objects.filter(author=user, deleted=False).order_by('-added_at')\r
+    answers = Answer.objects.filter(author=user, deleted=False).order_by('-added_at')\r
 \r
     up_votes = user.get_up_vote_count()\r
     down_votes = user.get_down_vote_count()\r
     votes_today = user.get_vote_count_today()\r
     votes_total = int(settings.MAX_VOTES_PER_DAY)\r
 \r
-    user_tags = Tag.objects.filter(Q(questions__author=user) | Q(questions__answers__author=user)) \\r
+    user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \\r
         .annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')\r
 \r
     awards = Badge.objects.filter(award_badge__user=user).annotate(count=Count('name')).order_by('-count')\r
@@ -165,499 +168,39 @@ def user_stats(request, user_id, user_view):
     else:\r
         moderate_user_form = None\r
 \r
-    return render_to_response(user_view.template_file,{\r
-                                'moderate_user_form': moderate_user_form,\r
-                                "tab_name" : user_view.id,\r
-                                "tab_description" : user_view.tab_description,\r
-                                "page_title" : user_view.page_title,\r
-                                "view_user" : user,\r
-                                "questions" : questions,\r
-                                "answers" : answers,\r
-                                "up_votes" : up_votes,\r
-                                "down_votes" : down_votes,\r
-                                "total_votes": up_votes + down_votes,\r
-                                "votes_today_left": votes_total-votes_today,\r
-                                "votes_total_per_day": votes_total,\r
-                                "user_tags" : user_tags[:50],\r
-                                "awards": awards,\r
-                                "total_awards" : awards.count(),\r
-                            }, context_instance=RequestContext(request))\r
-\r
-def user_recent(request, user_id, user_view):\r
-    user = get_object_or_404(User, id=user_id)\r
-    def get_type_name(type_id):\r
-        for item in TYPE_ACTIVITY:\r
-            if type_id in item:\r
-                return item[1]\r
-\r
-    class Event:\r
-        def __init__(self, time, type, title, summary, answer_id, question_id):\r
-            self.time = time\r
-            self.type = get_type_name(type)\r
-            self.type_id = type\r
-            self.title = title\r
-            self.summary = summary\r
-            slug_title = slugify(title)\r
-            self.title_link = reverse('question', kwargs={'id':question_id, 'slug':slug_title})\r
-            if int(answer_id) > 0:\r
-                self.title_link += '#%s' % answer_id\r
-\r
-    class AwardEvent:\r
-        def __init__(self, time, type, id):\r
-            self.time = time\r
-            self.type = get_type_name(type)\r
-            self.type_id = type\r
-            self.badge = get_object_or_404(Badge, id=id)\r
-\r
-    activities = []\r
-    # ask questions\r
-    questions = Activity.objects.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'question.id',\r
-            'active_at' : 'activity.active_at',\r
-            'activity_type' : 'activity.activity_type'\r
-            },\r
-        tables=['activity', 'question'],\r
-        where=['activity.content_type_id = %s AND activity.object_id = ' +\r
-            'question.id AND NOT question.deleted AND activity.user_id = %s AND activity.activity_type = %s'],\r
-        params=[question_type_id, user_id, TYPE_ACTIVITY_ASK_QUESTION],\r
-        order_by=['-activity.active_at']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'active_at',\r
-            'activity_type'\r
-            )\r
-    if len(questions) > 0:\r
-        questions = [(Event(q['active_at'], q['activity_type'], q['title'], '', '0', \\r
-                      q['question_id'])) for q in questions]\r
-        activities.extend(questions)\r
-\r
-    # answers\r
-    answers = Activity.objects.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'question.id',\r
-            'answer_id' : 'answer.id',\r
-            'active_at' : 'activity.active_at',\r
-            'activity_type' : 'activity.activity_type'\r
-            },\r
-        tables=['activity', 'answer', 'question'],\r
-        where=['activity.content_type_id = %s AND activity.object_id = answer.id AND ' + \r
-            'answer.question_id=question.id AND NOT answer.deleted AND activity.user_id=%s AND '+\r
-            'activity.activity_type=%s AND NOT question.deleted'],\r
-        params=[answer_type_id, user_id, TYPE_ACTIVITY_ANSWER],\r
-        order_by=['-activity.active_at']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'answer_id',\r
-            'active_at',\r
-            'activity_type'\r
-            )\r
-    if len(answers) > 0:\r
-        answers = [(Event(q['active_at'], q['activity_type'], q['title'], '', q['answer_id'], \\r
-                    q['question_id'])) for q in answers]\r
-        activities.extend(answers)\r
-\r
-    # question comments\r
-    comments = Activity.objects.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'comment.object_id',\r
-            'added_at' : 'comment.added_at',\r
-            'activity_type' : 'activity.activity_type'\r
-            },\r
-        tables=['activity', 'question', 'comment'],\r
-\r
-        where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+\r
-            'activity.user_id = comment.user_id AND comment.object_id=question.id AND '+\r
-            'comment.content_type_id=%s AND activity.user_id = %s AND activity.activity_type=%s AND ' +\r
-            'NOT question.deleted'],\r
-        params=[comment_type_id, question_type_id, user_id, TYPE_ACTIVITY_COMMENT_QUESTION],\r
-        order_by=['-comment.added_at']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'added_at',\r
-            'activity_type'\r
-            )\r
-\r
-    if len(comments) > 0:\r
-        comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \\r
-                     q['question_id'])) for q in comments]\r
-        activities.extend(comments)\r
-\r
-    # answer comments\r
-    comments = Activity.objects.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'question.id',\r
-            'answer_id' : 'answer.id',\r
-            'added_at' : 'comment.added_at',\r
-            'activity_type' : 'activity.activity_type'\r
-            },\r
-        tables=['activity', 'question', 'answer', 'comment'],\r
-\r
-        where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+\r
-            'activity.user_id = comment.user_id AND comment.object_id=answer.id AND '+\r
-            'comment.content_type_id=%s AND question.id = answer.question_id AND '+\r
-            'activity.user_id = %s AND activity.activity_type=%s AND '+\r
-            'NOT answer.deleted AND NOT question.deleted'],\r
-        params=[comment_type_id, answer_type_id, user_id, TYPE_ACTIVITY_COMMENT_ANSWER],\r
-        order_by=['-comment.added_at']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'answer_id',\r
-            'added_at',\r
-            'activity_type'\r
-            )\r
-\r
-    if len(comments) > 0:\r
-        comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', q['answer_id'], \\r
-                     q['question_id'])) for q in comments]\r
-        activities.extend(comments)\r
-\r
-    # question revisions\r
-    revisions = Activity.objects.extra(\r
-        select={\r
-            'title' : 'question_revision.title',\r
-            'question_id' : 'question_revision.question_id',\r
-            'added_at' : 'activity.active_at',\r
-            'activity_type' : 'activity.activity_type',\r
-            'summary' : 'question_revision.summary'\r
-            },\r
-        tables=['activity', 'question_revision', 'question'],\r
-        where=['activity.content_type_id = %s AND activity.object_id = question_revision.id AND '+\r
-            'question_revision.id=question.id AND NOT question.deleted AND '+\r
-            'activity.user_id = question_revision.author_id AND activity.user_id = %s AND '+\r
-            'activity.activity_type=%s'],\r
-        params=[question_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_QUESTION],\r
-        order_by=['-activity.active_at']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'added_at',\r
-            'activity_type',\r
-            'summary'\r
-            )\r
-\r
-    if len(revisions) > 0:\r
-        revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], '0', \\r
-                      q['question_id'])) for q in revisions]\r
-        activities.extend(revisions)\r
-\r
-    # answer revisions\r
-    revisions = Activity.objects.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'question.id',\r
-            'answer_id' : 'answer.id',\r
-            'added_at' : 'activity.active_at',\r
-            'activity_type' : 'activity.activity_type',\r
-            'summary' : 'answer_revision.summary'\r
-            },\r
-        tables=['activity', 'answer_revision', 'question', 'answer'],\r
-\r
-        where=['activity.content_type_id = %s AND activity.object_id = answer_revision.id AND '+\r
-            'activity.user_id = answer_revision.author_id AND activity.user_id = %s AND '+\r
-            'answer_revision.answer_id=answer.id AND answer.question_id = question.id AND '+\r
-            'NOT question.deleted AND NOT answer.deleted AND '+\r
-            'activity.activity_type=%s'],\r
-        params=[answer_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_ANSWER],\r
-        order_by=['-activity.active_at']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'added_at',\r
-            'answer_id',\r
-            'activity_type',\r
-            'summary'\r
-            )\r
-\r
-    if len(revisions) > 0:\r
-        revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], \\r
-                      q['answer_id'], q['question_id'])) for q in revisions]\r
-        activities.extend(revisions)\r
-\r
-    # accepted answers\r
-    accept_answers = Activity.objects.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'question.id',\r
-            'added_at' : 'activity.active_at',\r
-            'activity_type' : 'activity.activity_type',\r
-            },\r
-        tables=['activity', 'answer', 'question'],\r
-        where=['activity.content_type_id = %s AND activity.object_id = answer.id AND '+\r
-            'activity.user_id = question.author_id AND activity.user_id = %s AND '+\r
-            'NOT answer.deleted AND NOT question.deleted AND '+\r
-            'answer.question_id=question.id AND activity.activity_type=%s'],\r
-        params=[answer_type_id, user_id, TYPE_ACTIVITY_MARK_ANSWER],\r
-        order_by=['-activity.active_at']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'added_at',\r
-            'activity_type',\r
-            )\r
-    if len(accept_answers) > 0:\r
-        accept_answers = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \\r
-            q['question_id'])) for q in accept_answers]\r
-        activities.extend(accept_answers)\r
-    #award history\r
-    awards = Activity.objects.extra(\r
-        select={\r
-            'badge_id' : 'badge.id',\r
-            'awarded_at': 'award.awarded_at',\r
-            'activity_type' : 'activity.activity_type'\r
-            },\r
-        tables=['activity', 'award', 'badge'],\r
-        where=['activity.user_id = award.user_id AND activity.user_id = %s AND '+\r
-            'award.badge_id=badge.id AND activity.object_id=award.id AND activity.activity_type=%s'],\r
-        params=[user_id, TYPE_ACTIVITY_PRIZE],\r
-        order_by=['-activity.active_at']\r
-    ).values(\r
-            'badge_id',\r
-            'awarded_at',\r
-            'activity_type'\r
-            )\r
-    if len(awards) > 0:\r
-        awards = [(AwardEvent(q['awarded_at'], q['activity_type'], q['badge_id'])) for q in awards]\r
-        activities.extend(awards)\r
-\r
-    activities.sort(lambda x,y: cmp(y.time, x.time))\r
-\r
-    return render_to_response(user_view.template_file,{\r
-                                    "tab_name" : user_view.id,\r
-                                    "tab_description" : user_view.tab_description,\r
-                                    "page_title" : user_view.page_title,\r
-                                    "view_user" : user,\r
-                                    "activities" : activities[:user_view.data_size]\r
-                                }, context_instance=RequestContext(request))\r
+    return {'moderate_user_form': moderate_user_form,\r
+            "view_user" : user,\r
+            "questions" : questions,\r
+            "answers" : answers,\r
+            "up_votes" : up_votes,\r
+            "down_votes" : down_votes,\r
+            "total_votes": up_votes + down_votes,\r
+            "votes_today_left": votes_total-votes_today,\r
+            "votes_total_per_day": votes_total,\r
+            "user_tags" : user_tags[:50],\r
+            "awards": awards,\r
+            "total_awards" : awards.count(),\r
+        }\r
 \r
-def user_responses(request, user_id, user_view):\r
-    """\r
-    We list answers for question, comments, and answer accepted by others for this user.\r
-    """\r
-    class Response:\r
-        def __init__(self, type, title, question_id, answer_id, time, username, user_id, content):\r
-            self.type = type\r
-            self.title = title\r
-            self.titlelink = reverse('question', kwargs={'id': question_id, 'slug': slugify(title)}) +u'#%s' % answer_id\r
-            self.time = time\r
-            self.userlink = reverse('users') + u'%s/%s/' % (user_id, username)\r
-            self.username = username\r
-            self.content = u'%s ...' % strip_tags(content)[:300]\r
-\r
-        def __unicode__(self):\r
-            return u'%s %s' % (self.type, self.titlelink)\r
-\r
-    user = get_object_or_404(User, id=user_id)\r
-    responses = []\r
-    answers = Answer.objects.extra(\r
-                                    select={\r
-                                        'title' : 'question.title',\r
-                                        'question_id' : 'question.id',\r
-                                        'answer_id' : 'answer.id',\r
-                                        'added_at' : 'answer.added_at',\r
-                                        'html' : 'answer.html',\r
-                                        'username' : 'auth_user.username',\r
-                                        'user_id' : 'auth_user.id'\r
-                                        },\r
-                                    select_params=[user_id],\r
-                                    tables=['answer', 'question', 'auth_user'],\r
-                                    where=['answer.question_id = question.id AND NOT answer.deleted AND NOT question.deleted AND '+\r
-                                        'question.author_id = %s AND answer.author_id <> %s AND answer.author_id=auth_user.id'],\r
-                                    params=[user_id, user_id],\r
-                                    order_by=['-answer.id']\r
-                                ).values(\r
-                                        'title',\r
-                                        'question_id',\r
-                                        'answer_id',\r
-                                        'added_at',\r
-                                        'html',\r
-                                        'username',\r
-                                        'user_id'\r
-                                        )\r
-    if len(answers) > 0:\r
-        answers = [(Response(TYPE_RESPONSE['QUESTION_ANSWERED'], a['title'], a['question_id'],\r
-        a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers]\r
-        responses.extend(answers)\r
-\r
-\r
-    # question comments\r
-    comments = Comment.active.extra(\r
-                                select={\r
-                                    'title' : 'question.title',\r
-                                    'question_id' : 'comment.object_id',\r
-                                    'added_at' : 'comment.added_at',\r
-                                    'comment' : 'comment.comment',\r
-                                    'username' : 'auth_user.username',\r
-                                    'user_id' : 'auth_user.id'\r
-                                    },\r
-                                tables=['question', 'auth_user', 'comment'],\r
-                                where=['NOT question.deleted AND question.author_id = %s AND comment.object_id=question.id AND '+\r
-                                    'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id'],\r
-                                params=[user_id, question_type_id, user_id],\r
-                                order_by=['-comment.added_at']\r
-                            ).values(\r
-                                    'title',\r
-                                    'question_id',\r
-                                    'added_at',\r
-                                    'comment',\r
-                                    'username',\r
-                                    'user_id'\r
-                                    )\r
-\r
-    if len(comments) > 0:\r
-        comments = [(Response(TYPE_RESPONSE['QUESTION_COMMENTED'], c['title'], c['question_id'],\r
-            '', c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments]\r
-        responses.extend(comments)\r
-\r
-    # answer comments\r
-    comments = Comment.active.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'question.id',\r
-            'answer_id' : 'answer.id',\r
-            'added_at' : 'comment.added_at',\r
-            'comment' : 'comment.comment',\r
-            'username' : 'auth_user.username',\r
-            'user_id' : 'auth_user.id'\r
-            },\r
-        tables=['answer', 'auth_user', 'comment', 'question'],\r
-        where=['NOT answer.deleted AND answer.author_id = %s AND comment.object_id=answer.id AND '+\r
-            'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id '+\r
-            'AND question.id = answer.question_id'],\r
-        params=[user_id, answer_type_id, user_id],\r
-        order_by=['-comment.added_at']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'answer_id',\r
-            'added_at',\r
-            'comment',\r
-            'username',\r
-            'user_id'\r
-            )\r
-\r
-    if len(comments) > 0:\r
-        comments = [(Response(TYPE_RESPONSE['ANSWER_COMMENTED'], c['title'], c['question_id'],\r
-        c['answer_id'], c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments]\r
-        responses.extend(comments)\r
-\r
-    # answer has been accepted\r
-    answers = Answer.objects.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'question.id',\r
-            'answer_id' : 'answer.id',\r
-            'added_at' : 'answer.accepted_at',\r
-            'html' : 'answer.html',\r
-            'username' : 'auth_user.username',\r
-            'user_id' : 'auth_user.id'\r
-            },\r
-        select_params=[user_id],\r
-        tables=['answer', 'question', 'auth_user'],\r
-        where=['answer.question_id = question.id AND NOT answer.deleted AND NOT question.deleted AND '+\r
-            'answer.author_id = %s AND answer.accepted=True AND question.author_id=auth_user.id'],\r
-        params=[user_id],\r
-        order_by=['-answer.id']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'answer_id',\r
-            'added_at',\r
-            'html',\r
-            'username',\r
-            'user_id'\r
-            )\r
-    if len(answers) > 0:\r
-        answers = [(Response(TYPE_RESPONSE['ANSWER_ACCEPTED'], a['title'], a['question_id'],\r
-            a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers]\r
-        responses.extend(answers)\r
-\r
-    # sort posts by time\r
-    responses.sort(lambda x,y: cmp(y.time, x.time))\r
-\r
-    return render_to_response(user_view.template_file,{\r
-        "tab_name" : user_view.id,\r
-        "tab_description" : user_view.tab_description,\r
-        "page_title" : user_view.page_title,\r
-        "view_user" : user,\r
-        "responses" : responses[:user_view.data_size],\r
-\r
-    }, context_instance=RequestContext(request))\r
-\r
-def user_votes(request, user_id, user_view):\r
-    user = get_object_or_404(User, id=user_id)\r
-    if not request.user == user:\r
-        raise Http404\r
-    votes = []\r
-    question_votes = Vote.active.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'question.id',\r
-            'answer_id' : 0,\r
-            'voted_at' : 'vote.voted_at',\r
-            'vote' : 'vote',\r
-            },\r
-        select_params=[user_id],\r
-        tables=['vote', 'question', 'auth_user'],\r
-        where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = question.id '+\r
-            'AND vote.user_id=auth_user.id'],\r
-        params=[question_type_id, user_id],\r
-        order_by=['-vote.id']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'answer_id',\r
-            'voted_at',\r
-            'vote',\r
-            )\r
-    if(len(question_votes) > 0):\r
-        votes.extend(question_votes)\r
-\r
-    answer_votes = Vote.active.extra(\r
-        select={\r
-            'title' : 'question.title',\r
-            'question_id' : 'question.id',\r
-            'answer_id' : 'answer.id',\r
-            'voted_at' : 'vote.voted_at',\r
-            'vote' : 'vote',\r
-            },\r
-        select_params=[user_id],\r
-        tables=['vote', 'answer', 'question', 'auth_user'],\r
-        where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = answer.id '+\r
-            'AND answer.question_id = question.id AND vote.user_id=auth_user.id'],\r
-        params=[answer_type_id, user_id],\r
-        order_by=['-vote.id']\r
-    ).values(\r
-            'title',\r
-            'question_id',\r
-            'answer_id',\r
-            'voted_at',\r
-            'vote',\r
-            )\r
-\r
-    if(len(answer_votes) > 0):\r
-        votes.extend(answer_votes)\r
-    votes.sort(lambda x,y: cmp(y['voted_at'], x['voted_at']))\r
-    return render_to_response(user_view.template_file,{\r
-        "tab_name" : user_view.id,\r
-        "tab_description" : user_view.tab_description,\r
-        "page_title" : user_view.page_title,\r
-        "view_user" : user,\r
-        "votes" : votes[:user_view.data_size]\r
-\r
-    }, context_instance=RequestContext(request))\r
-\r
-def user_reputation(request, user_id, user_view):\r
-    user = get_object_or_404(User, id=user_id)\r
+@user_view('users/recent.html', 'recent', _('recent user activity'), _('profile - recent activity'))\r
+def user_recent(request, user):\r
+    activities = Activity.objects.filter(activity_type__in=(TYPE_ACTIVITY_PRIZE,\r
+            TYPE_ACTIVITY_ASK_QUESTION, TYPE_ACTIVITY_ANSWER,\r
+            TYPE_ACTIVITY_COMMENT_QUESTION, TYPE_ACTIVITY_COMMENT_ANSWER,\r
+            TYPE_ACTIVITY_MARK_ANSWER), user=user).order_by('-active_at')[:USERS_PAGE_SIZE]\r
+\r
+    return {"view_user" : user, "activities" : activities}\r
 \r
+\r
+@user_view('users/votes.html', 'votes', _('user vote record'), _('profile - votes'))\r
+def user_votes(request, user):\r
+    votes = user.votes.exclude(node__deleted=True).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
+\r
+    return {"view_user" : user, "votes" : votes}\r
+\r
+\r
+@user_view('users/reputation.html', 'reputation', _('user reputation in the community'), _('profile - user reputation'))\r
+def user_reputation(request, user):\r
     reputation = user.reputes.order_by('-reputed_at')\r
 \r
     graph_data = simplejson.dumps([\r
@@ -665,68 +208,16 @@ def user_reputation(request, user_id, user_view):
             for rep in reputation\r
     ])\r
 \r
-    return render_to_response(user_view.template_file, {\r
-                              "tab_name": user_view.id,\r
-                              "tab_description": user_view.tab_description,\r
-                              "page_title": user_view.page_title,\r
-                              "view_user": user,\r
-                              "reputation": reputation,\r
-                              "graph_data": graph_data\r
-                              }, context_instance=RequestContext(request))\r
-\r
-def user_favorites(request, user_id, user_view):\r
-    user = get_object_or_404(User, id=user_id)\r
-    questions = Question.objects.extra(\r
-        select={\r
-            'vote_count' : 'question.vote_up_count + question.vote_down_count',\r
-            'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s '+\r
-                'AND f.question_id = question.id',\r
-            'la_user_id' : 'auth_user.id',\r
-            'la_username' : 'auth_user.username',\r
-            'la_user_gold' : 'forum_user.gold',\r
-            'la_user_silver' : 'forum_user.silver',\r
-            'la_user_bronze' : 'forum_user.bronze',\r
-            'la_user_reputation' : 'forum_user.reputation'\r
-            },\r
-        select_params=[user_id],\r
-        tables=['question', 'auth_user', 'favorite_question', 'forum_user'],\r
-        where=['NOT question.deleted AND question.last_activity_by_id = auth_user.id '+\r
-            'AND favorite_question.question_id = question.id AND favorite_question.user_id = %s AND forum_user.user_ptr_id = auth_user.id'],\r
-        params=[user_id],\r
-        order_by=['-vote_count', '-question.id']\r
-    ).values('vote_count',\r
-             'favorited_myself',\r
-             'id',\r
-             'title',\r
-             'author_id',\r
-             'added_at',\r
-             'answer_accepted',\r
-             'answer_count',\r
-             'comment_count',\r
-             'view_count',\r
-             'favourite_count',\r
-             'summary',\r
-             'tagnames',\r
-             'vote_up_count',\r
-             'vote_down_count',\r
-             'last_activity_at',\r
-             'la_user_id',\r
-             'la_username',\r
-             'la_user_gold',\r
-             'la_user_silver',\r
-             'la_user_bronze',\r
-             'la_user_reputation')\r
-    return render_to_response(user_view.template_file,{\r
-        "tab_name" : user_view.id,\r
-        "tab_description" : user_view.tab_description,\r
-        "page_title" : user_view.page_title,\r
-        "questions" : questions[:user_view.data_size],\r
-        "view_user" : user\r
-    }, context_instance=RequestContext(request))\r
-\r
-def user_subscription_settings(request, user_id, user_view):\r
-    user = get_object_or_404(User, id=user_id)\r
+    return {"view_user": user, "reputation": reputation, "graph_data": graph_data}\r
+\r
+@user_view('users/questions.html', 'favorites', _('favorite questions'),  _('profile - favorite questions'))\r
+def user_favorites(request, user):\r
+    questions = user.favorite_questions.filter(deleted=False)\r
 \r
+    return {"questions" : questions, "view_user" : user}\r
+\r
+@user_view('users/subscriptions.html', 'subscriptions', _('subscription settings'), _('profile - subscriptions'))\r
+def user_subscriptions(request, user):\r
     if request.method == 'POST':\r
         form = SubscriptionSettingsForm(request.POST)\r
 \r
@@ -750,108 +241,10 @@ def user_subscription_settings(request, user_id, user_view):
 \r
     notificatons_on = user.subscription_settings.enable_notifications\r
 \r
-    return render_to_response(user_view.template_file,{\r
-        'tab_name':user_view.id,\r
-        'tab_description':user_view.tab_description,\r
-        'page_title':user_view.page_title,\r
-        'view_user':user,\r
-        'notificatons_on': notificatons_on,\r
-        'form':form,\r
-    }, context_instance=RequestContext(request))\r
-\r
-class UserView:\r
-    def __init__(self, id, tab_title, tab_description, page_title, view_func, template_file, data_size=0):\r
-        self.id = id\r
-        self.tab_title = tab_title\r
-        self.tab_description = tab_description\r
-        self.page_title = page_title\r
-        self.view_func = view_func \r
-        self.template_file = template_file\r
-        self.data_size = data_size\r
-        \r
-USER_TEMPLATE_VIEWS = (\r
-    UserView(\r
-        id = 'stats',\r
-        tab_title = _('overview'),\r
-        tab_description = _('user profile'),\r
-        page_title = _('user profile overview'),\r
-        view_func = user_stats,\r
-        template_file = 'user_stats.html'\r
-    ),\r
-    UserView(\r
-        id = 'recent',\r
-        tab_title = _('recent activity'),\r
-        tab_description = _('recent user activity'),\r
-        page_title = _('profile - recent activity'),\r
-        view_func = user_recent,\r
-        template_file = 'user_recent.html',\r
-        data_size = 50\r
-    ),\r
-    UserView(\r
-        id = 'responses',\r
-        tab_title = _('responses'),\r
-        tab_description = _('comments and answers to others questions'),\r
-        page_title = _('profile - responses'),\r
-        view_func = user_responses,\r
-        template_file = 'user_responses.html',\r
-        data_size = 50\r
-    ),\r
-    UserView(\r
-        id = 'reputation',\r
-        tab_title = _('reputation'),\r
-        tab_description = _('user reputation in the community'),\r
-        page_title = _('profile - user reputation'),\r
-        view_func = user_reputation,\r
-        template_file = 'user_reputation.html'\r
-    ),\r
-    UserView(\r
-        id = 'favorites',\r
-        tab_title = _('favorite questions'),\r
-        tab_description = _('users favorite questions'),\r
-        page_title = _('profile - favorite questions'),\r
-        view_func = user_favorites,\r
-        template_file = 'user_favorites.html',\r
-        data_size = 50\r
-    ),\r
-    UserView(\r
-        id = 'votes',\r
-        tab_title = _('casted votes'),\r
-        tab_description = _('user vote record'),\r
-        page_title = _('profile - votes'),\r
-        view_func = user_votes,\r
-        template_file = 'user_votes.html',\r
-        data_size = 50\r
-    ),\r
-    UserView(\r
-        id = 'subscriptions',\r
-        tab_title = _('subscriptions'),\r
-        tab_description = _('subscription settings'),\r
-        page_title = _('profile - subscriptions'),\r
-        view_func = user_subscription_settings,\r
-        template_file = 'user_subscriptions.html'\r
-    )\r
-)\r
-\r
-def user(request, id, slug=None):\r
-    sort = request.GET.get('sort', 'stats')\r
-    user_view = dict((v.id, v) for v in USER_TEMPLATE_VIEWS).get(sort, USER_TEMPLATE_VIEWS[0])\r
-    from forum.views import users\r
-    func = user_view.view_func\r
-    return func(request, id, user_view)\r
+    return {'view_user':user, 'notificatons_on': notificatons_on, 'form':form}\r
 \r
 @login_required\r
 def account_settings(request):\r
-    """\r
-    index pages to changes some basic account settings :\r
-     - change password\r
-     - change email\r
-     - associate a new openid\r
-     - delete account\r
-\r
-    url : /\r
-\r
-    template : authopenid/settings.html\r
-    """\r
     logging.debug('')\r
     msg = request.GET.get('msg', '')\r
     is_openid = False\r
index f65c4f4dc21c0d77c6080c7dc471e6691a46a21f..70be5eee420ae33f8a78aa034516a15da3e60516 100644 (file)
@@ -13,8 +13,6 @@ from django.utils.translation import ugettext as _
 from django.core.urlresolvers import reverse
 from django.core.exceptions import PermissionDenied
 
-from forum.utils.html import sanitize_html
-from markdown2 import Markdown
 from forum.forms import *
 from forum.models import *
 from forum.const import *
@@ -32,8 +30,6 @@ QUESTIONS_PAGE_SIZE = 10
 # used in answers
 ANSWERS_PAGE_SIZE = 10
 
-markdowner = Markdown(html4tags=True)
-
 def upload(request):#ajax upload file to a question or answer
     class FileTypeNotAllow(Exception):
         pass
@@ -80,47 +76,36 @@ def upload(request):#ajax upload file to a question or answer
     return HttpResponse(result, mimetype="application/xml")
 
 
+def _create_post(request, post_cls, form, parent=None):
+    post = post_cls()
+
+    if parent is not None:
+        post.parent = parent
+
+    revision_data = dict(summary=_('Initial revision'), body=form.cleaned_data['text'])
+
+    if form.cleaned_data.get('title', None):
+        revision_data['title'] = strip_tags(form.cleaned_data['title'].strip())
+
+    if form.cleaned_data.get('tags', None):
+        revision_data['tagnames'] = form.cleaned_data['tags'].strip()
+
+    post.create_revision(request.user, **revision_data)
+
+    if form.cleaned_data['wiki']:
+        post.wikify()
+
+    return HttpResponseRedirect(post.get_absolute_url())
+
+
+
 def ask(request):
     if request.method == "POST" and "text" in request.POST:
         form = AskForm(request.POST)
         if form.is_valid():
-
-            added_at = datetime.datetime.now()
-            title = strip_tags(form.cleaned_data['title'].strip())
-            wiki = form.cleaned_data['wiki']
-            tagnames = form.cleaned_data['tags'].strip()
-            text = form.cleaned_data['text']
-            html = sanitize_html(markdowner.convert(text))
-            summary = strip_tags(html)[:120]
-            
             if request.user.is_authenticated():
-                author = request.user 
-
-                question = Question.objects.create_new(
-                    title            = title,
-                    author           = author, 
-                    added_at         = added_at,
-                    wiki             = wiki,
-                    tagnames         = tagnames,
-                    summary          = summary,
-                    text = sanitize_html(markdowner.convert(text))
-                )
-
-                return HttpResponseRedirect(question.get_absolute_url())
+                return _create_post(request, Question, form)
             else:
-                request.session.flush()
-                session_key = request.session.session_key
-                question = AnonymousQuestion(
-                    session_key = session_key,
-                    title       = title,
-                    tagnames = tagnames,
-                    wiki = wiki,
-                    text = text,
-                    summary = summary,
-                    added_at = added_at,
-                    ip_addr = request.META['REMOTE_ADDR'],
-                )
-                question.save()
                 return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newquestion'}))
     elif request.method == "POST" and "go" in request.POST:
         form = AskForm({'title': request.POST['q']})
@@ -135,9 +120,7 @@ def ask(request):
         }, context_instance=RequestContext(request))
 
 @login_required
-def edit_question(request, id):#edit or retag a question
-    """view to edit question
-    """
+def edit_question(request, id):
     question = get_object_or_404(Question, id=id)
     if question.deleted and not request.user.can_view_deleted_post(question):
         raise Http404
@@ -148,33 +131,19 @@ def edit_question(request, id):#edit or retag a question
     else:
         raise Http404
 
-def _retag_question(request, question):#non-url subview of edit question - just retag
-    """retag question sub-view used by
-    view "edit_question"
-    """
+def _retag_question(request, question):
     if request.method == 'POST':
         form = RetagQuestionForm(question, request.POST)
         if form.is_valid():
             if form.has_changed():
-                latest_revision = question.get_latest_revision()
-                retagged_at = datetime.datetime.now()
-
-                question.tagnames = form.cleaned_data['tags']
-                question.last_edited_at = retagged_at
-                question.last_edited_by = request.user
-                question.last_activity_at = retagged_at
-                question.last_activity_by = request.user
-                question.save()
-
-                # Create a new revision
-                QuestionRevision.objects.create(
-                    question   = question,
-                    title      = latest_revision.title,
-                    author     = request.user,
-                    revised_at = retagged_at,
-                    tagnames   = form.cleaned_data['tags'],
-                    summary    = CONST['retagged'],
-                    text       = latest_revision.text
+                active = question.active_revision
+
+                question.create_revision(
+                    request.user,
+                    summary          = _('Retag'),
+                    title            = active.title,
+                    tagnames         = form.cleaned_data['tags'],
+                    body             = active.body,
                 )
 
             return HttpResponseRedirect(question.get_absolute_url())
@@ -186,70 +155,39 @@ def _retag_question(request, question):#non-url subview of edit question - just
         'tags' : _get_tags_cache_json(),
     }, context_instance=RequestContext(request))
 
-def _edit_question(request, question):#non-url subview of edit_question - just edit the body/title
-    latest_revision = question.get_latest_revision()
-    revision_form = None
+def _edit_question(request, question):
     if request.method == 'POST':
+        revision_form = RevisionForm(question, data=request.POST)
+        revision_form.is_valid()
+        revision = question.revisions.get(revision=revision_form.cleaned_data['revision'])
+
         if 'select_revision' in request.POST:
-            # user has changed revistion number
-            revision_form = RevisionForm(question, latest_revision, request.POST)
-            if revision_form.is_valid():
-                # Replace with those from the selected revision
-                form = EditQuestionForm(question,
-                    QuestionRevision.objects.get(question=question,
-                        revision=revision_form.cleaned_data['revision']))
-            else:
-                form = EditQuestionForm(question, latest_revision, request.POST)
+            form = EditQuestionForm(question, revision)
         else:
-            # Always check modifications against the latest revision
-            form = EditQuestionForm(question, latest_revision, request.POST)
-            if form.is_valid():
-                html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
-                if form.has_changed():
-                    edited_at = datetime.datetime.now()
-                    tags_changed = (latest_revision.tagnames !=
-                                    form.cleaned_data['tags'])
-
-                    # Update the Question itself
-                    question.title = form.cleaned_data['title']
-                    question.last_edited_at = edited_at
-                    question.last_edited_by = request.user
-                    question.last_activity_at = edited_at
-                    question.last_activity_by = request.user
-                    question.tagnames = form.cleaned_data['tags']
-                    question.summary = strip_tags(html)[:120]
-                    question.html = html
-
-                    # only save when it's checked
-                    # because wiki doesn't allow to be edited if last version has been enabled already
-                    # and we make sure this in forms.
-                    if ('wiki' in form.cleaned_data and
-                        form.cleaned_data['wiki']):
-                        question.wiki = True
-                        question.wikified_at = edited_at
-
-                    question.save()
-
-                    # Create a new revision
-                    revision = QuestionRevision(
-                        question   = question,
-                        title      = form.cleaned_data['title'],
-                        author     = request.user,
-                        revised_at = edited_at,
-                        tagnames   = form.cleaned_data['tags'],
-                        text       = form.cleaned_data['text'],
-                    )
-                    if form.cleaned_data['summary']:
-                        revision.summary = form.cleaned_data['summary']
-                    else:
-                        revision.summary = 'No.%s Revision' % latest_revision.revision
-                    revision.save()
-
-                return HttpResponseRedirect(question.get_absolute_url())
+            form = EditQuestionForm(question, revision, data=request.POST)
+
+        if not 'select_revision' in request.POST and form.is_valid():
+            if form.has_changed():
+                question.create_revision(
+                    request.user,
+                    summary          = form.cleaned_data['summary'],
+                    title            = strip_tags(form.cleaned_data['title'].strip()),
+                    tagnames         = form.cleaned_data['tags'].strip(),
+                    body             = form.cleaned_data['text'],
+                )
+
+                if form.cleaned_data.get('wiki', False):
+                    question.wikify()
+
+            else:
+                if not revision == question.active_revision:
+                    question.activate_revision(request.user, revision)
+
+            return HttpResponseRedirect(question.get_absolute_url())
     else:
+        revision_form = RevisionForm(question)
+        form = EditQuestionForm(question)
 
-        revision_form = RevisionForm(question, latest_revision)
-        form = EditQuestionForm(question, latest_revision)
     return render_to_response('question_edit.html', {
         'question': question,
         'revision_form': revision_form,
@@ -264,91 +202,52 @@ def edit_answer(request, id):
         raise Http404
     elif not request.user.can_edit_post(answer):
         raise Http404
-    else:
-        latest_revision = answer.get_latest_revision()
-        if request.method == "POST":
-            if 'select_revision' in request.POST:
-                # user has changed revistion number
-                revision_form = RevisionForm(answer, latest_revision, request.POST)
-                if revision_form.is_valid():
-                    # Replace with those from the selected revision
-                    form = EditAnswerForm(answer,
-                                          AnswerRevision.objects.get(answer=answer,
-                                          revision=revision_form.cleaned_data['revision']))
-                else:
-                    form = EditAnswerForm(answer, latest_revision, request.POST)
-            else:
-                form = EditAnswerForm(answer, latest_revision, request.POST)
-                if form.is_valid():
-                    html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
-                    if form.has_changed():
-                        edited_at = datetime.datetime.now()
-                        updated_fields = {
-                            'last_edited_at': edited_at,
-                            'last_edited_by': request.user,
-                            'html': html,
-                        }
-                        Answer.objects.filter(id=answer.id).update(**updated_fields)
-
-                        revision = AnswerRevision(
-                                                  answer=answer,
-                                                  author=request.user,
-                                                  revised_at=edited_at,
-                                                  text=form.cleaned_data['text']
-                                                  )
-
-                        if form.cleaned_data['summary']:
-                            revision.summary = form.cleaned_data['summary']
-                        else:
-                            revision.summary = 'No.%s Revision' % latest_revision.revision
-                        revision.save()
-
-                        answer.question.last_activity_at = edited_at
-                        answer.question.last_activity_by = request.user
-                        answer.question.save()
-
-                    return HttpResponseRedirect(answer.get_absolute_url())
+
+    if request.method == "POST":
+        revision_form = RevisionForm(answer, data=request.POST)
+        revision_form.is_valid()
+        revision = answer.revisions.get(revision=revision_form.cleaned_data['revision'])
+
+        if 'select_revision' in request.POST:
+            form = EditAnswerForm(answer, revision)
         else:
-            revision_form = RevisionForm(answer, latest_revision)
-            form = EditAnswerForm(answer, latest_revision)
-        return render_to_response('answer_edit.html', {
-                                  'answer': answer,
-                                  'revision_form': revision_form,
-                                  'form': form,
-                                  }, context_instance=RequestContext(request))
-
-def answer(request, id):#process a new answer
+            form = EditAnswerForm(answer, revision, data=request.POST)
+
+        if not 'select_revision' in request.POST and form.is_valid():
+            if form.has_changed():
+                answer.create_revision(
+                    request.user,
+                    summary          = form.cleaned_data['summary'],
+                    body             = form.cleaned_data['text'],
+                )
+
+                if form.cleaned_data.get('wiki', False):
+                    answer.wikify()
+
+            else:
+                if not revision == answer.active_revision:
+                    answer.activate_revision(request.user, revision)
+
+            return HttpResponseRedirect(answer.get_absolute_url())
+
+    else:
+        revision_form = RevisionForm(answer)
+        form = EditAnswerForm(answer)
+    return render_to_response('answer_edit.html', {
+                              'answer': answer,
+                              'revision_form': revision_form,
+                              'form': form,
+                              }, context_instance=RequestContext(request))
+
+def answer(request, id):
     question = get_object_or_404(Question, id=id)
     if request.method == "POST":
-        form = AnswerForm(question, request.user, request.POST)
+        form = AnswerForm(question, request.POST)
         if form.is_valid():
-            wiki = form.cleaned_data['wiki']
-            text = form.cleaned_data['text']
-            update_time = datetime.datetime.now()
-
             if request.user.is_authenticated():
-                Answer.objects.create_new(
-                                  question=question,
-                                  author=request.user,
-                                  added_at=update_time,
-                                  wiki=wiki,
-                                  text=sanitize_html(markdowner.convert(text)),
-                                  email_notify=form.cleaned_data['email_notify']
-                                  )
+                return _create_post(request, Answer, form, question)
             else:
-                request.session.flush()
-                html = sanitize_html(markdowner.convert(text))
-                summary = strip_tags(html)[:120]
-                anon = AnonymousAnswer(
-                                       question=question,
-                                       wiki=wiki,
-                                       text=text,
-                                       summary=summary,
-                                       session_key=request.session.session_key,
-                                       ip_addr=request.META['REMOTE_ADDR'],
-                                       )
-                anon.save()
-                return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newanswer'}))
+                return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newquestion'}))
 
     return HttpResponseRedirect(question.get_absolute_url())
 
index 246c3177ff526e5c46cca30311a548155c77229f..1f88d7b5f1576166658bbff586815c455e0fd3ea 100644 (file)
@@ -67,7 +67,7 @@ INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.humanize',
     'django.contrib.sitemaps',
-    #'django.contrib.markup',
+    'django.contrib.markup',
     'forum',
 ]