]> git.openstreetmap.org Git - osqa.git/commitdiff
New "action prepared" version of the sx importer.
authorhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Wed, 12 May 2010 09:58:19 +0000 (09:58 +0000)
committerhernani <hernani@0cfe37f9-358a-4d5e-be75-b63607b5c754>
Wed, 12 May 2010 09:58:19 +0000 (09:58 +0000)
git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@231 0cfe37f9-358a-4d5e-be75-b63607b5c754

forum_modules/sximporter/importer.py
forum_modules/sximporter/orm.py

index a16b29c741ada6038cb0ce9aec5ef405b2225594..b5bb0a66329a82c593d01d81c3f9220a216c845c 100644 (file)
@@ -1,11 +1,12 @@
 # -*- coding: utf-8 -*-\r
 \r
 from xml.dom import minidom\r
-from datetime import datetime\r
+from datetime import datetime, timedelta\r
 import time\r
 import re\r
 from django.utils.translation import ugettext as _\r
 from django.template.defaultfilters import slugify\r
+from forum.models.utils import dbsafe_encode\r
 from orm import orm\r
 \r
 def getText(el):\r
@@ -29,11 +30,46 @@ def readEl(el):
 def readTable(dump, name):\r
     return [readEl(e) for e in minidom.parseString(dump.read("%s.xml" % name)).getElementsByTagName('row')]\r
 \r
+google_accounts_lookup = re.compile(r'^https?://www.google.com/accounts/')\r
+yahoo_accounts_lookup = re.compile(r'^https?://me.yahoo.com/a/')\r
+\r
+openid_lookups = [\r
+    re.compile(r'^https?://www.google.com/profiles/(?P<uname>\w+(\.\w+)*)/?$'),\r
+    re.compile(r'^https?://me.yahoo.com/(?P<uname>\w+(\.\w+)*)/?$'),\r
+    re.compile(r'^https?://openid.aol.com/(?P<uname>\w+(\.\w+)*)/?$'),\r
+    re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).myopenid.com/?$'),\r
+    re.compile(r'^https?://flickr.com/(\w+/)*(?P<uname>\w+(\.\w+)*)/?$'),\r
+    re.compile(r'^https?://technorati.com/people/technorati/(?P<uname>\w+(\.\w+)*)/?$'),\r
+    re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).wordpress.com/?$'),\r
+    re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).blogspot.com/?$'),\r
+    re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).livejournal.com/?$'),\r
+    re.compile(r'^https?://claimid.com/(?P<uname>\w+(\.\w+)*)/?$'),\r
+    re.compile(r'^https?://(?P<uname>\w+(\.\w+)*).pip.verisignlabs.com/?$'),\r
+    re.compile(r'^https?://getopenid.com/(?P<uname>\w+(\.\w+)*)/?$'),\r
+    re.compile(r'^https?://[\w\.]+/(\w+/)*(?P<uname>\w+(\.\w+)*)/?$'),\r
+    re.compile(r'^https?://(?P<uname>[\w\.]+)/?$'),\r
+]\r
+\r
+def final_username_attempt(sxu):\r
+    openid = sxu.get('openid', None)\r
+\r
+    if openid:\r
+        if google_accounts_lookup.search(openid):\r
+            return UnknownGoogleUser()\r
+        if yahoo_accounts_lookup.search(openid):\r
+            return UnknownYahooUser()\r
+\r
+        for lookup in openid_lookups:\r
+            if lookup.search(openid):\r
+                return lookup.search(openid).group('uname')\r
+\r
+    return UnknownUser()\r
+\r
 class UnknownUser(object):\r
     counter = 0\r
     def __init__(self):\r
-        UnknownUser.counter += 1\r
-        self.number = UnknownUser.counter\r
+        self.__class__.counter += 1\r
+        self.number = self.__class__.counter\r
 \r
     def __str__(self):\r
         return _("Unknown user %(number)d") % {'number': self.number}\r
@@ -44,6 +80,19 @@ class UnknownUser(object):
     def encode(self, *args):\r
         return self.__str__()\r
 \r
