]> git.openstreetmap.org Git - osqa.git/commitdiff
Added a direct option to mark a post as community wiki, still needs some sort of...
authorhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Tue, 25 May 2010 01:45:49 +0000 (01:45 +0000)
committerhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Tue, 25 May 2010 01:45:49 +0000 (01:45 +0000)
Improved handling of a node state, requires migrations.
Improved handling of tags.
Some more ui improvements.

git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@320 0cfe37f9-358a-4d5e-be75-b63607b5c754

30 files changed:
forum/actions/meta.py
forum/actions/node.py
forum/feed.py
forum/forms.py
forum/migrations/0036_auto__add_nodestate__chg_field_award_action__add_field_node_state_stri.py [new file with mode: 0644]
forum/migrations/0037_fill_node_state.py [new file with mode: 0644]
forum/migrations/0038_auto__del_field_node_wiki__del_field_node_deleted__del_field_node_extr.py [new file with mode: 0644]
forum/migrations/0039_auto__del_field_tag_deleted__del_field_tag_deleted_by__del_field_tag_d.py [new file with mode: 0644]
forum/models/__init__.py
forum/models/action.py
forum/models/answer.py
forum/models/base.py
forum/models/node.py
forum/models/question.py
forum/models/tag.py
forum/models/user.py
forum/sitemap.py
forum/skins/default/media/js/osqa.main.js
forum/skins/default/templates/node/accept_button.html
forum/skins/default/templates/node/post_controls.html
forum/skins/default/templates/node/report.html
forum/skins/default/templates/question.html
forum/skins/default/templates/users/stats.html
forum/templatetags/node_tags.py
forum/views/admin.py
forum/views/commands.py
forum/views/readers.py
forum/views/users.py
forum/views/writers.py
forum_modules/default_badges/badges.py

index 7c951101f8954885e1ed811b3561b65d47142d87..adf51ca933c63fdf26d2b4a89aa8d4acb4f7c883 100644 (file)
@@ -102,7 +102,7 @@ class FlagAction(ActionProxy):
 \r
         if self.node.flag_count == int(settings.FLAG_COUNT_TO_DELETE_POST):\r
             self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED_5_TIMES))\r
-            if not self.node.deleted:\r
+            if not self.node.nis.deleted:\r
                 DeleteAction(node=self.node, user=self.user, extra="BYFLAGGED").save()\r
 \r
     def cancel_action(self):\r
@@ -136,14 +136,14 @@ class AcceptAnswerAction(ActionProxy):
         self.node.parent.extra_ref = self.node\r
         self.node.parent.save()\r
         self.node.marked = True\r
-        self.node.extra_action = self\r
+        self.node.nstate.accepted = self\r
         self.node.save()\r
 \r
     def cancel_action(self):\r
         self.node.parent.extra_ref = None\r
         self.node.parent.save()\r
         self.node.marked = False\r
-        self.node.extra_action = None\r
+        self.node.nstate.accepted = None\r
         self.node.save()\r
 \r
     def describe(self, viewer=None):\r
index 5283a8e98587feff199b64a2eed8c343e775dcf1..f5aad160ec6535f835478a26ed4d7704cd637f54 100644 (file)
@@ -134,13 +134,13 @@ class CloseAction(ActionProxy):
     verb = _("closed")\r
 \r
     def process_action(self):\r
-        self.node.extra_action = self\r
         self.node.marked = True\r
+        self.node.nstate.closed = self\r
         self.node.update_last_activity(self.user, save=True)\r
 \r
     def cancel_action(self):\r
-        self.node.extra_action = None\r
         self.node.marked = False\r
+        self.node.nstate.closed = None\r
         self.node.update_last_activity(self.user, save=True)\r
 \r
     def describe(self, viewer=None):\r
@@ -161,7 +161,8 @@ class AnswerToCommentAction(ActionProxy):
             comment.parent = new_parent\r
             comment.save()\r
 \r
-        self.node.save()\r
+        self.node.last_edited = self\r
+        self.node.update_last_activity(self.user, save=True)\r
         try:\r
             self.node.abs_parent.reset_answer_count_cache()\r
         except AttributeError:\r
@@ -173,3 +174,21 @@ class AnswerToCommentAction(ActionProxy):
             'question': self.describe_node(viewer, self.node.abs_parent),\r
         }\r
 \r
+class WikifyAction(ActionProxy):\r
+    verb = _("wikified")\r
+\r
+    def process_action(self):\r
+        self.node.nstate.wiky = self\r
+        self.node.last_edited = self\r
+        self.node.update_last_activity(self.user, save=True)\r
+\r
+    def cancel_action(self):\r
+        self.node.nstate.wiky = None\r
+        self.node.update_last_activity(self.user, save=True)\r
+\r
+    def describe(self, viewer=None):\r
+        return _("%(user)s marked %(node)s as community wiky.") % {\r
+            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+            'node': self.describe_node(viewer, self.node),\r
+        }\r
+\r
index 0f8deaec3cfba590bb02d26a4130727498035c91..e74e80e4fdafef45e27181d1935e3f75e281c13d 100644 (file)
@@ -34,7 +34,7 @@ class RssLastestQuestionsFeed(Feed):
         return item.added_at
 
     def items(self, item):
-       return Question.objects.filter(deleted=None).order_by('-last_activity_at')[:30]
+       return Question.objects.filter_state(deleted=False).order_by('-last_activity_at')[:30]
 
 def main():
     pass
index 49bd5ffa1c7140b106f237260ce14862b335a2cc..34fa271a1282d94e3f9ce9faba086b273afc4106 100644 (file)
@@ -141,7 +141,7 @@ class AnswerForm(forms.Form):
     def __init__(self, question, *args, **kwargs):
         super(AnswerForm, self).__init__(*args, **kwargs)
 
-        if question.wiki and settings.WIKI_ON:
+        if question.nis.wiki and settings.WIKI_ON:
             self.fields['wiki'].initial = True
 
 
@@ -187,7 +187,7 @@ class EditQuestionForm(forms.Form):
         self.fields['tags'].initial = revision.tagnames
             
         # Once wiki mode is enabled, it can't be disabled
-        if not question.wiki:
+        if settings.WIKI_ON and not question.nis.wiki:
             self.fields['wiki'] = WikiField()
 
 class EditAnswerForm(forms.Form):
