]> git.openstreetmap.org Git - osqa.git/blob - forum/migrations/0023_flaten_node_inheritance_create_actions.py
closes OSQA 401 - Wrong page title in search results
[osqa.git] / forum / migrations / 0023_flaten_node_inheritance_create_actions.py
1 # encoding: utf-8\r
2 import datetime\r
3 from south.db import db\r
4 from south.v2 import DataMigration\r
5 from django.db import models\r
6 from forum.migrations import ProgressBar\r
7 \r
8 GAIN_BY_UPVOTED = 1\r
9 GAIN_BY_ANSWER_ACCEPTED = 2\r
10 GAIN_BY_ACCEPTING_ANSWER = 3\r
11 GAIN_BY_DOWNVOTE_CANCELED = 4\r
12 GAIN_BY_CANCELING_DOWNVOTE = 5\r
13 LOST_BY_CANCELLING_ACCEPTED_ANSWER = -1\r
14 LOST_BY_ACCEPTED_ANSWER_CANCELED = -2\r
15 LOST_BY_DOWNVOTED = -3\r
16 LOST_BY_FLAGGED = -4\r
17 LOST_BY_DOWNVOTING = -5\r
18 LOST_BY_FLAGGED_3_TIMES = -6\r
19 LOST_BY_FLAGGED_5_TIMES = -7\r
20 LOST_BY_UPVOTE_CANCELED = -8\r
21 \r
22 class Migration(DataMigration):\r
23     \r
24     def forwards(self, orm):\r
25         rephist = dict([(t, []) for t in range(-8, 6) if t != 0])\r
26 \r
27         r_count = orm.Repute.objects.count()\r
28         print "\nCalculating rep gain/losses history through %d records:" % r_count\r
29         progress = ProgressBar(r_count)\r
30 \r
31         for r in orm.Repute.objects.all():\r
32             l = rephist.get(r.reputation_type, None)\r
33             if l is None: continue\r
34 \r
35             if (len(l) == 0) or (l[-1][1] != r.value):\r
36                 l.append((r.reputed_at, r.value))\r
37 \r
38             progress.update()\r
39 \r
40         print "\n...done\n"\r
41 \r
42 \r
43         def repval_at(reptype, repdate, default):\r
44             l = rephist.get(reptype, None)\r
45 \r
46             if l is None: return 0\r
47             if len(l) == 0: return default\r
48 \r
49             for r in l:\r
50                 if r[0] <= repdate:\r
51                     return r[1] or default\r
52 \r
53 \r
54         q_count = orm.Question.objects.count()\r
55         print "\nConverting %d questions:" % q_count\r
56         progress = ProgressBar(q_count)\r
57 \r
58         for q in orm.Question.objects.all():\r
59             n = q.node_ptr\r
60             n.last_activity_at = q.last_activity_at\r
61             n.last_activity_by = q.last_activity_by\r
62 \r
63             if q.accepted_answer:\r
64                 n.extra_ref = q.accepted_answer.node_ptr\r
65                 \r
66             n.extra_count = q.view_count\r
67 \r
68             n.marked = q.closed\r
69             n.wiki = q.wiki\r
70 \r
71             n.save()\r
72 \r
73             ask = orm.Action(\r
74                 user = n.author,\r
75                 action_date = n.added_at,\r
76                 node = n,\r
77                 action_type = "ask",\r
78                 extra = ''\r
79             )\r
80 \r
81             ask.save()\r
82 \r
83             if n.deleted:\r
84                 action = orm.Action(\r
85                     user = n.deleted_by,\r
86                     node = n,\r
87                     action_type = "delete",\r
88                     action_date = n.deleted_at or datetime.datetime.now(),\r
89                     extra = ''\r
90                 )\r
91 \r
92                 action.save()\r
93 \r
94 \r
95             if n.marked:\r
96                 action = orm.Action(\r
97                     user = q.closed_by,\r
98                     node = n,\r
99                     action_type = "close",\r
100                     extra = q.close_reason,\r
101                     action_date = q.closed_at or datetime.datetime.now(),\r
102                 )\r
103 \r
104                 action.save()\r
105 \r
106             if n.wiki:\r
107                 action = orm.Action(\r
108                     user = n.author,\r
109                     node = n,\r
110                     action_type = "wikify",\r
111                     action_date = q.wikified_at or datetime.datetime.now(),\r
112                     extra = ''\r
113                 )\r
114 \r
115                 action.save()\r
116 \r
117             progress.update()\r
118 \r
119         print "\n...done\n"\r
120 \r
121         a_count = orm.Answer.objects.count()\r
122         print "\nConverting %d answers:" % a_count\r
123         progress = ProgressBar(a_count)\r
124 \r
125         for a in orm.Answer.objects.all():\r
126             n = a.node_ptr\r
127 \r
128             n.marked = a.accepted\r
129             n.wiki = a.wiki\r
130 \r
131             n.save()\r
132 \r
133             ans = orm.Action(\r
134                 user = n.author,\r
135                 action_date = n.added_at,\r
136                 node = n,\r
137                 action_type = "answer",\r
138                 extra = ''\r
139             )\r
140 \r
141             ans.save()\r
142 \r
143             if n.deleted:\r
144                 action = orm.Action(\r
145                     user = n.deleted_by,\r
146                     node = n,\r
147                     action_type = "delete",\r
148                     action_date = n.deleted_at or datetime.datetime.now(),\r
149                     extra = ''\r
150                 )\r
151 \r
152                 action.save()\r
153 \r
154             if a.accepted:\r
155                 action = orm.Action(\r
156                     user = a.accepted_by,\r
157                     node = n,\r
158                     action_type = "acceptanswer",\r
159                     action_date = a.accepted_at or datetime.datetime.now(),\r
160                     extra = ''\r
161                 )\r
162 \r
163                 action.save()\r
164 \r
165                 if not a.wiki or a.wikified_at > action.action_date:\r
166                     if action.user == n.author:\r
167                         rep = orm.ActionRepute(\r
168                             action = action,\r
169                             user = action.user,\r
170                             value = repval_at(GAIN_BY_ACCEPTING_ANSWER, action.action_date, 2)\r
171                         )\r
172                         rep.save()\r
173 \r
174                     if n.author != n.parent.author:\r
175                         rep = orm.ActionRepute(\r
176                             action = action,\r
177                             user = n.author,\r
178                             value = repval_at(GAIN_BY_ANSWER_ACCEPTED, action.action_date, 15)\r
179                         )\r
180                         rep.save()\r
181 \r
182             if n.wiki:\r
183                 action = orm.Action(\r
184                     user = n.author,\r
185                     node = n,\r
186                     action_type = "wikify",\r
187                     action_date = a.wikified_at or datetime.datetime.now(),\r
188                     extra = ''\r
189                 )\r
190 \r
191                 action.save()\r
192 \r
193             progress.update()\r
194 \r
195         print "\n...done\n"\r
196 \r
197         v_count = orm.Vote.objects.count()\r
198         print "\nConverting %d votes:" % v_count\r
199         progress = ProgressBar(v_count)\r
200 \r
201         for v in orm.Vote.objects.exclude(canceled=True):\r
202             a = orm.Action(\r
203                 action_type = (v.vote == 1) and ((v.node.node_type == "comment") and "voteupcomment" or "voteup") or "votedown",\r
204                 user = v.user,\r
205                 node = v.node,\r
206                 action_date = v.voted_at,\r
207                 canceled = v.canceled,\r
208                 extra = ''\r
209             )\r
210 \r
211             a.save()\r
212 \r
213             def impl(node):\r
214                 if node.node_type == "question":\r
215                     return orm.Question.objects.get(node_ptr=node)\r
216                 else:\r
217                     return orm.Answer.objects.get(node_ptr=node)\r
218 \r
219             if a.node.node_type in ("question", "answer") and (not a.node.wiki or impl(a.node).wikified_at > a.action_date):\r
220                 reptype, default = (v.vote == 1) and (GAIN_BY_UPVOTED, 10) or (LOST_BY_DOWNVOTED, 2)\r
221                 rep = orm.ActionRepute(\r
222                     action = a,\r
223                     user = a.node.author,\r
224                     value = repval_at(reptype, a.action_date, default) or default\r
225                 )\r
226                 rep.save()\r
227 \r
228                 if v.vote == -1:\r
229                     rep = orm.ActionRepute(\r
230                         action = a,\r
231                         user = a.node.author,\r
232                         value = repval_at(LOST_BY_DOWNVOTING, a.action_date, 1) or default\r
233                     )\r
234                     rep.save()\r
235 \r
236             progress.update()\r
237 \r
238         print "\n...done\n"\r
239 \r
240         f_count = orm.FlaggedItem.objects.count()\r
241         print "\nConverting %d flags:" % f_count\r
242         progress = ProgressBar(f_count)\r
243 \r
244         for f in orm.FlaggedItem.objects.all():\r
245             a = orm.Action(\r
246                 action_type = "flag",\r
247                 user = f.user,\r
248                 node = f.node,\r
249                 action_date = f.flagged_at,\r
250                 extra = f.reason or ''\r
251             )\r
252 \r
253             a.save()\r
254 \r
255             rep = orm.ActionRepute(\r
256                 action = a,\r
257                 user = a.node.author,\r
258                 value = repval_at(LOST_BY_FLAGGED, a.action_date, 2) or 2\r
259             )\r
260             rep.save()\r
261 \r
262             progress.update()\r
263 \r
264         print "\n...done\n"\r
265 \r
266         n_count = orm.Node.objects.all().count()\r
267         print "\nChecking flag count of %d nodes:" % n_count\r
268         progress = ProgressBar(n_count)\r
269 \r
270         for n in orm.Node.objects.all():\r
271             flags = list(orm.Action.objects.filter(action_type="flag", node=n, canceled=False).order_by('-action_date'))\r
272 \r
273             if len(flags) >= 3:\r
274                 a = flags[2]\r
275                 rep = orm.ActionRepute(\r
276                     action = a,\r
277                     user = n.author,\r
278                     value = repval_at(LOST_BY_FLAGGED_3_TIMES, a.action_date, 30)\r
279                 )\r
280                 rep.save()\r
281 \r
282 \r
283             if len(flags) >= 5:\r
284                 a = flags[4]\r
285                 rep = orm.ActionRepute(\r
286                     action = a,\r
287                     user = n.author,\r
288                     value = repval_at(LOST_BY_FLAGGED_5_TIMES, a.action_date, 100)\r
289                 )\r
290                 rep.save()\r
291 \r
292             progress.update()\r
293 \r
294         print "\n...done\n"\r
295 \r
296         c_count = orm.Node.objects.filter(node_type="comment").count()\r
297         print "\nCreating %d comment actions:" % c_count\r
298         progress = ProgressBar(c_count)\r
299 \r
300         for c in orm.Node.objects.filter(node_type="comment").all():\r
301             a = orm.Action(\r
302                 action_type = "comment",\r
303                 user = c.author,\r
304                 node = c,\r
305                 action_date = c.added_at,\r
306                 extra = ''\r
307             )\r
308 \r
309             a.save()\r
310 \r
311             if c.deleted:\r
312                 action = orm.Action(\r
313                     user = c.deleted_by,\r
314                     node = c,\r
315                     action_type = "delete",\r
316                     action_date = c.deleted_at or datetime.datetime.now(),\r
317                     extra = ''\r
318                 )\r
319 \r
320                 action.save()\r
321 \r
322             progress.update()\r
323 \r
324         print "\n...done\n"\r
325 \r
326 \r
327         r_count = orm.NodeRevision.objects.exclude(revision=1).count()\r
328         print "\nCreating %d edit actions:" % r_count\r
329         progress = ProgressBar(r_count)\r
330 \r
331         for r in orm.NodeRevision.objects.exclude(revision=1):\r
332             a = orm.Action(\r
333                 action_type = "revise",\r
334                 user = r.author,\r
335                 node = r.node,\r
336                 action_date = r.revised_at,\r
337                 extra = r.revision\r
338             )\r
339 \r
340             a.save()\r
341             progress.update()\r
342 \r
343         print "\n...done\n"\r
344 \r
345         u_count = orm.User.objects.all().count()\r
346         print "\nCreating %d user join actions and reputation recalculation:" % u_count\r
347         progress = ProgressBar(u_count)\r
348 \r
349         for u in orm.User.objects.all():\r
350             a = orm.Action(\r
351                 user = u,\r
352                 action_date = u.date_joined,\r
353                 action_type = "userjoins",\r
354             )\r
355 \r
356             a.save()\r
357 \r
358             rep = orm.ActionRepute(\r
359                 action = a,\r
360                 user = u,\r
361                 value = 1\r
362             )\r
363             rep.save()\r
364 \r
365             new_rep = orm.ActionRepute.objects.filter(user=u).aggregate(reputation=models.Sum('value'))['reputation']\r
366 \r
367             if new_rep < 0:\r
368                 new_rep = 1\r
369 \r
370             u.reputation = new_rep\r
371             u.save()\r
372 \r
373             progress.update()\r
374 \r
375         print "\n...done\n"\r
376 \r
377     \r
378     \r
379     def backwards(self, orm):\r
380         "Write your backwards methods here."\r
381     \r
382     models = {\r
383         'auth.group': {\r
384             'Meta': {'object_name': 'Group'},\r
385             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
386             'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
387             'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
388         },\r
389         'auth.permission': {\r
390             'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
391             'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
392             'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
393             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
394             'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
395         },\r
396         'auth.user': {\r
397             'Meta': {'object_name': 'User'},\r
398             'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
399             'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
400             'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
401             'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
402             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
403             'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
404             'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
405             'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
406             'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
407             'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
408             'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
409             'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
410             'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
411         },\r
412         'contenttypes.contenttype': {\r
413             'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
414             'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
415             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
416             'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
417             'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
418         },\r
419         'forum.action': {\r
420             'Meta': {'object_name': 'Action'},\r
421             'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
422             'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
423             'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
424             'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
425             'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
426             'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
427             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
428             'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
429             'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
430             'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
431         },\r
432         'forum.actionrepute': {\r
433             'Meta': {'object_name': 'ActionRepute'},\r
434             'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
435             'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
436             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
437             'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
438             'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
439         },\r
440         'forum.activity': {\r
441             'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
442             'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
443             'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
444             'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
445             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
446             'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
447             'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
448             'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
449         },\r
450         'forum.anonymousnode': {\r
451             'Meta': {'object_name': 'AnonymousNode', '_ormbases': ['forum.Node']},\r
452             'convertible_to': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
453             'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
454             'validation_hash': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_content'", 'to': "orm['forum.Node']"})\r
455         },\r
456         'forum.answer': {\r
457             'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
458             'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
459             'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
460             'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
461             'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),\r
462             'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
463             'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
464         },\r
465         'forum.authkeyuserassociation': {\r
466             'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
467             'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
468             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
469             'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
470             'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
471             'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
472         },\r
473         'forum.award': {\r
474             'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
475             'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
476             'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
477             'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
478             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
479             'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
480             'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
481             'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
482         },\r
483         'forum.badge': {\r
484             'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
485             'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
486             'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
487             'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
488             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
489             'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
490             'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
491             'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
492             'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
493         },\r
494         'forum.favoritequestion': {\r
495             'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
496             'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
497             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
498             'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'favourites'", 'to': "orm['forum.Question']"}),\r
499             'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
500         },\r
501         'forum.flaggeditem': {\r
502             'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
503             'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
504             'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
505             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
506             'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
507             'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
508             'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
509         },\r
510         'forum.keyvalue': {\r
511             'Meta': {'object_name': 'KeyValue'},\r
512             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
513             'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
514             'value': ('forum.models.utils.PickledObjectField', [], {})\r
515         },\r
516         'forum.markedtag': {\r
517             'Meta': {'object_name': 'MarkedTag'},\r
518             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
519             'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
520             'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
521             'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
522         },\r
523         'forum.node': {\r
524             'Meta': {'object_name': 'Node'},\r
525             'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
526             'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
527             'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
528             'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
529             'body': ('django.db.models.fields.TextField', [], {}),\r
530             'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
531             'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
532             'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
533             'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
534             'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
535             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
536             'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
537             'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
538             'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
539             'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
540             'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
541             'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
542             'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
543             'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
544             'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
545             'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
546             'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
547             'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
548         },\r
549         'forum.noderevision': {\r
550             'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
551             'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
552             'body': ('django.db.models.fields.TextField', [], {}),\r
553             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
554             'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
555             'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
556             'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
557             'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
558             'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
559             'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
560         },\r
561         'forum.openidassociation': {\r
562             'Meta': {'object_name': 'OpenIdAssociation'},\r
563             'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
564             'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
565             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
566             'issued': ('django.db.models.fields.IntegerField', [], {}),\r
567             'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
568             'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
569             'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
570         },\r
571         'forum.openidnonce': {\r
572             'Meta': {'object_name': 'OpenIdNonce'},\r
573             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
574             'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
575             'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
576             'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
577         },\r
578         'forum.question': {\r
579             'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
580             'accepted_answer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'question_accepting'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Answer']"}),\r
581             'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
582             'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
583             'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
584             'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
585             'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
586             'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
587             'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
588             'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),\r
589             'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
590             'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
591             'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
592         },\r
593         'forum.questionsubscription': {\r
594             'Meta': {'object_name': 'QuestionSubscription'},\r
595             'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
596             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
597             'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 27, 11, 40, 32, 68000)'}),\r
598             'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
599             'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
600         },\r
601         'forum.repute': {\r
602             'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
603             'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
604             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
605             'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
606             'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
607             'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
608             'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
609             'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
610             'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
611             'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
612         },\r
613         'forum.subscriptionsettings': {\r
614             'Meta': {'object_name': 'SubscriptionSettings'},\r
615             'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
616             'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
617             'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
618             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
619             'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
620             'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
621             'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
622             'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
623             'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
624             'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
625             'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
626             'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
627             'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
628             'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
629             'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
630             'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
631             'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
632             'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
633         },\r
634         'forum.tag': {\r
635             'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
636             'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
637             'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
638             'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
639             'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
640             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
641             'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
642             'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
643             'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
644         },\r
645         'forum.user': {\r
646             'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
647             'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
648             'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
649             'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
650             'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
651             'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
652             'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
653             'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
654             'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
655             'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
656             'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
657             'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
658             'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
659             'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
660             'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
661             'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
662             'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
663             'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
664         },\r
665         'forum.validationhash': {\r
666             'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
667             'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 11, 40, 32, 153000)'}),\r
668             'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
669             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
670             'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
671             'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
672             'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
673         },\r
674         'forum.vote': {\r
675             'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
676             'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
677             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
678             'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
679             'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
680             'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
681             'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
682         }\r
683     }\r
684     \r
685     complete_apps = ['forum']\r