+class UnknownGoogleUser(UnknownUser):\r
+    counter = 0\r
+\r
+    def __str__(self):\r
+        return _("Unknown google user %(number)d") % {'number': self.number}\r
+\r
+class UnknownYahooUser(UnknownUser):\r
+    counter = 0\r
+\r
+    def __str__(self):\r
+        return _("Unknown yahoo user %(number)d") % {'number': self.number}\r
+\r
+\r
 class IdMapper(dict):\r
     def __getitem__(self, key):\r
         key = int(key)\r
@@ -77,7 +126,7 @@ def userimport(dump, options):
             uidmapper[-1] = 1\r
             create = False\r
         else:\r
-            username = sxu.get('displayname', sxu.get('displaynamecleaned', sxu.get('realname', UnknownUser())))\r
+            username = sxu.get('displayname', sxu.get('displaynamecleaned', sxu.get('realname', final_username_attempt(sxu))))\r
 \r
             if not isinstance(username, UnknownUser) and username in user_by_name:\r
                 #if options.get('mergesimilar', False) and sxu.get('email', 'INVALID') == user_by_name[username].email:\r
@@ -107,6 +156,7 @@ def userimport(dump, options):
                 is_staff     = sxu.get('usertypeid') == '4',\r
                 is_active    = True,\r
                 date_joined  = readTime(sxu.get('creationdate')),\r
+                last_seen    = readTime(sxu.get('lastaccessdate')),\r
                 about         = sxu.get('aboutme', ''),\r
                 date_of_birth = sxu.get('birthday', None) and readTime(sxu['birthday']) or None,\r
                 email_isvalid = int(sxu.get('usertypeid')) > 2,\r
@@ -120,6 +170,21 @@ def userimport(dump, options):
 \r
             osqau.save()\r
 \r
+            user_joins = orm.Action(\r
+                action_type = "userjoins",\r
+                action_date = osqau.date_joined,\r
+                user = osqau\r
+            )\r
+            user_joins.save()\r
+\r
+            rep = orm.ActionRepute(\r
+                value = 1,\r
+                user = osqau,\r
+                date = osqau.date_joined,\r
+                action = user_joins\r
+            )\r
+            rep.save()            \r
+\r
             try:\r
                 orm.SubscriptionSettings.objects.get(user=osqau)\r
             except:\r
@@ -189,32 +254,68 @@ def postimport(dump, uidmap, tagmap):
     posts = readTable(dump, "Posts")\r
 \r
     for sxpost in posts:\r
-        postclass = sxpost.get('posttypeid') == '1' and orm.Question or orm.Answer\r
+        nodetype = (sxpost.get('posttypeid') == '1') and "nodetype" or "answer"\r
 \r