diff --git a/forum/migrations/0036_auto__add_nodestate__chg_field_award_action__add_field_node_state_stri.py b/forum/migrations/0036_auto__add_nodestate__chg_field_award_action__add_field_node_state_stri.py
new file mode 100644 (file)
index 0000000..ac16256
--- /dev/null
@@ -0,0 +1,298 @@
+# 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 'NodeState'\r
+        db.create_table('forum_nodestate', (\r
+            ('node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='state', to=orm['forum.Node'])),\r
+            ('state_type', self.gf('django.db.models.fields.CharField')(max_length=16)),\r
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+            ('action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='node_state', unique=True, to=orm['forum.Action'])),\r
+        ))\r
+        db.send_create_signal('forum', ['NodeState'])\r
+\r
+        # Changing field 'Award.action'\r
+        db.alter_column('forum_award', 'action_id', self.gf('django.db.models.fields.related.OneToOneField')(unique=True, to=orm['forum.Action']))\r
+\r
+        # Adding field 'Node.state_string'\r
+        db.add_column('forum_node', 'state_string', self.gf('django.db.models.fields.TextField')(default=''), keep_default=False)\r
+\r
+        # Changing field 'Flag.action'\r
+        db.alter_column('forum_flag', 'action_id', self.gf('django.db.models.fields.related.OneToOneField')(unique=True, to=orm['forum.Action']))\r
+\r
+        # Changing field 'Vote.action'\r
+        db.alter_column('forum_vote', 'action_id', self.gf('django.db.models.fields.related.OneToOneField')(unique=True, to=orm['forum.Action']))\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        \r
+        # Deleting model 'NodeState'\r
+        db.delete_table('forum_nodestate')\r
+\r
+        # Changing field 'Award.action'\r
+        db.alter_column('forum_award', 'action_id', self.gf('django.db.models.fields.related.ForeignKey')(unique=True, to=orm['forum.Action']))\r
+\r
+        # Deleting field 'Node.state_string'\r
+        db.delete_column('forum_node', 'state_string')\r
+\r
+        # Changing field 'Flag.action'\r
+        db.alter_column('forum_flag', 'action_id', self.gf('django.db.models.fields.related.ForeignKey')(unique=True, to=orm['forum.Action']))\r
+\r
+        # Changing field 'Vote.action'\r
+        db.alter_column('forum_vote', 'action_id', self.gf('django.db.models.fields.related.ForeignKey')(unique=True, to=orm['forum.Action']))\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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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.action': {\r
+            'Meta': {'object_name': 'Action'},\r
+            'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+            'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.actionrepute': {\r
+            'Meta': {'object_name': 'ActionRepute'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+            'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\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': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'award'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.Badge']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+            'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'object_name': 'Badge'},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['forum.Award']", 'to': "orm['forum.User']"}),\r
+            'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.flag': {\r
+            'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),\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': "'flags'", 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flags'", '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', [], {'null': 'True'})\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
+            'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.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
+            'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\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
+            'state_string': ('django.db.models.fields.TextField', [], {'default': "''"}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'symmetrical': 'False', 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\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.nodestate': {\r
+            'Meta': {'unique_together': "(('node', 'state_type'),)", 'object_name': 'NodeState'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'node_state'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'state'", 'to': "orm['forum.Node']"}),\r
+            'state_type': ('django.db.models.fields.CharField', [], {'max_length': '16'})\r
+        },\r
+        'forum.openidassociation': {\r
+            'Meta': {'object_name': 'OpenIdAssociation'},\r
+            'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+            'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+            'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+            'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+            'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+        },\r
+        'forum.openidnonce': {\r
+            'Meta': {'object_name': 'OpenIdNonce'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+            'timestamp': ('django.db.models.fields.IntegerField', [], {})\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, 5, 24, 12, 24, 54, 587000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\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'},\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'", 'symmetrical': 'False', 'through': "orm['forum.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.PositiveIntegerField', [], {'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
+            'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\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
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'symmetrical': 'False', 'through': "orm['forum.QuestionSubscription']", 'to': "orm['forum.Node']"}),\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, 5, 25, 12, 24, 54, 760000)'}),\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': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'value': ('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/0037_fill_node_state.py b/forum/migrations/0037_fill_node_state.py
new file mode 100644 (file)
index 0000000..79ed9c9
--- /dev/null
@@ -0,0 +1,317 @@
+# 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
+        n_count = orm.Node.objects.count()\r
+        print "\nConverting %s node states:" % n_count\r
+        progress = ProgressBar(n_count)\r
+\r
+        for n in orm.Node.objects.all():\r
+            ss = ""\r
+\r
+            if n.deleted:\r
+                s = orm.NodeState(\r
+                    node = n,\r
+                    action = n.deleted,\r
+                    state_type = "deleted"\r
+                )\r
+                s.save()\r
+                ss += "(deleted)"\r
+\r
+            if n.wiki:\r
+                try:\r
+                    action = orm.Action.objects.get(node=n, action_type="wikify")\r
+                    s = orm.NodeState(\r
+                        node = n,\r
+                        action = action,\r
+                        state_type = "wiki"\r
+                    )\r
+                    s.save()\r
+                    ss += "(wiki)"\r
+                except:\r
+                    pass\r
+\r
+            if n.node_type == "question" and n.extra_action:\r
+                s = orm.NodeState(\r
+                    node = n,\r
+                    action = n.extra_action,\r
+                    state_type = "closed"\r
+                )\r
+                s.save()\r
+                ss += "(closed)"\r
+\r
+            if n.node_type == "answer" and n.extra_action:\r
+                s = orm.NodeState(\r
+                    node = n,\r
+                    action = n.extra_action,\r
+                    state_type = "accepted"\r
+                )\r
+                s.save()\r
+                ss += "(accepted)"\r
+\r
+            if ss:\r
+                n.state_string = ss\r
+                n.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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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.action': {\r
+            'Meta': {'object_name': 'Action'},\r
+            'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+            'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.actionrepute': {\r
+            'Meta': {'object_name': 'ActionRepute'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+            'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\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': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'award'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.Badge']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+            'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'object_name': 'Badge'},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['forum.Award']", 'to': "orm['forum.User']"}),\r
+            'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.flag': {\r
+            'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),\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': "'flags'", 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flags'", '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', [], {'null': 'True'})\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
+            'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.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
+            'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\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
+            'state_string': ('django.db.models.fields.TextField', [], {'default': "''"}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'symmetrical': 'False', 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\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.nodestate': {\r
+            'Meta': {'unique_together': "(('node', 'state_type'),)", 'object_name': 'NodeState'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'node_state'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'state'", 'to': "orm['forum.Node']"}),\r
+            'state_type': ('django.db.models.fields.CharField', [], {'max_length': '16'})\r
+        },\r
+        'forum.openidassociation': {\r
+            'Meta': {'object_name': 'OpenIdAssociation'},\r
+            'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+            'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+            'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+            'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+            'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+        },\r
+        'forum.openidnonce': {\r
+            'Meta': {'object_name': 'OpenIdNonce'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+            'timestamp': ('django.db.models.fields.IntegerField', [], {})\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, 5, 24, 12, 26, 33, 742000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\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'},\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'", 'symmetrical': 'False', 'through': "orm['forum.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.PositiveIntegerField', [], {'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
+            'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\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
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'symmetrical': 'False', 'through': "orm['forum.QuestionSubscription']", 'to': "orm['forum.Node']"}),\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, 5, 25, 12, 26, 33, 797000)'}),\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': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'value': ('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/0038_auto__del_field_node_wiki__del_field_node_deleted__del_field_node_extr.py b/forum/migrations/0038_auto__del_field_node_wiki__del_field_node_deleted__del_field_node_extr.py
new file mode 100644 (file)
index 0000000..c38e21f
--- /dev/null
@@ -0,0 +1,282 @@
+# 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 field 'Node.wiki'\r
+        db.delete_column('forum_node', 'wiki')\r
+\r
+        # Deleting field 'Node.deleted'\r
+        db.delete_column('forum_node', 'deleted_id')\r
+\r
+        # Deleting field 'Node.extra_action'\r
+        db.delete_column('forum_node', 'extra_action_id')\r
+\r
+        # Deleting field 'Node.in_moderation'\r
+        db.delete_column('forum_node', 'in_moderation_id')\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        \r
+        # Adding field 'Node.wiki'\r
+        db.add_column('forum_node', 'wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+        # Adding field 'Node.deleted'\r
+        db.add_column('forum_node', 'deleted', self.gf('django.db.models.fields.related.ForeignKey')(related_name='deleted_node', unique=True, null=True, to=orm['forum.Action']), keep_default=False)\r
+\r
+        # Adding field 'Node.extra_action'\r
+        db.add_column('forum_node', 'extra_action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='extra_node', null=True, to=orm['forum.Action']), keep_default=False)\r
+\r
+        # Adding field 'Node.in_moderation'\r
+        db.add_column('forum_node', 'in_moderation', self.gf('django.db.models.fields.related.ForeignKey')(related_name='moderated_node', unique=True, null=True, to=orm['forum.Action']), 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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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.action': {\r
+            'Meta': {'object_name': 'Action'},\r
+            'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+            'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.actionrepute': {\r
+            'Meta': {'object_name': 'ActionRepute'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+            'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\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': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'award'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.Badge']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+            'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'object_name': 'Badge'},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['forum.Award']", 'to': "orm['forum.User']"}),\r
+            'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.flag': {\r
+            'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),\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': "'flags'", 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flags'", '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', [], {'null': 'True'})\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
+            'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.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
+            'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\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
+            'state_string': ('django.db.models.fields.TextField', [], {'default': "''"}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'symmetrical': 'False', 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\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.nodestate': {\r
+            'Meta': {'unique_together': "(('node', 'state_type'),)", 'object_name': 'NodeState'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'node_state'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['forum.Node']"}),\r
+            'state_type': ('django.db.models.fields.CharField', [], {'max_length': '16'})\r
+        },\r
+        'forum.openidassociation': {\r
+            'Meta': {'object_name': 'OpenIdAssociation'},\r
+            'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+            'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+            'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+            'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+            'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+        },\r
+        'forum.openidnonce': {\r
+            'Meta': {'object_name': 'OpenIdNonce'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+            'timestamp': ('django.db.models.fields.IntegerField', [], {})\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, 5, 24, 19, 29, 24, 232000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\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'},\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'", 'symmetrical': 'False', 'through': "orm['forum.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.PositiveIntegerField', [], {'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
+            'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\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
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'symmetrical': 'False', 'through': "orm['forum.QuestionSubscription']", 'to': "orm['forum.Node']"}),\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, 5, 25, 19, 29, 24, 443000)'}),\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': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'value': ('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/0039_auto__del_field_tag_deleted__del_field_tag_deleted_by__del_field_tag_d.py b/forum/migrations/0039_auto__del_field_tag_deleted__del_field_tag_deleted_by__del_field_tag_d.py
new file mode 100644 (file)
index 0000000..4a91aa7
--- /dev/null
@@ -0,0 +1,273 @@
+# 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 field 'Tag.deleted'\r
+        db.delete_column('forum_tag', 'deleted')\r
+\r
+        # Deleting field 'Tag.deleted_by'\r
+        db.delete_column('forum_tag', 'deleted_by_id')\r
+\r
+        # Deleting field 'Tag.deleted_at'\r
+        db.delete_column('forum_tag', 'deleted_at')\r
+    \r
+    \r
+    def backwards(self, orm):\r
+        \r
+        # Adding field 'Tag.deleted'\r
+        db.add_column('forum_tag', 'deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+        # Adding field 'Tag.deleted_by'\r
+        db.add_column('forum_tag', 'deleted_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='deleted_tags', null=True, to=orm['forum.User'], blank=True), keep_default=False)\r
+\r
+        # Adding field 'Tag.deleted_at'\r
+        db.add_column('forum_tag', 'deleted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), 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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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']", 'symmetrical': 'False', '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.action': {\r
+            'Meta': {'object_name': 'Action'},\r
+            'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+            'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+        },\r
+        'forum.actionrepute': {\r
+            'Meta': {'object_name': 'ActionRepute'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+            'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+            'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\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': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'award'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.Badge']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+            'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+        },\r
+        'forum.badge': {\r
+            'Meta': {'object_name': 'Badge'},\r
+            'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['forum.Award']", 'to': "orm['forum.User']"}),\r
+            'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+        },\r
+        'forum.flag': {\r
+            'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),\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': "'flags'", 'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flags'", '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', [], {'null': 'True'})\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
+            'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.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
+            'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+            'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+            'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+            'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\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
+            'state_string': ('django.db.models.fields.TextField', [], {'default': "''"}),\r
+            'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+            'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'symmetrical': 'False', 'to': "orm['forum.Tag']"}),\r
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\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.nodestate': {\r
+            'Meta': {'unique_together': "(('node', 'state_type'),)", 'object_name': 'NodeState'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'node_state'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'states'", 'to': "orm['forum.Node']"}),\r
+            'state_type': ('django.db.models.fields.CharField', [], {'max_length': '16'})\r
+        },\r
+        'forum.openidassociation': {\r
+            'Meta': {'object_name': 'OpenIdAssociation'},\r
+            'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+            'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+            'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+            'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+            'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+        },\r
+        'forum.openidnonce': {\r
+            'Meta': {'object_name': 'OpenIdNonce'},\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+            'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+            'timestamp': ('django.db.models.fields.IntegerField', [], {})\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, 5, 25, 0, 18, 31, 631000)'}),\r
+            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\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'},\r
+            'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", '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'", 'symmetrical': 'False', 'through': "orm['forum.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.PositiveIntegerField', [], {'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
+            'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\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
+            'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+            'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'symmetrical': 'False', 'through': "orm['forum.QuestionSubscription']", 'to': "orm['forum.Node']"}),\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, 5, 26, 0, 18, 31, 914000)'}),\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': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},\r
+            'action': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+            'value': ('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 2c9c9970aad196a48b42019935d197ec8e91ca4e..dbf237cafc7e241d7c29cfa2c0de811ef11fc7f6 100644 (file)
@@ -2,7 +2,7 @@ from question import Question ,QuestionRevision, QuestionSubscription
 from answer import Answer, AnswerRevision\r
 from tag import Tag, MarkedTag\r
 from user import User, ValidationHash, AuthKeyUserAssociation, SubscriptionSettings\r
-from node import Node, NodeRevision, NodeMetaClass\r
+from node import Node, NodeRevision, NodeState, NodeMetaClass\r
 from comment import Comment\r
 from action import Action, ActionRepute\r
 from meta import Vote, Flag, Badge, Award\r
@@ -17,7 +17,7 @@ except:
 from base import *\r
 \r
 __all__ = [\r
-        'Node', 'NodeRevision',  \r
+        'Node', 'NodeRevision', 'NodeState',  \r
         'Question', 'QuestionSubscription', 'QuestionRevision',\r
         'Answer', 'AnswerRevision',\r
         'Tag', 'Comment', 'MarkedTag', 'Badge', 'Award',\r
index d892ac92658099b1a3f50a4ee63482076a7cff54..7f9a7c189acf73817d9f64d72969b919ace2e072 100644 (file)
@@ -123,7 +123,7 @@ class Action(BaseModel):
         super(Action, self).save(*args, **kwargs)\r
 \r
         if isnew:\r
-            if (self.node is None) or (not self.node.wiki):\r
+            if (self.node is None) or (not self.node.nis.wiki):\r
                 self.repute_users()\r
             self.process_action()\r
             self.trigger_hooks(True)\r
index 090e19d004a5d8db4ebeabb82f1f7deaafbdf8e0..564605e7d227d42a830ecdb376d2e760dd30f6c0 100644 (file)
@@ -7,9 +7,9 @@ class Answer(Node):
     class Meta(Node.Meta):
         proxy = True
 
-    @property    
-    def accepted(self):
-        return self.extra_action
+    #@property
+    #def accepted(self):
+    #    return self.nstate.accepted
 
     @property
     def headline(self):
index dfdf989fa305fa2fc41b30b277b44e2977ab6ff5..63c73e848408c24a1e81fbd13981fbdb4b18f4d1 100644 (file)
@@ -81,9 +81,9 @@ class CachedManager(models.Manager):
 
 
 class DenormalizedField(object):
-    def __init__(self, manager, **kwargs):
+    def __init__(self, manager, *args, **kwargs):
         self.manager = manager
-        self.filter = kwargs
+        self.filter = (args, kwargs)
 
     def setup_class(self, cls, name):
         dict_name = '_%s_dencache_' % name
@@ -92,7 +92,7 @@ class DenormalizedField(object):
             val = inst.__dict__.get(dict_name, None)
 
             if val is None:
-                val = getattr(inst, self.manager).filter(**self.filter).count()
+                val = getattr(inst, self.manager).filter(*self.filter[0], **self.filter[1]).count()
                 inst.__dict__[dict_name] = val
                 inst.cache()
 
@@ -135,14 +135,17 @@ class BaseModel(models.Model):
 
     def __init__(self, *args, **kwargs):
         super(BaseModel, self).__init__(*args, **kwargs)
-        self.reset_original_state()
+        self.reset_original_state(kwargs.keys())
 
     @classmethod
     def cache_key(cls, pk):
         return '%s:%s:%s' % (settings.APP_URL, cls.__name__, pk)
 
-    def reset_original_state(self):
+    def reset_original_state(self, reset_fields=None):
         self._original_state = self._as_dict()
+        
+        if reset_fields:
+            self._original_state.update(dict([(f, None) for f in reset_fields]))
 
     def get_dirty_fields(self):
         return [f.name for f in self._meta.fields if self._original_state[f.attname] != self.__dict__[f.attname]]
index 4be2a00557c21fca3a83c0b3217c90a9f9b7dc29..dc3ecb93ff9b61130a1980ee4d947828e2c2a7cf 100644 (file)
@@ -1,4 +1,5 @@
 from base import *\r
+import re\r
 from tag import Tag\r
 \r
 import markdown\r
@@ -91,6 +92,10 @@ class NodeQuerySet(CachedQuerySet):
     def get(self, *args, **kwargs):\r
         return super(NodeQuerySet, self).get(*args, **kwargs).leaf\r
 \r
+    def filter_state(self, **kwargs):\r
+        apply_bool = lambda q, b: b and q or ~q\r
+        return self.filter(*[apply_bool(models.Q(state_string__contains="(%s)" % s), b) for s, b in kwargs.items()])\r
+\r
 \r
 class NodeManager(CachedManager):\r
     use_for_related_fields = True\r
@@ -107,6 +112,60 @@ class NodeManager(CachedManager):
         kwargs['node_type__in'] = [t.get_type() for t in types]\r
         return self.get(*args, **kwargs)\r
 \r
+    def filter_state(self, **kwargs):\r
+        return self.all().filter_state(**kwargs)\r
+\r
+\r
+class NodeStateDict(object):\r
+    def __init__(self, node):\r
+        self.__dict__['_node'] = node\r
+\r
+    def __getattr__(self, name):\r
+        if self.__dict__.get(name, None):\r
+            return self.__dict__[name]\r
+\r
+        try:\r
+            node = self.__dict__['_node']\r
+            action = NodeState.objects.get(node=node, state_type=name).action\r
+            self.__dict__[name] = action\r
+            return action\r
+        except:\r
+            return None\r
+\r
+    def __setattr__(self, name, value):\r
+        current = self.__getattr__(name)\r
+\r
+        if value:\r
+            if current:\r
+                current.action = value\r
+                current.save()\r
+            else:\r
+                node = self.__dict__['_node']\r
+                state = NodeState(node=node, action=value, state_type=name)\r
+                state.save()\r
+                self.__dict__[name] = value\r
+\r
+                if not "(%s)" % name in node.state_string:\r
+                    node.state_string = "%s(%s)" % (node.state_string, name)\r
+                    node.save()\r
+        else:\r
+            if current:\r
+                node = self.__dict__['_node']\r
+                node.state_string = "".join("(%s)" % s for s in re.findall('\w+', node.state_string) if s != name)\r
+                node.save()\r
+                current.node_state.delete()\r
+                del self.__dict__[name]\r
+\r
+\r
+class NodeStateQuery(object):\r
+    def __init__(self, node):\r
+        self.__dict__['_node'] = node\r
+\r
+    def __getattr__(self, name):\r
+        node = self.__dict__['_node']\r
+        return "(%s)" % name in node.state_string\r
+\r
+\r
 \r
 class Node(BaseModel, NodeContent):\r
     __metaclass__ = NodeMetaClass\r
@@ -118,8 +177,10 @@ class Node(BaseModel, NodeContent):
     added_at             = models.DateTimeField(default=datetime.datetime.now)\r
     score                 = models.IntegerField(default=0)\r
 \r
-    deleted               = models.ForeignKey('Action', null=True, unique=True, related_name="deleted_node")\r
-    in_moderation         = models.ForeignKey('Action', null=True, unique=True, related_name="moderated_node")\r
+    state_string          = models.TextField(default='')\r
+\r
+    #deleted               = models.ForeignKey('Action', null=True, unique=True, related_name="deleted_node")\r
+    #in_moderation         = models.ForeignKey('Action', null=True, unique=True, related_name="moderated_node")\r
     last_edited           = models.ForeignKey('Action', null=True, unique=True, related_name="edited_node")\r
 \r
     last_activity_by       = models.ForeignKey(User, null=True)\r
@@ -130,10 +191,10 @@ class Node(BaseModel, NodeContent):
 \r
     extra_ref = models.ForeignKey('Node', null=True)\r
     extra_count = models.IntegerField(default=0)\r
-    extra_action = models.ForeignKey('Action', null=True, related_name="extra_node")\r
+    #extra_action = models.ForeignKey('Action', null=True, related_name="extra_node")\r
     \r
     marked = models.BooleanField(default=False)\r
-    wiki = models.BooleanField(default=False)\r
+    #wiki = models.BooleanField(default=False)\r
 \r
     comment_count = DenormalizedField("children", node_type="comment", canceled=False)\r
     flag_count = DenormalizedField("flags")\r
@@ -161,6 +222,30 @@ class Node(BaseModel, NodeContent):
         leaf.__dict__ = self.__dict__\r
         return leaf\r
 \r
+    @property\r
+    def nstate(self):\r
+        state = self.__dict__.get('_nstate', None)\r
+\r
+        if state is None:\r
+            state = NodeStateDict(self)\r
+            self._nstate = state\r
+\r
+        return state\r
+\r
+    @property\r
+    def nis(self):\r
+        nis = self.__dict__.get('_nis', None)\r
+\r
+        if nis is None:\r
+            nis = NodeStateQuery(self)\r
+            self._nis = nis\r
+\r
+        return nis\r
+\r
+    #@property\r
+    #def deleted(self):\r
+    #    return self.nstate.deleted\r
+\r
     @property    \r
     def absolute_parent(self):\r
         if not self.abs_parent_id:\r
@@ -238,18 +323,16 @@ class Node(BaseModel, NodeContent):
                 except:\r
                     tag = Tag.objects.create(name=name, created_by=self._last_active_user())\r
 \r
-                if not self.deleted:\r
+                if not self.nis.deleted:\r
                     tag.used_count = models.F('used_count') + 1\r
                     tag.save()\r
 \r
-            if not self.deleted:\r
+            if not self.nis.deleted:\r
                 for name in tag_changes['removed']:\r
                     try:\r
                         tag = Tag.objects.get(name=name)\r
                         tag.used_count = models.F('used_count') - 1\r
                         tag.save()\r
-                        if tag.used_count == 0:\r
-                            tag.mark_deleted(self._last_active_user())\r
                     except:\r
                         pass\r
 \r
@@ -258,15 +341,13 @@ class Node(BaseModel, NodeContent):
         return False\r
 \r
     def mark_deleted(self, action):\r
-        self.deleted = action\r
+        self.nstate.deleted = action\r
         self.save()\r
 \r
         if action:\r
             for tag in self.tags.all():\r
                 tag.used_count = models.F('used_count') - 1\r
                 tag.save()\r
-                if tag.used_count == 0:\r
-                    tag.mark_deleted(self._last_active_user())\r
         else:\r
             for tag in Tag.objects.filter(name__in=self.tagname_list()):\r
                 tag.used_count = models.F('used_count') + 1\r
@@ -302,3 +383,13 @@ class NodeRevision(BaseModel, NodeContent):
         app_label = 'forum'\r
 \r
 \r
+class NodeState(models.Model):\r
+    node       = models.ForeignKey(Node, related_name='states')\r
+    state_type = models.CharField(max_length=16)\r
+    action     = models.OneToOneField('Action', related_name="node_state")\r
+\r
+    class Meta:\r
+        unique_together = ('node', 'state_type')\r
+        app_label = 'forum'\r
+\r
+\r
index 9e8dcf643cd986c3ebc7b1b2550346aff2868b59..a7ecd221d549f055d9ab790325014db67daa8209 100644 (file)
@@ -14,15 +14,15 @@ class Question(Node):
     class Meta(Node.Meta):
         proxy = True
 
-    answer_count = DenormalizedField("children", node_type="answer", deleted=None)
+    answer_count = DenormalizedField("children", ~models.Q(state_string__contains="(deleted)"), node_type="answer")
     favorite_count = DenormalizedField("actions", action_type="favorite", canceled=False)
 
     friendly_name = _("question")
     objects = QuestionManager()
 
-    @property   
-    def closed(self):
-        return self.extra_action
+    #@property
+    #def closed(self):
+    #    return self.nstate.closed
 
     @property    
     def view_count(self):
@@ -30,12 +30,12 @@ class Question(Node):
 
     @property
     def headline(self):
-        if self.marked:
-            return _('[closed] ') + self.title
-
-        if self.deleted:
+        if self.nis.deleted:
             return _('[deleted] ') + self.title
 
+        if self.nis.closed:
+            return _('[closed] ') + self.title
+
         return self.title
 
     @property
@@ -58,8 +58,8 @@ class Question(Node):
         related_list = cache.get(cache_key)
 
         if related_list is None:
-            related_list = Question.objects.values('id').filter(tags__id__in=[t.id for t in self.tags.all()]
-            ).exclude(id=self.id).filter(deleted=None).annotate(frequency=models.Count('id')).order_by('-frequency')[:count]
+            related_list = Question.objects.filter_state(deleted=False).values('id').filter(tags__id__in=[t.id for t in self.tags.all()]
+            ).exclude(id=self.id).annotate(frequency=models.Count('id')).order_by('-frequency')[:count]
             cache.set(cache_key, related_list, 60 * 60)
 
         return [Question.objects.get(id=r['id']) for r in related_list]
index 13445977ded256e0dc004d22e2a15fae787a23c8..898c3e178d75d3b7d37664bccba046872ef776b5 100644 (file)
@@ -5,7 +5,7 @@ import django.dispatch
 
 class ActiveTagManager(models.Manager):
     def get_query_set(self):
-        return super(ActiveTagManager, self).get_query_set().exclude(deleted=False, used_count=0)
+        return super(ActiveTagManager, self).get_query_set().exclude(used_count__lt=1)
 
 
 class Tag(BaseModel):
@@ -15,29 +15,8 @@ class Tag(BaseModel):
     # Denormalised data
     used_count = models.PositiveIntegerField(default=0)
 
-    deleted     = models.BooleanField(default=False)
-    deleted_at  = models.DateTimeField(null=True, blank=True)
-    deleted_by  = models.ForeignKey(User, null=True, blank=True, related_name='deleted_%(class)ss')
-
     active = ActiveTagManager()
 
-    def mark_deleted(self, user):
-        if not self.deleted:
-            self.deleted = True
-            self.deleted_at = datetime.datetime.now()
-            self.deleted_by = user
-            self.save()
-            return True
-        else:
-            return False
-
-    def unmark_deleted(self):
-        if self.deleted:
-            self.deleted = False
-            self.save()
-            return True
-        else:
-            return False
 
     class Meta:
         ordering = ('-used_count', 'name')
index c196bd44b74f7d5a0c39670f33f53fd12cfadaad..cddfe35c3388fb9134ec65330b697583a4c60263 100644 (file)
@@ -26,7 +26,7 @@ class UserManager(CachedManager):
 \r
 class AnonymousUser(DjangoAnonymousUser):\r
     def get_visible_answers(self, question):\r
-        return question.answers.filter(deleted=None)\r
+        return question.answers.filter_state(deleted=False)\r
 \r
     def can_view_deleted_post(self, post):\r
         return False\r
@@ -147,7 +147,7 @@ class User(BaseModel, DjangoUser):
         return mark_safe(profile_link)\r
 \r
     def get_visible_answers(self, question):\r
-        return question.answers.filter(deleted=None, in_moderation=None)\r
+        return question.answers.filter_state(deleted=False)\r
 \r
     def get_vote_count_today(self):\r
         today = datetime.date.today()\r
index 39dcdc1aa15e5e335ffa73bb59eae8ead364a769..3606cab1147dffeac8eb51378a94fba1cc0c967c 100644 (file)
@@ -5,7 +5,7 @@ class QuestionsSitemap(Sitemap):
     changefreq = 'daily'
     priority = 0.5
     def items(self):
-        return Question.objects.filter(deleted=None)
+        return Question.objects.filter_state(deleted=False)
 
     def lastmod(self, obj):
         return obj.last_activity_at
index af80421ec51fc91b4ac3aad1afe08a4744e4ec2e..c78367bf3333c3d42ba750a0a86472c84be2d3ca 100644 (file)
@@ -294,6 +294,24 @@ $(function() {
 \r
         if (el.is('.withprompt')) {\r
             load_prompt(evt, el.attr('href'));\r
+        } else if(el.is('.confirm')) {\r
+            $dialog = show_dialog({\r
+                html: messages.confirm,\r
+                extra_class: 'confirm',\r
+                event: evt,\r
+                yes_callback: function() {\r
+                    start_command();\r
+                    $.getJSON(el.attr('href'), function(data) {\r
+                        process_ajax_response(data, evt);\r
+                        $dialog.fadeOut('fast', function() {\r
+                            $dialog.remove();\r
+                        });\r
+                    });\r
+                },\r
+                yes_text: messages.yes,\r
+                show_no: true,\r
+                no_text: messages.no\r
+            });\r
         } else {\r
             start_command();\r
             $.getJSON(el.attr('href'), function(data) {\r
index beff321f325504f1a7e01b12206fad7dab2c6a27..21214913f46e7a122571d6d773b23332ea374cd9 100644 (file)
@@ -1,7 +1,7 @@
 {% load i18n %}\r
 \r
 {% if can_accept %}\r
-    <a id="accept-answer-{{ answer.id }}" class="ajax-command accept-answer{% if answer.accepted %} on{% endif %}"\r
-        title="{% if answer.accepted %}{% blocktrans with answer.accepted_by.username as who %}{{ who }} has selected this answer as the correct answer{% endblocktrans %}{% else %}{% trans "mark this answer as the accepted answer" %}{% endif %}"\r
+    <a id="accept-answer-{{ answer.id }}" class="ajax-command accept-answer{% if answer.nis.accepted %} on{% endif %}"\r
+        title="{% if answer.nis.accepted %}{% blocktrans with answer.accepted_by.username as who %}{{ who }} has selected this answer as the correct answer{% endblocktrans %}{% else %}{% trans "mark this answer as the accepted answer" %}{% endif %}"\r
          href="{% url accept_answer id=answer.id %}" rel="nofollow"> </a>\r
 {% endif %}
\ No newline at end of file
index 9311e4b254221bedb3889efe6abe8c8fb75d8f25..c8808a9c63e2c7a6d28a57c6eb32e115547f80ad 100644 (file)
@@ -2,8 +2,7 @@
 {% spaceless %}\r
 {% for control in controls %}\r
     <span class="action-link">\r
-        <a title="{{ control.title }}" class="{% if control.command %}ajax-command{% endif %}{% if control.withprompt %} withprompt{% endif %}"\r
-            href="{{ control.url }}">{{ control.text }}</a>\r
+        <a title="{{ control.title }}" class="{{ control.classes }}" href="{{ control.url }}">{{ control.text }}</a>\r
     </span>\r
     {% ifnotequal controls|last control %}\r
         <span class="action-link-separator">|</span>\r
@@ -14,8 +13,7 @@
         <span id="node-{{ node.id }}-menu-trigger" class="context-menu-trigger">{% trans "more" %} &#9660;</span>\r
         <ul id="node-{{ node.id }}-menu-dropdown" class="context-menu-dropdown">\r
             {% for item in menu %}\r
-            <li class="item"><a class="{% if item.command %}ajax-command{% endif %}{% if item.withprompt %} withprompt{% endif %}"\r
-                href="{{ item.url }}" title="{{ item.title }}" >{{ item.text }}</a></li>\r
+            <li class="item"><a class="{{ item.classes }}" href="{{ item.url }}" title="{{ item.title }}" >{{ item.text }}</a></li>\r
             {% endfor %}\r
         </ul>\r
     </span>\r
index 68b66d9ff2e600ec4dafc923f00d41596b15ce5f..1635d7d6726f4dedbea54610a06c714685ed74e7 100644 (file)
@@ -8,7 +8,7 @@
 </select>\r
 <textarea name="prompt">{{ types|first }}</textarea>\r
 <script>\r
-$('.user-prompt .prompt-examples').change(function() {\r
-    $('.user-prompt textarea').val($(this).val())            \r
+$('.prompt-examples').change(function() {\r
+    $('textarea[name=prompt]').val($(this).val())            \r
 })\r
 </script>
\ No newline at end of file
index 466df6a4907242f0c6ccf04f83bf3b5125794f30..7fb9d9de3bc8a41cf48254ab015617f4cf248e93 100644 (file)
@@ -63,7 +63,7 @@
 </div>\r
 <div id="main-body" class="">\r
     <div id="askform">\r
-            <table style="width:100%;" id="question-table" {% if question.deleted %}class="deleted"{%endif%}>\r
+            <table style="width:100%;" id="question-table" {% if question.nis.deleted %}class="deleted"{%endif%}>\r
                 <tr>\r
                     <td style="width:30px;vertical-align:top">\r
                         <div class="vote-buttons">\r
                     </td>\r
                 </tr>\r
             </table>\r
-            {% if question.marked %}\r
+            {% if question.nis.closed %}\r
             <div class="question-status" style="margin-bottom:15px">\r
             <h3>\r
-                {% blocktrans with question.closed.extra as close_reason %}\r
+                {% blocktrans with question.nstate.closed.extra as close_reason %}\r
                     The question has been closed for the following reason "{{ close_reason }}" by\r
                 {% endblocktrans %}\r
-                <a href="{{ question.closed.by.get_profile_url }}">{{ question.closed.by.username }}</a>\r
-                 {% diff_date question.closed.at %}\r
+                <a href="{{ question.nstate.closed.by.get_profile_url }}">{{ question.nstate.closed.by.username }}</a>\r
+                 {% diff_date question.nstate.closed.at %}\r
             </h3>\r
             </div>\r
             {% endif %}\r
   \r
                 {% for answer in answers %}\r
                     <a name="{{ answer.id }}"></a>\r
-                    <div id="answer-container-{{ answer.id }}" class="answer {% if answer.accepted %}accepted-answer{% endif %} {% ifequal answer.author_id question.author_id %} answered-by-owner{% endifequal %} {% if answer.deleted %}deleted{% endif %}">\r
+                    <div id="answer-container-{{ answer.id }}" class="answer {% if answer.nis.accepted %}accepted-answer{% endif %} {% ifequal answer.author_id question.author_id %} answered-by-owner{% endifequal %} {% if answer.nis.deleted %}deleted{% endif %}">\r
                         <table style="width:100%;">\r
                             <tr>\r
                                 <td style="width:30px;vertical-align:top">\r
index adc6e12652151fb8728ed11d905308b0c830edf1..9f12493c8a9b680d7896999f9f48c0beeb77b886 100644 (file)
@@ -38,8 +38,8 @@
             <div class="answer-summary">
                 <a title="{{answer.question.title}}"
                     href="{{ answer.get_absolute_url }}">
-                    <span class="{% if answer.accepted %}answered-accepted {% endif %} answer-votes" 
-                                               title="{% blocktrans with answer.score as vote_count %}the answer has been voted for {{ vote_count }} times{% endblocktrans %} {% if answer.accepted %}{% trans "this answer has been selected as correct" %}{%endif%}">
+                    <span class="{% if answer.nis.accepted %}answered-accepted {% endif %} answer-votes" 
+                                               title="{% blocktrans with answer.score as vote_count %}the answer has been voted for {{ vote_count }} times{% endblocktrans %} {% if answer.nis.accepted %}{% trans "this answer has been selected as correct" %}{%endif%}">
                         {{ answer.score }}
                     </span>
                 </a>
index 454819437223e61bbe26b5c49ed3aaa3f625e265..7ade554eafacbcd92280907bc4d57ddd8b1b71f1 100644 (file)
@@ -36,8 +36,9 @@ def favorite_mark(question, user):
 \r
     return {'favorited': favorited, 'favorite_count': question.favorite_count, 'question': question}\r
 \r
-def post_control(text, url, command=False, withprompt=False, title=""):\r
-    return {'text': text, 'url': url, 'command': command, 'withprompt': withprompt ,'title': title}\r
+def post_control(text, url, command=False, withprompt=False, confirm=False, title=""):\r
+    classes = (command and "ajax-command" or " ") + (withprompt and " withprompt" or " ") + (confirm and " confirm" or " ")\r
+    return {'text': text, 'url': url, 'classes': classes, 'title': title}\r
 \r
 @register.inclusion_tag('node/post_controls.html')\r
 def post_controls(post, user):\r
@@ -57,9 +58,9 @@ def post_controls(post, user):
             controls.append(post_control(_('retag'), edit_url))\r
 \r
         if post_type == 'question':\r
-            if post.closed and user.can_reopen_question(post):\r
+            if post.nis.closed and user.can_reopen_question(post):\r
                 controls.append(post_control(_('reopen'), reverse('reopen', kwargs={'id': post.id}), command=True))\r
-            elif not post.closed and user.can_close_question(post):\r
+            elif not post.nis.closed and user.can_close_question(post):\r
                 controls.append(post_control(_('close'), reverse('close', kwargs={'id': post.id}), command=True, withprompt=True))\r
 \r
         if user.can_flag_offensive(post):\r
@@ -72,16 +73,16 @@ def post_controls(post, user):
                     command=True, withprompt=True, title=_("report as offensive (i.e containing spam, advertising, malicious text, etc.)")))\r
 \r
         if user.can_delete_post(post):\r
-            if post.deleted:\r
+            if post.nis.deleted:\r
                 controls.append(post_control(_('undelete'), reverse('delete_post', kwargs={'id': post.id}),\r
-                        command=True))\r
+                        command=True, confirm=True))\r
             else:\r
                 controls.append(post_control(_('delete'), reverse('delete_post', kwargs={'id': post.id}),\r
-                        command=True))\r
+                        command=True, confirm=True))\r
 \r
-        if user.can_wikify(post):\r
+        if (not post.nis.wiki) and user.can_wikify(post):\r
             menu.append(post_control(_('mark as community wiki'), reverse('wikify', kwargs={'id': post.id}),\r
-                        command=True))\r
+                        command=True, confirm=True))\r
 \r
         if post.node_type == "answer" and user.can_convert_to_comment(post):\r
             menu.append(post_control(_('convert to comment'), reverse('convert_to_comment', kwargs={'id': post.id}),\r
@@ -91,7 +92,7 @@ def post_controls(post, user):
 \r
 @register.inclusion_tag('node/comments.html')\r
 def comments(post, user):\r
-    all_comments = post.comments.filter(deleted=None).order_by('added_at')\r
+    all_comments = post.comments.filter_state(deleted=False).order_by('added_at')\r
 \r
     if len(all_comments) <= 5:\r
         top_scorers = all_comments\r
index bfe8919721cc38db2c04b71753bc526e5a8cac34..54cb5ff3afbc74ad017ca4470278512ce79d433b 100644 (file)
@@ -63,10 +63,10 @@ def statistics(request):
     today = datetime.now()
     last_month = today - timedelta(days=30)
 
-    last_month_questions = Question.objects.filter(deleted=None, added_at__gt=last_month
+    last_month_questions = Question.objects.filter_state(deleted=False).filter(added_at__gt=last_month
                                                   ).order_by('added_at').values_list('added_at', flat=True)
 
-    last_month_n_questions = Question.objects.filter(deleted=None, added_at__lt=last_month).count()
+    last_month_n_questions = Question.objects.filter_state(deleted=False).filter(added_at__lt=last_month).count()
     qgraph_data = simplejson.dumps([
             (time.mktime(d.timetuple()) * 1000, i + last_month_n_questions)
             for i, d in enumerate(last_month_questions)
@@ -149,10 +149,10 @@ def get_statistics():
     return {
         'total_users': User.objects.all().count(),
         'users_last_24': User.objects.filter(date_joined__gt=(datetime.now() - timedelta(days=1))).count(),
-        'total_questions': Question.objects.filter(deleted=None).count(),
-        'questions_last_24': Question.objects.filter(deleted=None, added_at__gt=(datetime.now() - timedelta(days=1))).count(),
-        'total_answers': Answer.objects.filter(deleted=None).count(),
-        'answers_last_24': Answer.objects.filter(deleted=None, added_at__gt=(datetime.now() - timedelta(days=1))).count(),
+        'total_questions': Question.objects.filter_state(deleted=False).count(),
+        'questions_last_24': Question.objects.filter_state(deleted=False).filter(added_at__gt=(datetime.now() - timedelta(days=1))).count(),
+        'total_answers': Answer.objects.filter_state(deleted=False).count(),
+        'answers_last_24': Answer.objects.filter_state(deleted=False).filter(added_at__gt=(datetime.now() - timedelta(days=1))).count(),
     }
 
 @super_user_required
index 1b3afc5ef3a3f8e0c014c34fe146697a9763e175..461240344dfd4bb387aa06821a4e6c9101d4273b 100644 (file)
@@ -179,7 +179,7 @@ def delete_comment(request, id):
     if not user.can_delete_comment(comment):
         raise NotEnoughRepPointsException( _('delete comments'))
 
-    if not comment.deleted:
+    if not comment.nis.deleted:
         DeleteAction(node=comment, user=user, ip=request.META['REMOTE_ADDR']).save()
 
     return {
@@ -288,13 +288,13 @@ def accept_answer(request, id):
 
     commands = {}
 
-    if answer.accepted:
-        answer.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
+    if answer.nis.accepted:
+        answer.nstate.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
         commands['unmark_accepted'] = [answer.id]
     else:
         if question.answer_accepted:
             accepted = question.accepted_answer
-            accepted.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
+            accepted.nstate.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
             commands['unmark_accepted'] = [accepted.id]
 
         AcceptAnswerAction(node=answer, user=user, ip=request.META['REMOTE_ADDR']).save()
@@ -315,8 +315,8 @@ def delete_post(request, id):
 
     ret = {'commands': {}}
 
-    if post.deleted:
-        post.deleted.cancel(user, ip=request.META['REMOTE_ADDR'])
+    if post.nis.deleted:
+        post.nstate.deleted.cancel(user, ip=request.META['REMOTE_ADDR'])
         ret['commands']['unmark_deleted'] = [post.node_type, id]
     else:
         DeleteAction(node=post, user=user, ip=request.META['REMOTE_ADDR']).save()
@@ -336,11 +336,11 @@ def close(request, id, close):
     if not user.is_authenticated():
         raise AnonymousNotAllowedException(_('close questions'))
 
-    if question.extra_action:
+    if question.nis.closed:
         if not user.can_reopen_question(question):
             raise NotEnoughRepPointsException(_('reopen questions'))
 
-        question.extra_action.cancel(user, ip=request.META['REMOTE_ADDR'])
+        question.nstate.closed.cancel(user, ip=request.META['REMOTE_ADDR'])
     else:
         if not request.user.can_close_question(question):
             raise NotEnoughRepPointsException(_('close questions'))
@@ -360,7 +360,26 @@ def close(request, id, close):
 
 @command
 def wikify(request, id):
-    pass
+    node = get_object_or_404(Node, id=id)
+
+    if node.nis.wiky:
+        raise CommandException(_("This post is already marked as community wiky."))
+
+    user = request.user
+
+    if not user.is_authenticated():
+        raise AnonymousNotAllowedException(_('mark posts as community wiki'))
+
+    if not user.can_wikify(node):
+        raise NotEnoughRepPointsException(_('mark posts as community wiki'))
+
+    WikifyAction(node=node, user=user, ip=request.META['REMOTE_ADDR']).save()
+
+    return {
+        'commands': {
+            'refresh_page': []
+        }
+    }
 
 @command
 def convert_to_comment(request, id):
@@ -371,7 +390,7 @@ def convert_to_comment(request, id):
     if not request.POST:
         description = lambda a: _("Answer by %(uname)s: %(snippet)s...") % {'uname': a.author.username, 'snippet': a.summary[:10]}
         nodes = [(question.id, _("Question"))]
-        [nodes.append((a.id, description(a))) for a in question.answers.filter(deleted=None).exclude(id=answer.id)]
+        [nodes.append((a.id, description(a))) for a in question.answers.filter_state(deleted=False).exclude(id=answer.id)]
 
         return render_to_response('node/convert_to_comment.html', {'answer': answer, 'nodes': nodes})
 
index a48c35b19041b94e7ecf2932dc1fae3ddbae18c7..f756a9468f7c12042ec8d34c6104b5b177ec19d4 100644 (file)
@@ -73,7 +73,7 @@ def tag(request, tag):
 
 @decorators.list('questions', QUESTIONS_PAGE_SIZE)
 def question_list(request, initial, list_description=_('questions'), sort=None, base_path=None, page_title=None, allowIgnoreTags=True):
-    questions = initial.filter(deleted=None, in_moderation=None)
+    questions = initial.filter_state(deleted=False)
 
     if request.user.is_authenticated() and allowIgnoreTags:
         questions = questions.filter(~Q(tags__id__in = request.user.marked_tags.filter(user_selections__reason = 'bad')))
@@ -95,7 +95,7 @@ def question_list(request, initial, list_description=_('questions'), sort=None,
     if request.GET.get("q"):
         keywords = request.GET.get("q").strip()
 
-    answer_count = Answer.objects.filter(deleted=None, parent__in=questions).count()   
+    answer_count = Answer.objects.filter_state(deleted=False).filter(parent__in=questions).count()   
     answer_description = _("answers")
 
     return {
@@ -148,12 +148,12 @@ def tags(request):#view showing a listing of available tags - plain list
     if request.method == "GET":
         stag = request.GET.get("q", "").strip()
         if stag != '':
-            objects_list = Paginator(Tag.objects.filter(deleted=False).exclude(used_count=0).extra(where=['name like %s'], params=['%' + stag + '%']), DEFAULT_PAGE_SIZE)
+            objects_list = Paginator(Tag.active.filter(name__contains=stag), DEFAULT_PAGE_SIZE)
         else:
             if sortby == "name":
-                objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("name"), DEFAULT_PAGE_SIZE)
+                objects_list = Paginator(Tag.active.order_by("name"), DEFAULT_PAGE_SIZE)
             else:
-                objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("-used_count"), DEFAULT_PAGE_SIZE)
+                objects_list = Paginator(Tag.active.order_by("-used_count"), DEFAULT_PAGE_SIZE)
 
     try:
         tags = objects_list.page(page)
@@ -228,7 +228,7 @@ def question(request, id, slug):
     page = int(request.GET.get('page', 1))
     view_id, order_by = get_answer_sort_order(request)
 
-    if question.deleted and not request.user.can_view_deleted_post(question):
+    if question.nis.deleted and not request.user.can_view_deleted_post(question):
         raise Http404
 
     if request.POST:
@@ -240,7 +240,7 @@ def question(request, id, slug):
 
     if answers is not None:
         answers = [a for a in answers.order_by("-marked", order_by)
-                   if not a.deleted or a.author == request.user]
+                   if not a.nis.deleted or a.author == request.user]
 
     objects_list = Paginator(answers, ANSWERS_PAGE_SIZE)
     page_objects = objects_list.page(page)
index 67f0a90c257aa2557a3cf4f970dbc94f24c6fb55..7202d39e7fbd2f2a5b1e8f758048972dd6572b72 100644 (file)
@@ -174,8 +174,8 @@ def user_view(template, tab_name, tab_description, page_title, private=False):
 \r
 @user_view('users/stats.html', 'stats', _('user profile'), _('user overview'))\r
 def user_stats(request, user):\r
-    questions = Question.objects.filter(author=user, deleted=None).order_by('-added_at')\r
-    answers = Answer.objects.filter(author=user, deleted=None).order_by('-added_at')\r
+    questions = Question.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
+    answers = Answer.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
 \r
     up_votes = user.vote_up_count\r
     down_votes = user.vote_down_count\r
@@ -211,7 +211,7 @@ def user_recent(request, user):
 \r
 @user_view('users/votes.html', 'votes', _('user vote record'), _('votes'), True)\r
 def user_votes(request, user):\r
-    votes = user.votes.filter(node__deleted=None, node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
+    votes = user.votes.exclude(node__state_string__contains="(deleted").filter(node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
 \r
     return {"view_user" : user, "votes" : votes}\r
 \r
index cc2c807c0538b3672bc9ba00ba9a77e795bcccd1..5bddc6040b070c692cf8e21bdf98bf40e9d737a8 100644 (file)
@@ -91,7 +91,7 @@ def ask(request):
 @login_required
 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):
+    if question.nis.deleted and not request.user.can_view_deleted_post(question):
         raise Http404
     if request.user.can_edit_post(question):
         return _edit_question(request, question)
index 2305dd4ddc76f3e4f8974bbbce45897ebc6e3747..a04177632a78c7ba826e6002b74e9cb5e7b2b814 100644 (file)
@@ -254,7 +254,7 @@ class Student(AbstractBadge):
     description = _('Asked first question with at least one up vote')
 
     def award_to(self, action):
-        if (action.node.node_type == "question") and (action.node.author.nodes.filter(node_type="question", deleted=None, score=1).count() == 1):
+        if (action.node.node_type == "question") and (action.node.author.nodes.filter_state(deleted=False).filter(node_type="question", score=1).count() == 1):
             return action.node.author
 
 
@@ -265,7 +265,7 @@ class Teacher(AbstractBadge):
     description = _('Answered first question with at least one up vote')
 
     def award_to(self, action):
-        if (action.node.node_type == "answer") and (action.node.author.nodes.filter(node_type="answer", deleted=None, score=1).count() == 1):
+        if (action.node.node_type == "answer") and (action.node.author.nodes.filter_state(deleted=False).filter(node_type="answer", score=1).count() == 1):
             return action.node.author