-        post = postclass(\r
+        post = orm.Node(\r
+            node_type = nodetype,\r
             id = sxpost['id'],\r
             added_at = readTime(sxpost['creationdate']),\r
             body = sxpost['body'],\r
             score = sxpost.get('score', 0),\r
-            vote_up_count = 0,\r
-            vote_down_count = 0\r
+            author_id = sxpost.get('deletiondate', None) and 1 or uidmap[sxpost['owneruserid']]\r
         )\r
 \r
-        if sxpost.get('deletiondate', None):\r
-            post.deleted = True\r
-            post.deleted_at = readTime(sxpost['deletiondate'])\r
-            post.author_id = 1\r
-        else:\r
-            post.author_id = uidmap[sxpost['owneruserid']]\r
+        post.save()\r
+\r
+        create_action = orm.Action(\r
+            action_type = (nodetype == "nodetype") and "ask" or "answer",\r
+            user_id = post.author_id,\r
+            node = post,\r
+            action_date = post.added_at\r
+        )\r
+\r
+        create_action.save()\r
+\r
+        #if sxpost.get('deletiondate', None):\r
+        #    delete_action = orm.Action(\r
+        #        action_type = "delete",\r
+        #        user_id = 1,\r
+        #        node = post,\r
+        #        action_date = readTime(sxpost['deletiondate'])\r
+        #    )\r
+\r
+        #    delete_action.save()\r
+        #    post.deleted = delete_action\r
 \r
         if sxpost.get('lasteditoruserid', None):\r
-            post.last_edited_by_id = uidmap[sxpost.get('lasteditoruserid')]\r
-            post.last_edited_at = readTime(sxpost['lasteditdate'])\r
+            revise_action = orm.Action(\r
+                action_type = "revise",\r
+                user_id = uidmap[sxpost.get('lasteditoruserid')],\r
+                node = post,\r
+                action_date = readTime(sxpost['lasteditdate']),\r
+            )\r
+\r
+            revise_action.save()\r
+            post.last_edited = revise_action\r
 \r
         if sxpost.get('communityowneddate', None):\r
             post.wiki = True\r
-            post.wikified_at = readTime(sxpost['communityowneddate'])\r
 \r
+            wikify_action = orm.Action(\r
+                action_type = "wikify",\r
+                user_id = 1,\r
+                node = post,\r
+                action_date = readTime(sxpost['communityowneddate'])\r
+            )\r
+\r
+            wikify_action.save()\r
+\r
+\r
+        if sxpost.get('lastactivityuserid', None):\r
+            post.last_activity_by_id = uidmap[sxpost['lastactivityuserid']]\r
+            post.last_activity_at = readTime(sxpost['lastactivitydate'])\r
+\r
+            \r
         if sxpost.get('posttypeid') == '1': #question\r
             post.node_type = "question"\r
             post.title = sxpost['title']\r
@@ -222,31 +323,49 @@ def postimport(dump, uidmap, tagmap):
             tagnames = sxpost['tags'].replace(u'ö', '-').replace(u'é', '').replace(u'à', '')\r
             post.tagnames = tagnames\r
 \r
-            post.view_count = sxpost.get('viewcount', 0)\r
-            post.favourite_count = sxpost.get('favoritecount', 0)\r
-            post.answer_count = sxpost.get('answercount', 0)\r
+            post.extra_count = sxpost.get('viewcount', 0)\r
 \r
-            if sxpost.get('lastactivityuserid', None):\r
-                post.last_activity_by_id = uidmap[sxpost['lastactivityuserid']]\r
-                post.last_activity_at = readTime(sxpost['lastactivitydate'])\r
+            #if sxpost.get('closeddate', None):\r
+            #    post.marked = True\r
+            #\r
+            #    close_action = orm.Action(\r
+            #        action_type = "close",\r
+            #        user_id = 1,\r
+            #        node = post,\r
+            #        action_date = datetime.now() - timedelta(days=7)\r
+            #    )\r
+            #\r
+            #    close_action.save()\r
+            #    post.extra_action = close_action\r
 \r
-            if sxpost.get('closeddate', None):\r
-                post.closed = True\r
-                post.closed_by_id = 1\r
-                post.closed_at = datetime.now()\r
+            #if sxpost.get('acceptedanswerid', None):\r
+            #    accepted[int(sxpost.get('acceptedanswerid'))] = post\r
 \r
-            if sxpost.get('acceptedanswerid', None):\r
-                post.accepted_answer_id = int(sxpost.get('acceptedanswerid'))\r
-                accepted[int(sxpost.get('acceptedanswerid'))] = post\r
+            #post.save()\r
 \r
         else:\r
-            post.node_type = "answer"\r
             post.parent_id = sxpost['parentid']\r
 \r
-            if int(post.id) in accepted:\r
-                post.accepted = True\r
-                post.accepted_at = datetime.now()\r
-                post.accepted_by_id = accepted[int(post.id)].author_id\r
+            #if int(post.id) in accepted:\r
+                #post.marked = True\r
+\r
+                #accept_action = orm.Action(\r
+                #    action_type = "acceptanswer",\r
+                #    user_id = accepted[int(post.id)].author_id,\r
+                #    node = post,\r
+                #    action_date = datetime.now() - timedelta(days=7)\r
+                #)\r
+\r
+                #accept_action.save()\r
+\r
+\r
+                #post.accepted_at = datetime.now()\r
+                #post.accepted_by_id = accepted[int(post.id)].author_id\r
+\r
+                #accepted[int(post.id)].extra_ref = post\r
+                #accepted[int(post.id)].save()\r
+\r
+        post.save()\r
 \r
         all[int(post.id)] = post\r
 \r
@@ -266,18 +385,35 @@ def comment_import(dump, uidmap, posts):
             author_id = uidmap[sxc.get('userid', 1)],\r
             body = sxc['text'],\r
             parent_id = sxc.get('postid'),\r
-            vote_up_count = 0,\r
-            vote_down_count = 0\r
         )\r
 \r
         if sxc.get('deletiondate', None):\r
-            oc.deleted = True\r
-            oc.deleted_at = readTime(sxc['deletiondate'])\r
-            oc.deleted_by_id = uidmap[sxc['deletionuserid']]\r
+            delete_action = orm.Action(\r
+                action_type = "delete",\r
+                user_id = uidmap[sxc['deletionuserid']],\r
+                action_date = readTime(sxc['deletiondate'])\r
+            )\r
+\r
             oc.author_id = uidmap[sxc['deletionuserid']]\r
+            oc.save()\r
+\r
+            delete_action.node = oc\r
+            delete_action.save()\r
+\r
+            oc.deleted = delete_action\r
         else:\r
             oc.author_id = uidmap[sxc.get('userid', 1)]\r
+            oc.save()\r
 \r
+        create_action = orm.Action(\r
+            action_type = "comment",\r
+            user_id = oc.author_id,\r
+            node = oc,\r
+            action_date = oc.added_at\r
+        )\r
+\r
+        create_action.save()\r
+        oc.save()\r
 \r
         posts[oc.id] = oc\r
         mapping[int(sxc['id'])] = int(oc.id)\r
@@ -285,12 +421,10 @@ def comment_import(dump, uidmap, posts):
     return posts, mapping\r
 \r
 \r
-def save_posts(posts, tagmap):\r
+def add_tags_to_posts(posts, tagmap):\r
     for post in posts.values():\r
-        post.save()\r
-\r
         if post.node_type == "question":\r
-            tags = filter(lambda t: t is not None, [tagmap.get(n, None) for n in post.tagnames.split()])\r
+            tags = [tag for tag in [tagmap.get(name.strip()) for name in post.tagnames.split(u' ') if name] if tag]\r
             post.tagnames = " ".join([t.name for t in tags]).strip()\r
             post.tags = tags\r
 \r
@@ -313,64 +447,182 @@ def create_and_activate_revision(post):
     post.active_revision_id = rev.id\r
     post.save()\r
 \r
-\r
 def post_vote_import(dump, uidmap, posts):\r
     votes = readTable(dump, "Posts2Votes")\r
+    close_reasons = dict([(r['id'], r['name']) for r in readTable(dump, "CloseReasons")])\r
+\r
+    user2vote = []\r
 \r
     for sxv in votes:\r
-        if sxv['votetypeid'] in ('2', '3'):\r
-            ov = orm.Vote(\r
-                node_id = sxv['postid'],\r
+        action = orm.Action(\r
+            user_id=uidmap[sxv['userid']],\r
+            action_date = readTime(sxv['creationdate']),\r
+        )\r
+\r
+        node = posts.get(int(sxv['postid']), None)\r
+        if not node: continue\r
+        action.node = node\r
+\r
+        if sxv['votetypeid'] == '1':\r
+            answer = node\r
+            question = posts.get(int(answer.parent_id), None)\r
+\r
+            action.action_type = "acceptanswer"\r
+            action.save()\r
+\r
+            answer.marked = True\r
+            answer.extra_action = action\r
+\r
+            question.extra_ref_id = answer.id\r
+\r
+            answer.save()\r
+            question.save()\r
+\r
+        elif sxv['votetypeid'] in ('2', '3'):\r
+            if not (action.node.id, action.user_id) in user2vote:\r
+                user2vote.append((action.node.id, action.user_id))\r
+\r
+                action.action_type = (sxv['votetypeid'] == '2') and "voteup" or "votedown"\r
+                action.save()\r
+\r
+                ov = orm.Vote(\r
+                    node_id = action.node.id,\r
+                    user_id = action.user_id,\r
+                    voted_at = action.action_date,\r
+                    value = sxv['votetypeid'] == '2' and 1 or -1,\r
+                    action = action\r
+                )\r
+                ov.save()\r
+            else:\r
+                action.action_type = "unknown"\r
+                action.save()\r
+\r
+        elif sxv['votetypeid'] in ('4', '12', '13'):\r
+            action.action_type = "flag"\r
+            action.save()\r
+\r
+            of = orm.Flag(\r
+                node = action.node,\r
+                user_id = action.user_id,\r
+                flagged_at = action.action_date,\r
+                reason = '',\r
+                action = action\r
+            )\r
+\r
+            of.save()\r
+\r
+        elif sxv['votetypeid'] == '5':\r
+            action.action_type = "favorite"\r
+            action.save()\r
+\r
+        elif sxv['votetypeid'] == '6':\r
+            action.action_type = "close"\r
+            action.extra = dbsafe_encode(close_reasons[sxv['comment']])\r
+            action.save()\r
+\r
+            node.marked = True\r
+            node.extra_action = action\r
+            node.save()\r
+\r
+        elif sxv['votetypeid'] == '7':\r
+            action.action_type = "unknown"\r
+            action.save()\r
+            \r
+            node.marked = False\r
+            node.extra_action = None\r
+            node.save()\r
+\r
+        elif sxv['votetypeid'] == '10':\r
+            action.action_type = "delete"\r
+            action.save()\r
+\r
+            node.deleted = action\r
+            node.save()\r
+\r
+        elif sxv['votetypeid'] == '11':\r
+            action.action_type = "unknown"\r
+            action.save()\r
+\r
+            node.deleted = None\r
+            node.save()\r
+\r
+        else:\r
+            action.action_type = "unknown"\r
+            action.save()\r
+\r
+\r
+        if sxv.get('targetrepchange', None):\r
+            rep = orm.ActionRepute(\r
+                action = action,\r
+                date = action.action_date,\r
+                user_id = uidmap[sxv['targetuserid']],\r
+                value = int(sxv['targetrepchange'])\r
+            )\r
+\r
+            rep.save()\r
+\r
+        if sxv.get('voterrepchange', None):\r
+            rep = orm.ActionRepute(\r
+                action = action,\r
+                date = action.action_date,\r
                 user_id = uidmap[sxv['userid']],\r
-                voted_at = readTime(sxv['creationdate']),\r
-                vote = sxv['votetypeid'] == '2' and 1 or -1,\r
+                value = int(sxv['voterrepchange'])\r
             )\r
 \r
-            if sxv['votetypeid'] == '2':\r
-                posts[int(sxv['postid'])].vote_up_count += 1\r
-            else:\r
-                posts[int(sxv['postid'])].vote_down_count += 1\r
+            rep.save()\r
 \r
-            ov.save()\r
 \r
 def comment_vote_import(dump, uidmap, comments, posts):\r
     votes = readTable(dump, "Comments2Votes")\r
+    user2vote = []\r
 \r
     for sxv in votes:\r
-        if sxv['votetypeid'] in ('2', '3'):\r
-            ov = orm.Vote(\r
-                node_id = comments[int(sxv['postcommentid'])],\r
-                user_id = uidmap[sxv['userid']],\r
-                voted_at = readTime(sxv['creationdate']),\r
-                vote = sxv['votetypeid'] == '2' and 1 or -1,\r
-            )\r
+        if sxv['votetypeid'] == "2":\r
+            comment_id = comments[int(sxv['postcommentid'])]\r
+            user_id = uidmap[sxv['userid']]\r
 \r
-            if sxv['votetypeid'] == '2':\r
-                posts[comments[int(sxv['postcommentid'])]].vote_up_count += 1\r
-            else:\r
-                posts[comments[int(sxv['postcommentid'])]].vote_down_count += 1\r
+            if not (comment_id, user_id) in user2vote:\r
+                user2vote.append((comment_id, user_id))\r
+\r
+                action = orm.Action(\r
+                    action_type = "voteupcomment",\r
+                    user_id = user_id,\r
+                    action_date = readTime(sxv['creationdate']),\r
+                    node_id = comment_id\r
+                )\r
+                action.save()\r
 \r
-            ov.save()\r
+                ov = orm.Vote(\r
+                    node_id = comment_id,\r
+                    user_id = user_id,\r
+                    voted_at = action.action_date,\r
+                    value = 1,\r
+                    action = action\r
+                )\r
 \r
+                ov.save()\r
 \r
+                posts[int(action.node_id)].score += 1\r
+                posts[int(action.node_id)].save()\r
 \r
-def badges_import(dump, uidmap):\r
+\r
+\r
+def badges_import(dump, uidmap, post_list):\r
     node_ctype = orm['contenttypes.contenttype'].objects.get(name='node')\r
-    obadges = dict([(b.slug, b) for b in orm.Badge.objects.all()])\r
+    obadges = dict([(b.cls, b) for b in orm.Badge.objects.all()])\r
     sxbadges = dict([(int(b['id']), b) for b in readTable(dump, "Badges")])\r
+    user_badge_count = {}\r
 \r
     sx_to_osqa = {}\r
 \r
     for id, sxb in sxbadges.items():\r
-        slug = slugify(sxb['name'].replace('&', 'and'))\r
-        if slug in obadges:\r
-            sx_to_osqa[id] = obadges[slug]\r
+        cls = "".join(sxb['name'].replace('&', 'And').split(' '))\r
+\r
+        if cls in obadges:\r
+            sx_to_osqa[id] = obadges[cls]\r
         else:\r
             osqab = orm.Badge(\r
-                name = sxb['name'],\r
-                slug = slugify(sxb['name']),\r
-                description = sxb['description'],\r
-                multiple = sxb.get('single', 'false') == 'false',\r
+                cls = cls,\r
                 awarded_count = 0,\r
                 type = sxb['class']                \r
             )\r
@@ -382,21 +634,33 @@ def badges_import(dump, uidmap):
 \r
     for sxa in sxawards:\r
         badge = sx_to_osqa[int(sxa['badgeid'])]\r
+\r
+        user_id = uidmap[sxa['userid']]\r
+        if not user_badge_count.get(user_id, None):\r
+            user_badge_count[user_id] = 0\r
+\r
+        action = orm.Action(\r
+            action_type = "award",\r
+            user_id = user_id,\r
+            action_date = readTime(sxa['date'])\r
+        )\r
+\r
+        action.save()\r
+\r
         osqaa = orm.Award(\r
             user_id = uidmap[sxa['userid']],\r
             badge = badge,\r
-            content_type = node_ctype,\r
-            object_id = 1\r
+            node = post_list[user_badge_count[user_id]],\r
+            awarded_at = action.action_date,\r
+            action = action\r
         )\r
 \r
-        osqaawards.append(osqaa)\r
+        osqaa.save()\r
         badge.awarded_count += 1\r
+        user_badge_count[user_id] += 1\r
 \r
-    for b in sx_to_osqa.values():\r
-        b.save()\r
-\r
-    for a in osqaawards:\r
-        a.save()\r
+    for badge in obadges.values():\r
+        badge.save()\r
 \r
 \r
 def reset_sequences():\r
@@ -411,12 +675,10 @@ def sximport(dump, options):
     tagmap = tagsimport(dump, uidmap)\r
     posts = postimport(dump, uidmap, tagmap)\r
     posts, comments = comment_import(dump, uidmap, posts)\r
-    save_posts(posts, tagmap)\r
+    add_tags_to_posts(posts, tagmap)\r
     post_vote_import(dump, uidmap, posts)\r
     comment_vote_import(dump, uidmap, comments, posts)\r
-    for post in posts.values():\r
-        post.save()\r
-    badges_import(dump, uidmap)\r
+    badges_import(dump, uidmap, posts.values())\r
 \r
     from south.db import db\r
     db.commit_transaction()\r
@@ -429,29 +691,27 @@ PG_SEQUENCE_RESETS = """
 SELECT setval('"auth_user_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "auth_user";\r
 SELECT setval('"auth_user_groups_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "auth_user_groups";\r
 SELECT setval('"auth_user_user_permissions_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "auth_user_user_permissions";\r
-SELECT setval('"activity_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "activity";\r
-SELECT setval('"forum_subscriptionsettings_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_subscriptionsettings";\r
-SELECT setval('"forum_validationhash_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_validationhash";\r
-SELECT setval('"forum_authkeyuserassociation_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_authkeyuserassociation";\r
-SELECT setval('"tag_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "tag";\r
-SELECT setval('"forum_markedtag_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_markedtag";\r
-SELECT setval('"forum_node_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node";\r
-SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node_tags";\r
-SELECT setval('"forum_noderevision_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_noderevision";\r
-SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node_tags";\r
-SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node_tags";\r
-SELECT setval('"favorite_question_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "favorite_question";\r
-SELECT setval('"forum_questionsubscription_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_questionsubscription";\r
-SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node_tags";\r
-SELECT setval('"vote_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "vote";\r
-SELECT setval('"flagged_item_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "flagged_item";\r
-SELECT setval('"badge_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "badge";\r
-SELECT setval('"award_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "award";\r
-SELECT setval('"repute_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "repute";\r
-SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_node_tags";\r
-SELECT setval('"forum_keyvalue_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_keyvalue";\r
-SELECT setval('"forum_openidnonce_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_openidnonce";\r
-SELECT setval('"forum_openidassociation_id_seq"', coalesce(max("id"), 1) + 2, max("id") IS NOT null) FROM "forum_openidassociation";\r
+SELECT setval('"forum_keyvalue_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_keyvalue";\r
+SELECT setval('"forum_action_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_action";\r
+SELECT setval('"forum_actionrepute_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_actionrepute";\r
+SELECT setval('"forum_subscriptionsettings_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_subscriptionsettings";\r
+SELECT setval('"forum_validationhash_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_validationhash";\r
+SELECT setval('"forum_authkeyuserassociation_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_authkeyuserassociation";\r
+SELECT setval('"forum_tag_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_tag";\r
+SELECT setval('"forum_markedtag_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_markedtag";\r
+SELECT setval('"forum_node_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_node";\r
+SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_node_tags";\r
+SELECT setval('"forum_noderevision_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_noderevision";\r
+SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_node_tags";\r
+SELECT setval('"forum_questionsubscription_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_questionsubscription";\r
+SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_node_tags";\r
+SELECT setval('"forum_node_tags_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_node_tags";\r
+SELECT setval('"forum_vote_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_vote";\r
+SELECT setval('"forum_flag_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_flag";\r
+SELECT setval('"forum_badge_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_badge";\r
+SELECT setval('"forum_award_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_award";\r
+SELECT setval('"forum_openidnonce_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_openidnonce";\r
+SELECT setval('"forum_openidassociation_id_seq"', coalesce(max("id"), 1), max("id") IS NOT null) FROM "forum_openidassociation";\r
 """\r
 \r
 \r
index c0898c3f9e9a36bb6b388db7cb19e81d1876dcf8..6b95d10dba34e78fdb86d5883caf6eeaec22776b 100644 (file)
@@ -48,30 +48,28 @@ class Migration(DataMigration):
             'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
             'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
         },\r
-        'forum.activity': {\r
-            'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
-            'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
-            'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+        '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
-            'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
-            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
-            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+            '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.anonymousnode': {\r
-            'Meta': {'object_name': 'AnonymousNode', '_ormbases': ['forum.Node']},\r
-            'convertible_to': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
-            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
-            'validation_hash': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_content'", 'to': "orm['forum.Node']"})\r
-        },\r
-        'forum.answer': {\r
-            'Meta': {'object_name': 'Answer', '_ormbases': ['forum.Node'], 'db_table': "u'answer'"},\r
-            'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
-            'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
-            'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
-            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
-            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
-            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+        '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
@@ -82,47 +80,37 @@ class Migration(DataMigration):
             'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
         },\r
         'forum.award': {\r
-            'Meta': {'unique_together': "(('content_type', 'object_id', 'user', 'badge'),)", 'object_name': 'Award', 'db_table': "u'award'"},\r
+            'Meta': {'unique_together': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'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': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+            'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Badge']"}),\r
             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
-            'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
-            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
-            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+            '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': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'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'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
-            'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),\r
             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
-            'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
-            'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
             'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
         },\r
-        'forum.favoritequestion': {\r
-            'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
-            'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+        'forum.flag': {\r
+            'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
-            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
-            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
-        },\r
-        'forum.flaggeditem': {\r
-            'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
-            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
             'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
-            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
-            'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
-            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
         },\r
         'forum.keyvalue': {\r
             'Meta': {'object_name': 'KeyValue'},\r
             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
             'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
-            'value': ('forum.models.utils.PickledObjectField', [], {})\r
+            'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})\r
         },\r
         'forum.markedtag': {\r
             'Meta': {'object_name': 'MarkedTag'},\r
@@ -138,22 +126,23 @@ class Migration(DataMigration):
             'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
             'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
             'body': ('django.db.models.fields.TextField', [], {}),\r
-            'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
-            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
-            'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
-            'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            '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
-            'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
-            'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+            '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
-            'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
             'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
             'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
             'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
             'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
             'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
-            'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
-            'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
         },\r
         'forum.noderevision': {\r
             'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
@@ -184,44 +173,14 @@ class Migration(DataMigration):
             'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
             'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
         },\r
-        'forum.question': {\r
-            'Meta': {'object_name': 'Question', '_ormbases': ['forum.Node'], 'db_table': "u'question'"},\r
-            'accepted_answer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'question_accepting'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Answer']"}),\r
-            'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
-            'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
-            'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
-            'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
-            'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
-            'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
-            'favourite_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
-            'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
-            'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
-            'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True'}),\r
-            'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscriptions'", 'through': "'QuestionSubscription'", 'to': "orm['forum.User']"}),\r
-            'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
-            'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
-            'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
-        },\r
         'forum.questionsubscription': {\r
             'Meta': {'object_name': 'QuestionSubscription'},\r
             'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
-            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 17, 2, 50, 12, 337000)'}),\r
-            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+            'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 3, 11, 46, 22, 80000)'}),\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.repute': {\r
-            'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
-            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
-            'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
-            'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
-            'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
-            'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
-            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
-            'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
-            'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
-        },\r
         'forum.subscriptionsettings': {\r
             'Meta': {'object_name': 'SubscriptionSettings'},\r
             'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
@@ -244,7 +203,7 @@ class Migration(DataMigration):
             'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
         },\r
         'forum.tag': {\r
-            'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+            '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
@@ -257,25 +216,23 @@ class Migration(DataMigration):
         'forum.user': {\r
             'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
             'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
-            'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            '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
-            'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
-            'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
-            'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            '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
-            'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
             'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
             'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
-            'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),\r
+            'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+            'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'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, 4, 18, 2, 50, 12, 421000)'}),\r
+            'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 4, 11, 46, 28, 428000)'}),\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
@@ -283,13 +240,13 @@ class Migration(DataMigration):
             'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
         },\r
         'forum.vote': {\r
-            'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
-            'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+            'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},\r
+            'action': ('django.db.models.fields.related.ForeignKey', [], {'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'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
-            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
-            'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
-            'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+            'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'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