From: hernani
Date: Fri, 7 May 2010 01:15:39 +0000 (+0000)
Subject: Merging the experimental branch back to trunk.
X-Git-Tag: live~973
X-Git-Url: https://git.openstreetmap.org./osqa.git/commitdiff_plain/410bfa05ee36ed1d99356c443a5f3f6aa3ee9578
Merging the experimental branch back to trunk.
git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@156 0cfe37f9-358a-4d5e-be75-b63607b5c754
---
diff --git a/forum/actions/__init__.py b/forum/actions/__init__.py
new file mode 100644
index 0000000..a681069
--- /dev/null
+++ b/forum/actions/__init__.py
@@ -0,0 +1,3 @@
+from meta import *
+from node import *
+from user import *
\ No newline at end of file
diff --git a/forum/actions/meta.py b/forum/actions/meta.py
new file mode 100644
index 0000000..a45fe58
--- /dev/null
+++ b/forum/actions/meta.py
@@ -0,0 +1,207 @@
+from django.utils.translation import ugettext as _
+from django.db.models import F
+from forum.models.action import ActionProxy, DummyActionProxy
+from forum.models import Vote, Flag
+import settings
+
+class VoteAction(ActionProxy):
+ def update_node_score(self, inc):
+ self.node.score = F('score') + inc
+ self.node.save()
+
+ def process_vote_action(self, value):
+ self.update_node_score(value)
+ vote = Vote(node=self.node, user=self.user, action=self, value=value)
+ vote.save()
+
+ def cancel_action(self):
+ vote = self.vote.all()[0]
+ self.update_node_score(-vote.value)
+ vote.delete()
+
+ @classmethod
+ def get_for(cls, user, node):
+ try:
+ vote = Vote.objects.get(user=user, node=node)
+ return vote.value
+ except:
+ return None
+
+ def describe_vote(self, vote_desc, viewer=None):
+ return _("%(user)s %(vote_desc)s %(post_desc)s") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'vote_desc': vote_desc, 'post_desc': self.describe_node(viewer, self.node)
+ }
+
+
+class VoteUpAction(VoteAction):
+ def repute_users(self):
+ self.repute(self.node.author, int(settings.REP_GAIN_BY_UPVOTED))
+
+ def process_action(self):
+ self.process_vote_action(1)
+ self.user.reset_vote_up_count_cache()
+
+ def cancel_action(self):
+ super(VoteUpAction, self).cancel_action()
+ self.user.reset_vote_up_count_cache()
+
+ def describe(self, viewer=None):
+ return self.describe_vote(_("voted up"), viewer)
+
+class VoteDownAction(VoteAction):
+ def repute_users(self):
+ self.repute(self.node.author, -int(settings.REP_LOST_BY_DOWNVOTED))
+ self.repute(self.user, -int(settings.REP_LOST_BY_DOWNVOTING))
+
+ def process_action(self):
+ self.process_vote_action(-1)
+ self.user.reset_vote_down_count_cache()
+
+ def cancel_action(self):
+ super(VoteDownAction, self).cancel_action()
+ self.user.reset_vote_down_count_cache()
+
+ def describe(self, viewer=None):
+ return self.describe_vote(_("voted down"), viewer)
+
+
+class VoteUpCommentAction(VoteUpAction):
+ def repute_users(self):
+ pass
+
+ def process_action(self):
+ self.process_vote_action(1)
+
+ def cancel_action(self):
+ super(VoteUpAction, self).cancel_action()
+
+ def describe(self, viewer=None):
+ return self.describe_vote(_("liked"), viewer)
+
+
+class FlagAction(ActionProxy):
+ def repute_users(self):
+ self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED))
+
+ def process_action(self):
+ flag = Flag(user=self.user, node=self.node, action=self, reason=self.extra)
+ flag.save()
+ self.node.reset_flag_count_cache()
+
+ if self.node.flag_count == int(settings.FLAG_COUNT_TO_HIDE_POST):
+ self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED_3_TIMES))
+
+ if self.node.flag_count == int(settings.FLAG_COUNT_TO_DELETE_POST):
+ self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED_5_TIMES))
+ if not self.node.deleted:
+ DeleteAction(node=self.node, user=self.user, extra="BYFLAGGED").save()
+
+ def cancel_action(self):
+ self.flag.all()[0].delete()
+ self.node.reset_flag_count_cache()
+
+ @classmethod
+ def get_for(cls, user, node):
+ try:
+ flag = Flag.objects.get(user=user, node=node)
+ return flag.reason or _("No reason given")
+ except:
+ return None
+
+ def describe(self, viewer=None):
+ return _("%(user)s flagged %(post_desc)s: %(reason)s") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'post_desc': self.describe_node(viewer, self.node), 'reason': self.extra
+ }
+
+
+class AcceptAnswerAction(ActionProxy):
+ def repute_users(self):
+ if (self.user == self.node.parent.author) and (not self.user == self.node.author):
+ self.repute(self.user, int(settings.REP_GAIN_BY_ACCEPTING))
+
+ if self.user != self.node.author:
+ self.repute(self.node.author, int(settings.REP_GAIN_BY_ACCEPTED))
+
+ def process_action(self):
+ self.node.parent.extra_ref = self.node
+ self.node.parent.save()
+ self.node.marked = True
+ self.node.extra_action = self
+ self.node.save()
+
+ def cancel_action(self):
+ self.node.parent.extra_ref = None
+ self.node.parent.save()
+ self.node.marked = False
+ self.node.extra_action = None
+ self.node.save()
+
+ def describe(self, viewer=None):
+ answer = self.node
+ question = answer.parent
+
+ if self.user == question.author:
+ asker = (self.user == viewer) and _("your") or _("his")
+ else:
+ asker = self.hyperlink(question.author.get_profile_url(), question.author.username)
+
+ return _("%(user)s accepted %(answerer)s answer on %(asker)s question %(question)s") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'answerer': self.hyperlink(answer.author.get_profile_url(), self.friendly_username(viewer, answer.author)),
+ 'asker': asker,
+ 'question': self.hyperlink(question.get_absolute_url(), question.title)
+ }
+
+
+class FavoriteAction(ActionProxy):
+ def process_action(self):
+ self.node.reset_favorite_count_cache()
+
+ def cancel_action(self):
+ self.process_action()
+
+ def describe(self, viewer=None):
+ return _("%(user)s marked %(post_desc)s as favorite") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'post_desc': self.describe_node(viewer, self.node),
+ }
+
+
+class DeleteAction(ActionProxy):
+ def process_action(self):
+ self.node.deleted = self
+ self.node.save()
+
+ if self.node.node_type == "answer":
+ self.node.question.reset_answer_count_cache()
+
+ def cancel_action(self):
+ self.node.deleted = None
+ self.node.save()
+
+ if self.node.node_type == "answer":
+ self.node.question.reset_answer_count_cache()
+
+ def describe(self, viewer=None):
+ return _("%(user)s deleted %(post_desc)s: %(reason)s") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'post_desc': self.describe_node(viewer, self.node), 'reason': self.reason(),
+ }
+
+ def reason(self):
+ if self.extra != "BYFLAGGED":
+ return self.extra
+ else:
+ return _("flagged by multiple users: ") + "; ".join([f.extra for f in FlagAction.objects.filter(node=self.node)])
+
+
+class QuestionViewAction(DummyActionProxy):
+ def __init__(self, question, user):
+ self.viewuser = user
+ self.question = question
+
+ def process_action(self):
+ self.question.extra_count = F('extra_count') + 1
+ self.question.save()
diff --git a/forum/actions/node.py b/forum/actions/node.py
new file mode 100644
index 0000000..d7f9383
--- /dev/null
+++ b/forum/actions/node.py
@@ -0,0 +1,115 @@
+from django.utils.html import strip_tags
+from django.utils.translation import ugettext as _
+from forum.models.action import ActionProxy
+from forum.models import Comment, Question, Answer, NodeRevision
+
+class NodeEditAction(ActionProxy):
+ def create_revision_data(self, initial=False, **data):
+ revision_data = dict(summary=data.get('summary', (initial and _('Initial revision' or ''))), body=data['text'])
+
+ if data.get('title', None):
+ revision_data['title'] = strip_tags(data['title'].strip())
+
+ if data.get('tags', None):
+ revision_data['tagnames'] = data['tags'].strip()
+
+ return revision_data
+
+class AskAction(NodeEditAction):
+ def process_data(self, **data):
+ question = Question(author=self.user, **self.create_revision_data(True, **data))
+ question.save()
+ self.node = question
+
+ def describe(self, viewer=None):
+ return _("%(user)s asked %(question)s") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'question': self.hyperlink(self.node.get_absolute_url(), self.node.title)
+ }
+
+class AnswerAction(NodeEditAction):
+ def process_data(self, **data):
+ answer = Answer(author=self.user, parent=data['question'], **self.create_revision_data(True, **data))
+ answer.save()
+ self.node = answer
+
+ def process_action(self):
+ self.node.question.reset_answer_count_cache()
+
+ def describe(self, viewer=None):
+ question = self.node.parent
+ return _("%(user)s answered %(asker)s %(question)s") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'asker': self.hyperlink(question.author.get_profile_url(), self.friendly_username(viewer, question.author)),
+ 'question': self.hyperlink(self.node.get_absolute_url(), question.title)
+ }
+
+class CommentAction(ActionProxy):
+ def process_data(self, text='', parent=None):
+ comment = Comment(author=self.user, parent=parent, body=text)
+ comment.save()
+ self.node = comment
+
+ def describe(self, viewer=None):
+ return _("%(user)s commented on %(post_desc)s") % {
+ 'user': self.hyperlink(self.node.author.get_profile_url(), self.friendly_username(viewer, self.node.author)),
+ 'post_desc': self.describe_node(viewer, self.node.parent)
+ }
+
+class ReviseAction(NodeEditAction):
+ def process_data(self, **data):
+ revision_data = self.create_revision_data(**data)
+ revision = self.node.create_revision(self.user, action=self, **revision_data)
+ self.extra = revision.revision
+
+ def describe(self, viewer=None):
+ return _("%(user)s edited %(post_desc)s") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'post_desc': self.describe_node(viewer, self.node)
+ }
+
+class RetagAction(ActionProxy):
+ def process_data(self, tagnames=''):
+ active = self.node.active_revision
+ revision_data = dict(summary=_('Retag'), title=active.title, tagnames=strip_tags(tagnames.strip()), body=active.body)
+ self.node.create_revision(self.user, action=self, **revision_data)
+
+ def describe(self, viewer=None):
+ return _("%(user)s retagged %(post_desc)s") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'post_desc': self.describe_node(viewer, self.node)
+ }
+
+class RollbackAction(ActionProxy):
+ def process_data(self, activate=None):
+ previous = self.node.active_revision
+ self.node.activate_revision(self.user, activate, self)
+ self.extra = "%d:%d" % (previous.revision, activate.revision)
+
+ def describe(self, viewer=None):
+ revisions = [NodeRevision.objects.get(node=self.node, revision=int(n)) for n in self.extra.split(':')]
+
+ return _("%(user)s reverted %(post_desc)s from revision %(initial)d (%(initial_sum)s) to revision %(final)d (%(final_sum)s)") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'post_desc': self.describe_node(viewer, self.node),
+ 'initial': revisions[0].revision, 'initial_sum': revisions[0].summary,
+ 'final': revisions[1].revision, 'final_sum': revisions[1].summary,
+ }
+
+class CloseAction(ActionProxy):
+ def process_action(self):
+ self.node.extra_action = self
+ self.node.marked = True
+ self.node.save()
+
+ def cancel_action(self):
+ self.node.extra_action = None
+ self.node.marked = False
+ self.node.save()
+
+ def describe(self, viewer=None):
+ return _("%(user)s closed %(post_desc)s: %(reason)s") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'post_desc': self.describe_node(viewer, self.node),
+ 'reason': self.extra
+ }
\ No newline at end of file
diff --git a/forum/actions/user.py b/forum/actions/user.py
new file mode 100644
index 0000000..2695f9f
--- /dev/null
+++ b/forum/actions/user.py
@@ -0,0 +1,53 @@
+from django.utils.translation import ugettext as _
+from django.db.models import F
+from forum.models.action import ActionProxy
+from forum.models import Award
+from forum import settings
+
+class UserJoinsAction(ActionProxy):
+ def repute_users(self):
+ self.repute(self.user, int(settings.INITIAL_REP))
+
+class EditProfileAction(ActionProxy):
+ pass
+
+class AwardAction(ActionProxy):
+ def process_data(self, badge, trigger):
+ self.__dict__['_badge'] = badge
+ self.__dict__['_trigger'] = trigger
+
+ def process_action(self):
+ badge = self.__dict__['_badge']
+ trigger = self.__dict__['_trigger']
+
+ award = Award(user=self.user, badge=badge, trigger=trigger, action=self)
+ if self.node:
+ award.node = self.node
+
+ award.save()
+ award.badge.awarded_count = F('awarded_count') + 1
+ award.badge.save()
+ self.user.message_set.create(message=_("Congratulations, you have received a badge '%(badge_name)s'. " \
+ + u"Check out your profile .") % dict(badge_name=award.badge.name,
+ profile_url=self.user.get_profile_url()))
+
+ def cancel_action(self):
+ award = self.award
+ badge = award.badge
+ badge.awarded_count = F('awarded_count') - 1
+ badge.save()
+ award.delete()
+
+ @classmethod
+ def get_for(cls, user, node, badge):
+ try:
+ award = Award.objects.get(user=user, node=node, badge=badge)
+ return award.action
+ except:
+ return None
+
+ def describe(self, viewer=None):
+ return _("%(user)s was awarded the %(badge_name)s badge") % {
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
+ 'badge_name': self.award.all()[0].badge.name,
+ }
\ No newline at end of file
diff --git a/forum/activity.py b/forum/activity.py
deleted file mode 100644
index 1687798..0000000
--- a/forum/activity.py
+++ /dev/null
@@ -1,121 +0,0 @@
-import datetime
-from django.db.models.signals import post_save
-from forum.models import *
-from forum.models.base import marked_deleted, mark_canceled
-from forum.models.node import node_create
-from forum.models.answer import answer_accepted
-from forum.authentication import user_updated
-from forum.const import *
-
-def record_ask_event(instance, **kwargs):
- activity = Activity(user=instance.author, active_at=instance.added_at, content_object=instance, activity_type=TYPE_ACTIVITY_ASK_QUESTION)
- activity.save()
-
-node_create.connect(record_ask_event, sender=Question)
-
-
-def record_answer_event(instance, **kwargs):
- activity = Activity(user=instance.author, active_at=instance.added_at, content_object=instance, activity_type=TYPE_ACTIVITY_ANSWER)
- activity.save()
-
-node_create.connect(record_answer_event, sender=Answer)
-
-
-def record_comment_event(instance, **kwargs):
- act_type = (instance.content_object.__class__ is Question) and TYPE_ACTIVITY_COMMENT_QUESTION or TYPE_ACTIVITY_COMMENT_ANSWER
- activity = Activity(user=instance.user, active_at=instance.added_at, content_object=instance, activity_type=act_type)
- activity.save()
-
-node_create.connect(record_comment_event, sender=Comment)
-
-
-def record_revision_event(instance, created, **kwargs):
- if created and instance.revision <> 1 and instance.node.node_type in ('question', 'answer',):
- activity_type = instance.node.node_type == 'question' and TYPE_ACTIVITY_UPDATE_QUESTION or TYPE_ACTIVITY_UPDATE_ANSWER
- activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=activity_type)
- activity.save()
-
-post_save.connect(record_revision_event, sender=NodeRevision)
-
-
-def record_award_event(instance, created, **kwargs):
- if created:
- activity = Activity(user=instance.user, active_at=instance.awarded_at, content_object=instance,
- activity_type=TYPE_ACTIVITY_PRIZE)
- activity.save()
-
-post_save.connect(record_award_event, sender=Award)
-
-
-def record_answer_accepted(answer, user, **kwargs):
- activity = Activity(user=user, active_at=datetime.datetime.now(), content_object=answer, activity_type=TYPE_ACTIVITY_MARK_ANSWER)
- activity.save()
-
-answer_accepted.connect(record_answer_accepted)
-
-
-def update_last_seen(instance, **kwargs):
- user = instance.user
- user.last_seen = datetime.datetime.now()
- user.save()
-
-post_save.connect(update_last_seen, sender=Activity)
-
-
-def record_vote(instance, created, **kwargs):
- if created:
- act_type = (instance.vote == 1) and TYPE_ACTIVITY_VOTE_UP or TYPE_ACTIVITY_VOTE_DOWN
-
- activity = Activity(user=instance.user, active_at=instance.voted_at, content_object=instance, activity_type=act_type)
- activity.save()
-
-post_save.connect(record_vote, sender=Vote)
-
-
-def record_cancel_vote(instance, **kwargs):
- act_type = (instance.vote == 1) and TYPE_ACTIVITY_CANCEL_VOTE_UP or TYPE_ACTIVITY_CANCEL_VOTE_DOWN
- activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=act_type)
- activity.save()
-
-mark_canceled.connect(record_cancel_vote, sender=Vote)
-
-
-def record_delete_post(instance, **kwargs):
- act_type = (instance.__class__ is Question) and TYPE_ACTIVITY_DELETE_QUESTION or TYPE_ACTIVITY_DELETE_ANSWER
- activity = Activity(user=instance.deleted_by, active_at=datetime.datetime.now(), content_object=instance, activity_type=act_type)
- activity.save()
-
-marked_deleted.connect(record_delete_post, sender=Question)
-marked_deleted.connect(record_delete_post, sender=Answer)
-
-
-def record_update_tags(instance, created, **kwargs):
- if not created and 'tagnames' in instance.get_dirty_fields():
- activity = Activity(user=instance.author, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_TAGS)
- activity.save()
-
-post_save.connect(record_update_tags, sender=Question)
-
-
-def record_mark_offensive(instance, created, **kwargs):
- if created:
- activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance.content_object, activity_type=TYPE_ACTIVITY_MARK_OFFENSIVE)
- activity.save()
-
-post_save.connect(record_mark_offensive, sender=FlaggedItem)
-
-
-def record_favorite_question(instance, created, **kwargs):
- if created:
- activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_FAVORITE)
- activity.save()
-
-post_save.connect(record_favorite_question, sender=FavoriteQuestion)
-
-
-def record_user_full_updated(instance, **kwargs):
- activity = Activity(user=instance, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_USER_FULL_UPDATED)
- activity.save()
-
-user_updated.connect(record_user_full_updated, sender=User)
-
diff --git a/forum/admin.py b/forum/admin.py
index 3afa224..e770806 100644
--- a/forum/admin.py
+++ b/forum/admin.py
@@ -6,7 +6,7 @@ from models import *
class AnonymousQuestionAdmin(admin.ModelAdmin):
"""AnonymousQuestion admin class"""
-class QuestionAdmin(admin.ModelAdmin):
+class NodeAdmin(admin.ModelAdmin):
"""Question admin class"""
class TagAdmin(admin.ModelAdmin):
@@ -42,7 +42,7 @@ class BadgeAdmin(admin.ModelAdmin):
class ReputeAdmin(admin.ModelAdmin):
""" admin class"""
-class ActivityAdmin(admin.ModelAdmin):
+class ActionAdmin(admin.ModelAdmin):
""" admin class"""
#class BookAdmin(admin.ModelAdmin):
@@ -54,19 +54,13 @@ class ActivityAdmin(admin.ModelAdmin):
#class BookAuthorRssAdmin(admin.ModelAdmin):
# """ admin class"""
-admin.site.register(Question, QuestionAdmin)
+admin.site.register(Node, NodeAdmin)
admin.site.register(Tag, TagAdmin)
-admin.site.register(Answer, Answerdmin)
-admin.site.register(Comment, CommentAdmin)
-admin.site.register(Vote, VoteAdmin)
-admin.site.register(FlaggedItem, FlaggedItemAdmin)
-admin.site.register(FavoriteQuestion, FavoriteQuestionAdmin)
admin.site.register(QuestionRevision, QuestionRevisionAdmin)
admin.site.register(AnswerRevision, AnswerRevisionAdmin)
admin.site.register(Badge, BadgeAdmin)
admin.site.register(Award, AwardAdmin)
-admin.site.register(Repute, ReputeAdmin)
-admin.site.register(Activity, ActivityAdmin)
+admin.site.register(Action, ActionAdmin)
#admin.site.register(Book, BookAdmin)
#admin.site.register(BookAuthorInfo, BookAuthorInfoAdmin)
#admin.site.register(BookAuthorRss, BookAuthorRssAdmin)
diff --git a/forum/akismet.py b/forum/akismet.py
index 940e5dd..4138d5a 100644
--- a/forum/akismet.py
+++ b/forum/akismet.py
@@ -119,8 +119,8 @@ class Akismet(object):
if agent is None:
agent = DEFAULTAGENT % __version__
self.user_agent = user_agent % (agent, __version__)
- self.key = settings.WORDPRESS_API_KEY
- self.blog_url = settings.WORDPRESS_BLOG_URL
+ self.key = str(settings.WORDPRESS_API_KEY)
+ self.blog_url = str(settings.WORDPRESS_BLOG_URL)
def _getURL(self):
diff --git a/forum/authentication/__init__.py b/forum/authentication/__init__.py
index f6e14b7..08ea03f 100644
--- a/forum/authentication/__init__.py
+++ b/forum/authentication/__init__.py
@@ -34,7 +34,6 @@ AUTH_PROVIDERS = dict([
#todo: probably this don't belong here, also this post_stored routine needs a lot of work
user_logged_in = django.dispatch.Signal(providing_args=["user", "old_session"])
-user_updated = django.dispatch.Signal(providing_args=["instance", "updated_by"])
#def post_stored_anonymous_content(user,old_session,**kwargs):
# from forum.models import AnonymousQuestion, AnonymousAnswer
diff --git a/forum/badges/__init__.py b/forum/badges/__init__.py
index 421348f..935effd 100644
--- a/forum/badges/__init__.py
+++ b/forum/badges/__init__.py
@@ -1,10 +1,3 @@
-import re
+from forum.modules import get_modules_script
-from forum.badges.base import AbstractBadge
-from forum.modules import get_modules_script_classes
-
-ALL_BADGES = [
- cls() for name, cls
- in get_modules_script_classes('badges', AbstractBadge).items()
- if not re.search('AbstractBadge$', name)
- ]
+get_modules_script('badges')
diff --git a/forum/badges/base.py b/forum/badges/base.py
index 63b6b0b..fce6b6e 100644
--- a/forum/badges/base.py
+++ b/forum/badges/base.py
@@ -4,111 +4,66 @@ from string import lower
from django.contrib.contenttypes.models import ContentType
from django.db.models.signals import post_save
-from forum.models.user import activity_record
-from forum.models.base import denorm_update
-from forum.models import Badge, Award, Activity, Node
+from forum.models import Badge, Node
+from forum.actions import AwardAction
import logging
-class AbstractBadge(object):
-
- _instance = None
-
- @property
- def name(self):
- return " ".join(re.findall(r'([A-Z][a-z1-9]+)', re.sub('Badge', '', self.__class__.__name__)))
-
- @property
- def description(self):
- raise NotImplementedError
-
- def __new__(cls, *args, **kwargs):
- if cls._instance is None:
- cls.badge = "-".join(map(lower, re.findall(r'([A-Z][a-z1-9]+)', re.sub('Badge', '', cls.__name__))))
- cls._instance = super(AbstractBadge, cls).__new__(cls, *args, **kwargs)
-
- return cls._instance
-
- def install(self):
- try:
- installed = Badge.objects.get(slug=self.badge)
- except:
- badge = Badge(name=self.name, description=self.description, slug=self.badge, type=self.type)
- badge.save()
-
- def award_badge(self, user, obj=None, award_once=False):
- try:
- badge = Badge.objects.get(slug=self.badge)
- except:
- logging.log(1, 'Trying to award a badge not installed in the database.')
- return
-
- content_type = ContentType.objects.get_for_model(obj.__class__)
-
- awarded = user.awards.filter(badge=badge)
+installed = dict([(b.cls, b) for b in Badge.objects.all()])
- if not award_once:
- awarded = awarded.filter(content_type=content_type, object_id=obj.id)
+class BadgesMeta(type):
+ by_class = {}
+ by_id = {}
- if len(awarded):
- logging.log(1, 'Trying to award badged already awarded.')
- return
-
- award = Award(user=user, badge=badge, content_type=content_type, object_id=obj.id)
- award.save()
+ def __new__(mcs, name, bases, dic):
+ badge = type.__new__(mcs, name, bases, dic)
-class CountableAbstractBadge(AbstractBadge):
+ if not dic.get('abstract', False):
+ if not name in installed:
+ badge.ondb = Badge(cls=name, type=dic.get('type', Badge.BRONZE))
+ badge.ondb.save()
+ else:
+ badge.ondb = installed[name]
- def __init__(self, model, field, expected_value, handler):
- def wrapper(instance, sfield, old, new, **kwargs):
- if sfield == field and (new == expected_value) or (old < expected_value and new > expected_value):
- handler(instance=instance)
-
- denorm_update.connect(wrapper, sender=model, weak=False)
+ inst = badge()
-class PostCountableAbstractBadge(CountableAbstractBadge):
- def __init__(self, model, field, expected_value):
+ def hook(action, new):
+ user = inst.award_to(action)
- def handler(instance):
- self.award_badge(instance.author, instance)
+ if user:
+ badge.award(user, action, badge.award_once)
- super(PostCountableAbstractBadge, self).__init__(model, field, expected_value, handler)
+ for action in badge.listen_to:
+ action.hook(hook)
-class NodeCountableAbstractBadge(CountableAbstractBadge):
- def __init__(self, node_type, field, expected_value):
+ BadgesMeta.by_class[name] = badge
+ badge.ondb.__dict__['_class'] = inst
+ BadgesMeta.by_id[badge.ondb.id] = badge
- def handler(instance):
- if instance.node_type == node_type:
- self.award_badge(instance.author, instance)
+ return badge
- super(NodeCountableAbstractBadge, self).__init__(Node, field, expected_value, handler)
-
-class ActivityAbstractBadge(AbstractBadge):
-
- def __init__(self, activity_type, handler):
-
- def wrapper(sender, **kwargs):
- handler(instance=kwargs['instance'])
-
- activity_record.connect(wrapper, sender=activity_type, weak=False)
-
-
-class ActivityCountAbstractBadge(AbstractBadge):
+class AbstractBadge(object):
+ __metaclass__ = BadgesMeta
- def __init__(self, activity_type, count):
+ abstract = True
+ award_once = False
- def handler(sender, **kwargs):
- instance = kwargs['instance']
- if Activity.objects.filter(user=instance.user, activity_type__in=activity_type).count() == count:
- self.award_badge(instance.user, instance.content_object)
+ @property
+ def name(self):
+ raise NotImplementedError
- if not isinstance(activity_type, (tuple, list)):
- activity_type = (activity_type, )
+ @property
+ def description(self):
+ raise NotImplementedError
- for type in activity_type:
- activity_record.connect(handler, sender=type, weak=False)
+ @classmethod
+ def award(cls, user, action, once=False):
+ if once:
+ node = None
+ else:
+ node = action.node
-class FirstActivityAbstractBadge(ActivityCountAbstractBadge):
+ awarded = AwardAction.get_for(user, node, cls.ondb)
- def __init__(self, activity_type):
- super(FirstActivityAbstractBadge, self).__init__(activity_type, 1)
+ if not awarded:
+ AwardAction(user=user, node=node, ip=action.ip).save(data=dict(badge=cls.ondb, trigger=action))
\ No newline at end of file
diff --git a/forum/feed.py b/forum/feed.py
index 0a08825..4017d61 100644
--- a/forum/feed.py
+++ b/forum/feed.py
@@ -34,7 +34,7 @@ class RssLastestQuestionsFeed(Feed):
return item.added_at
def items(self, item):
- return Question.objects.filter(deleted=False).order_by('-last_activity_at')[:30]
+ return Question.objects.filter(deleted=None).order_by('-last_activity_at')[:30]
def main():
pass
diff --git a/forum/forms.py b/forum/forms.py
index 35c6083..70466b5 100644
--- a/forum/forms.py
+++ b/forum/forms.py
@@ -101,18 +101,6 @@ class SummaryField(forms.CharField):
self.label = _('update summary:')
self.help_text = _('enter a brief summary of your revision (e.g. fixed spelling, grammar, improved style, this field is optional)')
-class ModerateUserForm(forms.ModelForm):
- is_approved = forms.BooleanField(label=_("Automatically accept user's contributions for the email updates"),
- required=False)
-
- def clean_is_approved(self):
- if 'is_approved' not in self.cleaned_data:
- self.cleaned_data['is_approved'] = False
- return self.cleaned_data['is_approved']
-
- class Meta:
- model = User
- fields = ('is_approved',)
class FeedbackForm(forms.Form):
name = forms.CharField(label=_('Your name:'), required=False)
diff --git a/forum/management/__init__.py b/forum/management/__init__.py
index 49ad8d5..b654caa 100644
--- a/forum/management/__init__.py
+++ b/forum/management/__init__.py
@@ -1,13 +1,3 @@
from forum.modules import get_modules_script
-from django.db.models.signals import post_syncdb
-import forum.models
-
-def setup_badges(sender, **kwargs):
- from forum.badges import ALL_BADGES
-
- for badge in ALL_BADGES:
- badge.install()
-
-post_syncdb.connect(setup_badges, sender=forum.models)
get_modules_script('management')
\ No newline at end of file
diff --git a/forum/migrations/0014_auto__add_field_question_accepted_answer.py b/forum/migrations/0014_auto__add_field_question_accepted_answer.py
index 54ef078..e73c960 100644
--- a/forum/migrations/0014_auto__add_field_question_accepted_answer.py
+++ b/forum/migrations/0014_auto__add_field_question_accepted_answer.py
@@ -12,10 +12,9 @@ class Migration(SchemaMigration):
# Adding field 'Question.accepted_answer'
db.add_column(u'question', 'accepted_answer', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Answer'], unique=True, null=True), keep_default=False)
- if db.backend_name == "postgres" and not "pgfulltext" in settings.DISABLED_MODULES:
- pass
- db.execute("DROP TRIGGER tsvectorupdate ON question;")
- db.execute("ALTER TABLE question DROP COLUMN tsv;")
+ #if db.backend_name == "postgres" and not "pgfulltext" in settings.DISABLED_MODULES:
+ # db.execute("DROP TRIGGER tsvectorupdate ON question;")
+ # db.execute("ALTER TABLE question DROP COLUMN tsv;")
def backwards(self, orm):
diff --git a/forum/migrations/0022_auto__add_actionrepute__add_action__add_favoritenode__del_field_node_v.py b/forum/migrations/0022_auto__add_actionrepute__add_action__add_favoritenode__del_field_node_v.py
new file mode 100644
index 0000000..87b792e
--- /dev/null
+++ b/forum/migrations/0022_auto__add_actionrepute__add_action__add_favoritenode__del_field_node_v.py
@@ -0,0 +1,463 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ print "# Adding model 'ActionRepute'"
+ db.create_table('forum_actionrepute', (
+ ('action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reputes', to=orm['forum.Action'])),
+ ('by_canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('value', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'])),
+ ))
+ db.send_create_signal('forum', ['ActionRepute'])
+
+ print "# Adding model 'Action'"
+ db.create_table('forum_action', (
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True)),
+ ('extra', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('canceled_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='canceled_actions', null=True, to=orm['forum.User'])),
+ ('canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('action_date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='actions', to=orm['forum.User'])),
+ ('action_type', self.gf('django.db.models.fields.CharField')(max_length=16)),
+ ('canceled_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('ip', self.gf('django.db.models.fields.CharField')(max_length=16, null=True)),
+ ))
+ db.send_create_signal('forum', ['Action'])
+
+ print "# Deleting field 'Node.vote_up_count'"
+ db.delete_column('forum_node', 'vote_up_count')
+
+ print "# Deleting field 'Node.comment_count'"
+ db.delete_column('forum_node', 'comment_count')
+
+ print "# Deleting field 'Node.offensive_flag_count'"
+ db.delete_column('forum_node', 'offensive_flag_count')
+
+ print "# Deleting field 'Node.vote_down_count'"
+ db.delete_column('forum_node', 'vote_down_count')
+
+ print "# Adding field 'Node.wiki'"
+ db.add_column('forum_node', 'wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ print "# Adding field 'Node.marked'"
+ db.add_column('forum_node', 'marked', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ print "# Adding field 'Node.extra_count'"
+ db.add_column('forum_node', 'extra_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)
+
+ print "# Adding field 'Node.last_activity_by'"
+ db.add_column('forum_node', 'last_activity_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'], null=True), keep_default=False)
+
+ print "# Adding field 'Node.extra_ref'"
+ db.add_column('forum_node', 'extra_ref', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True), keep_default=False)
+
+ print "# Adding field 'Node.last_activity_at'"
+ db.add_column('forum_node', 'last_activity_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)
+
+ # Changing field 'Answer.node_ptr'
+ #db.alter_column(u'answer', 'node_ptr_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True, primary_key=True))
+
+ print "# Changing field 'QuestionSubscription.question'"
+ db.alter_column('forum_questionsubscription', 'question_id', self.gf('django.db.models.fields.IntegerField')())
+
+ # Removing unique constraint on 'Award', fields ['badge', 'object_id', 'content_type', 'user']
+ #db.delete_unique(u'award', ['badge_id', 'object_id', 'content_type_id', 'user_id'])
+
+ print "# Changing field 'User.gold'"
+ db.alter_column('forum_user', 'gold', self.gf('django.db.models.fields.PositiveIntegerField')())
+
+ print "# Changing field 'User.silver'"
+ db.alter_column('forum_user', 'silver', self.gf('django.db.models.fields.PositiveIntegerField')())
+
+ print "# Changing field 'User.bronze'"
+ db.alter_column('forum_user', 'bronze', self.gf('django.db.models.fields.PositiveIntegerField')())
+
+ print "# Deleting field 'Question.answer_count'"
+ db.delete_column(u'question', 'answer_count')
+
+ print "# Deleting field 'Question.favourite_count'"
+ db.delete_column(u'question', 'favourite_count')
+
+ # Changing field 'Question.node_ptr'
+ #db.alter_column(u'question', 'node_ptr_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True, primary_key=True))
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'ActionRepute'
+ db.delete_table('forum_actionrepute')
+
+ # Deleting model 'Action'
+ db.delete_table('forum_action')
+
+ # Deleting model 'FavoriteNode'
+ db.delete_table('forum_favoritenode')
+
+ # Adding field 'Node.vote_up_count'
+ db.add_column('forum_node', 'vote_up_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)
+
+ # Adding field 'Node.comment_count'
+ db.add_column('forum_node', 'comment_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0), keep_default=False)
+
+ # Adding field 'Node.offensive_flag_count'
+ db.add_column('forum_node', 'offensive_flag_count', self.gf('django.db.models.fields.SmallIntegerField')(default=0), keep_default=False)
+
+ # Adding field 'Node.vote_down_count'
+ db.add_column('forum_node', 'vote_down_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)
+
+ # Deleting field 'Node.wiki'
+ db.delete_column('forum_node', 'wiki')
+
+ # Deleting field 'Node.marked'
+ db.delete_column('forum_node', 'marked')
+
+ # Deleting field 'Node.extra_count'
+ db.delete_column('forum_node', 'extra_count')
+
+ # Deleting field 'Node.last_activity_by'
+ db.delete_column('forum_node', 'last_activity_by_id')
+
+ # Deleting field 'Node.extra_ref'
+ db.delete_column('forum_node', 'extra_ref_id')
+
+ # Deleting field 'Node.last_activity_at'
+ db.delete_column('forum_node', 'last_activity_at')
+
+ # Changing field 'Answer.node_ptr'
+ db.alter_column(u'answer', 'node_ptr_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True, primary_key=True))
+
+ # Adding unique constraint on 'Award', fields ['badge', 'object_id', 'content_type', 'user']
+ db.create_unique(u'award', ['badge_id', 'object_id', 'content_type_id', 'user_id'])
+
+ # Changing field 'User.gold'
+ db.alter_column('forum_user', 'gold', self.gf('django.db.models.fields.SmallIntegerField')())
+
+ # Changing field 'User.silver'
+ db.alter_column('forum_user', 'silver', self.gf('django.db.models.fields.SmallIntegerField')())
+
+ # Changing field 'User.bronze'
+ db.alter_column('forum_user', 'bronze', self.gf('django.db.models.fields.SmallIntegerField')())
+
+ # Adding field 'Question.answer_count'
+ db.add_column(u'question', 'answer_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0), keep_default=False)
+
+ # Adding field 'Question.favourite_count'
+ db.add_column(u'question', 'favourite_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)
+
+ # Changing field 'Question.node_ptr'
+ db.alter_column(u'question', 'node_ptr_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True))
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.anonymousnode': {
+ 'Meta': {'object_name': 'AnonymousNode', '_ormbases': ['forum.Node']},
+ 'convertible_to': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),
+ 'validation_hash': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_content'", 'to': "orm['forum.Node']"})
+ },
+ 'forum.answer': {
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.favoritequestion': {
+ 'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'favourites'", 'to': "orm['forum.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.flaggeditem': {
+ 'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.question': {
+ 'Meta': {'object_name': 'Question', 'db_table': "u'question'"},
+ 'accepted_answer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'question_accepting'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Answer']"}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),
+ 'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 27, 11, 37, 29, 356000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 11, 37, 29, 624000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.vote': {
+ 'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0023_flaten_node_inheritance_create_actions.py b/forum/migrations/0023_flaten_node_inheritance_create_actions.py
new file mode 100644
index 0000000..d4b081b
--- /dev/null
+++ b/forum/migrations/0023_flaten_node_inheritance_create_actions.py
@@ -0,0 +1,685 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from forum.migrations import ProgressBar
+
+GAIN_BY_UPVOTED = 1
+GAIN_BY_ANSWER_ACCEPTED = 2
+GAIN_BY_ACCEPTING_ANSWER = 3
+GAIN_BY_DOWNVOTE_CANCELED = 4
+GAIN_BY_CANCELING_DOWNVOTE = 5
+LOST_BY_CANCELLING_ACCEPTED_ANSWER = -1
+LOST_BY_ACCEPTED_ANSWER_CANCELED = -2
+LOST_BY_DOWNVOTED = -3
+LOST_BY_FLAGGED = -4
+LOST_BY_DOWNVOTING = -5
+LOST_BY_FLAGGED_3_TIMES = -6
+LOST_BY_FLAGGED_5_TIMES = -7
+LOST_BY_UPVOTE_CANCELED = -8
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ rephist = dict([(t, []) for t in range(-8, 6) if t != 0])
+
+ r_count = orm.Repute.objects.count()
+ print "\nCalculating rep gain/losses history through %d records:" % r_count
+ progress = ProgressBar(r_count)
+
+ for r in orm.Repute.objects.all():
+ l = rephist.get(r.reputation_type, None)
+ if l is None: continue
+
+ if (len(l) == 0) or (l[-1][1] != r.value):
+ l.append((r.reputed_at, r.value))
+
+ progress.update()
+
+ print "\n...done\n"
+
+
+ def repval_at(reptype, repdate, default):
+ l = rephist.get(reptype, None)
+
+ if l is None: return 0
+ if len(l) == 0: return default
+
+ for r in l:
+ if r[0] <= repdate:
+ return r[1] or default
+
+
+ q_count = orm.Question.objects.count()
+ print "\nConverting %d questions:" % q_count
+ progress = ProgressBar(q_count)
+
+ for q in orm.Question.objects.all():
+ n = q.node_ptr
+ n.last_activity_at = q.last_activity_at
+ n.last_activity_by = q.last_activity_by
+
+ if q.accepted_answer:
+ n.extra_ref = q.accepted_answer.node_ptr
+
+ n.extra_count = q.view_count
+
+ n.marked = q.closed
+ n.wiki = q.wiki
+
+ n.save()
+
+ ask = orm.Action(
+ user = n.author,
+ action_date = n.added_at,
+ node = n,
+ action_type = "ask",
+ extra = ''
+ )
+
+ ask.save()
+
+ if n.deleted:
+ action = orm.Action(
+ user = n.deleted_by,
+ node = n,
+ action_type = "delete",
+ action_date = n.deleted_at or datetime.datetime.now(),
+ extra = ''
+ )
+
+ action.save()
+
+
+ if n.marked:
+ action = orm.Action(
+ user = q.closed_by,
+ node = n,
+ action_type = "close",
+ extra = q.close_reason,
+ action_date = q.closed_at or datetime.datetime.now(),
+ )
+
+ action.save()
+
+ if n.wiki:
+ action = orm.Action(
+ user = n.author,
+ node = n,
+ action_type = "wikify",
+ action_date = q.wikified_at or datetime.datetime.now(),
+ extra = ''
+ )
+
+ action.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+ a_count = orm.Answer.objects.count()
+ print "\nConverting %d answers:" % a_count
+ progress = ProgressBar(a_count)
+
+ for a in orm.Answer.objects.all():
+ n = a.node_ptr
+
+ n.marked = a.accepted
+ n.wiki = a.wiki
+
+ n.save()
+
+ ans = orm.Action(
+ user = n.author,
+ action_date = n.added_at,
+ node = n,
+ action_type = "answer",
+ extra = ''
+ )
+
+ ans.save()
+
+ if n.deleted:
+ action = orm.Action(
+ user = n.deleted_by,
+ node = n,
+ action_type = "delete",
+ action_date = n.deleted_at or datetime.datetime.now(),
+ extra = ''
+ )
+
+ action.save()
+
+ if a.accepted:
+ action = orm.Action(
+ user = a.accepted_by,
+ node = n,
+ action_type = "acceptanswer",
+ action_date = a.accepted_at or datetime.datetime.now(),
+ extra = ''
+ )
+
+ action.save()
+
+ if not a.wiki or a.wikified_at > action.action_date:
+ if action.user == n.author:
+ rep = orm.ActionRepute(
+ action = action,
+ user = action.user,
+ value = repval_at(GAIN_BY_ACCEPTING_ANSWER, action.action_date, 2)
+ )
+ rep.save()
+
+ if n.author != n.parent.author:
+ rep = orm.ActionRepute(
+ action = action,
+ user = n.author,
+ value = repval_at(GAIN_BY_ANSWER_ACCEPTED, action.action_date, 15)
+ )
+ rep.save()
+
+ if n.wiki:
+ action = orm.Action(
+ user = n.author,
+ node = n,
+ action_type = "wikify",
+ action_date = a.wikified_at or datetime.datetime.now(),
+ extra = ''
+ )
+
+ action.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+ v_count = orm.Vote.objects.count()
+ print "\nConverting %d votes:" % v_count
+ progress = ProgressBar(v_count)
+
+ for v in orm.Vote.objects.exclude(canceled=True):
+ a = orm.Action(
+ action_type = (v.vote == 1) and ((v.node.node_type == "comment") and "voteupcomment" or "voteup") or "votedown",
+ user = v.user,
+ node = v.node,
+ action_date = v.voted_at,
+ canceled = v.canceled,
+ extra = ''
+ )
+
+ a.save()
+
+ def impl(node):
+ if node.node_type == "question":
+ return orm.Question.objects.get(node_ptr=node)
+ else:
+ return orm.Answer.objects.get(node_ptr=node)
+
+ if a.node.node_type in ("question", "answer") and (not a.node.wiki or impl(a.node).wikified_at > a.action_date):
+ reptype, default = (v.vote == 1) and (GAIN_BY_UPVOTED, 10) or (LOST_BY_DOWNVOTED, 2)
+ rep = orm.ActionRepute(
+ action = a,
+ user = a.node.author,
+ value = repval_at(reptype, a.action_date, default) or default
+ )
+ rep.save()
+
+ if v.vote == -1:
+ rep = orm.ActionRepute(
+ action = a,
+ user = a.node.author,
+ value = repval_at(LOST_BY_DOWNVOTING, a.action_date, 1) or default
+ )
+ rep.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+ f_count = orm.FlaggedItem.objects.count()
+ print "\nConverting %d flags:" % f_count
+ progress = ProgressBar(f_count)
+
+ for f in orm.FlaggedItem.objects.all():
+ a = orm.Action(
+ action_type = "flag",
+ user = f.user,
+ node = f.node,
+ action_date = f.flagged_at,
+ extra = f.reason or ''
+ )
+
+ a.save()
+
+ rep = orm.ActionRepute(
+ action = a,
+ user = a.node.author,
+ value = repval_at(LOST_BY_FLAGGED, a.action_date, 2) or 2
+ )
+ rep.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+ n_count = orm.Node.objects.all().count()
+ print "\nChecking flag count of %d nodes:" % n_count
+ progress = ProgressBar(n_count)
+
+ for n in orm.Node.objects.all():
+ flags = list(orm.Action.objects.filter(action_type="flag", node=n, canceled=False).order_by('-action_date'))
+
+ if len(flags) >= 3:
+ a = flags[2]
+ rep = orm.ActionRepute(
+ action = a,
+ user = n.author,
+ value = repval_at(LOST_BY_FLAGGED_3_TIMES, a.action_date, 30)
+ )
+ rep.save()
+
+
+ if len(flags) >= 5:
+ a = flags[4]
+ rep = orm.ActionRepute(
+ action = a,
+ user = n.author,
+ value = repval_at(LOST_BY_FLAGGED_5_TIMES, a.action_date, 100)
+ )
+ rep.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+ c_count = orm.Node.objects.filter(node_type="comment").count()
+ print "\nCreating %d comment actions:" % c_count
+ progress = ProgressBar(c_count)
+
+ for c in orm.Node.objects.filter(node_type="comment").all():
+ a = orm.Action(
+ action_type = "comment",
+ user = c.author,
+ node = c,
+ action_date = c.added_at,
+ extra = ''
+ )
+
+ a.save()
+
+ if c.deleted:
+ action = orm.Action(
+ user = c.deleted_by,
+ node = c,
+ action_type = "delete",
+ action_date = c.deleted_at or datetime.datetime.now(),
+ extra = ''
+ )
+
+ action.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+
+ r_count = orm.NodeRevision.objects.exclude(revision=1).count()
+ print "\nCreating %d edit actions:" % r_count
+ progress = ProgressBar(r_count)
+
+ for r in orm.NodeRevision.objects.exclude(revision=1):
+ a = orm.Action(
+ action_type = "revise",
+ user = r.author,
+ node = r.node,
+ action_date = r.revised_at,
+ extra = r.revision
+ )
+
+ a.save()
+ progress.update()
+
+ print "\n...done\n"
+
+ u_count = orm.User.objects.all().count()
+ print "\nCreating %d user join actions and reputation recalculation:" % u_count
+ progress = ProgressBar(u_count)
+
+ for u in orm.User.objects.all():
+ a = orm.Action(
+ user = u,
+ action_date = u.date_joined,
+ action_type = "userjoins",
+ )
+
+ a.save()
+
+ rep = orm.ActionRepute(
+ action = a,
+ user = u,
+ value = 1
+ )
+ rep.save()
+
+ new_rep = orm.ActionRepute.objects.filter(user=u).aggregate(reputation=models.Sum('value'))['reputation']
+
+ if new_rep < 0:
+ new_rep = 1
+
+ u.reputation = new_rep
+ u.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.anonymousnode': {
+ 'Meta': {'object_name': 'AnonymousNode', '_ormbases': ['forum.Node']},
+ 'convertible_to': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),
+ 'validation_hash': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_content'", 'to': "orm['forum.Node']"})
+ },
+ 'forum.answer': {
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.favoritequestion': {
+ 'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'favourites'", 'to': "orm['forum.Question']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.flaggeditem': {
+ 'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.question': {
+ 'Meta': {'object_name': 'Question', 'db_table': "u'question'"},
+ 'accepted_answer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'question_accepting'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Answer']"}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),
+ 'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 27, 11, 40, 32, 68000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 11, 40, 32, 153000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.vote': {
+ 'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0024_auto__del_repute__del_vote__del_answer__del_flaggeditem__del_anonymous.py b/forum/migrations/0024_auto__del_repute__del_vote__del_answer__del_flaggeditem__del_anonymous.py
new file mode 100644
index 0000000..38a7604
--- /dev/null
+++ b/forum/migrations/0024_auto__del_repute__del_vote__del_answer__del_flaggeditem__del_anonymous.py
@@ -0,0 +1,377 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting model 'Repute'
+ db.delete_table(u'repute')
+
+ # Deleting model 'Vote'
+ db.delete_table(u'vote')
+
+ # Deleting model 'Answer'
+ db.delete_table(u'answer')
+
+ # Deleting model 'FlaggedItem'
+ db.delete_table(u'flagged_item')
+
+ # Deleting model 'AnonymousNode'
+ db.delete_table('forum_anonymousnode')
+
+ # Deleting model 'FavoriteQuestion'
+ db.delete_table(u'favorite_question')
+
+ # Deleting model 'Question'
+ db.delete_table(u'question')
+
+ # Deleting field 'Node.deleted_at'
+ db.delete_column('forum_node', 'deleted_at')
+
+ # Deleting field 'Node.last_edited_by'
+ db.delete_column('forum_node', 'last_edited_by_id')
+
+ # Deleting field 'Node.deleted'
+ db.delete_column('forum_node', 'deleted')
+
+ # Deleting field 'Node.deleted_by'
+ db.delete_column('forum_node', 'deleted_by_id')
+
+ # Deleting field 'Node.last_edited_at'
+ db.delete_column('forum_node', 'last_edited_at')
+
+
+ def backwards(self, orm):
+
+ # Adding model 'Repute'
+ db.create_table(u'repute', (
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reputes', null=True, to=orm['forum.Node'])),
+ ('reputed_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Question'])),
+ ('value', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),
+ ('canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('reputation_type', self.gf('django.db.models.fields.SmallIntegerField')()),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reputes', to=orm['forum.User'])),
+ ('user_previous_rep', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['Repute'])
+
+ # Adding model 'Vote'
+ db.create_table(u'vote', (
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='votes', null=True, to=orm['forum.Node'])),
+ ('vote', self.gf('django.db.models.fields.SmallIntegerField')()),
+ ('canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='votes', to=orm['forum.User'])),
+ ('voted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['Vote'])
+
+ # Adding model 'Answer'
+ db.create_table(u'answer', (
+ ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('accepted_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'], null=True)),
+ ('accepted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('wikified_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('node_ptr', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True, primary_key=True)),
+ ('accepted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ))
+ db.send_create_signal('forum', ['Answer'])
+
+ # Adding model 'FlaggedItem'
+ db.create_table(u'flagged_item', (
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='flaggeditems', null=True, to=orm['forum.Node'])),
+ ('flagged_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('reason', self.gf('django.db.models.fields.CharField')(max_length=300, null=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='flaggeditems', to=orm['forum.User'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['FlaggedItem'])
+
+ # Adding model 'AnonymousNode'
+ db.create_table('forum_anonymousnode', (
+ ('convertible_to', self.gf('django.db.models.fields.CharField')(default='node', max_length=16)),
+ ('validation_hash', self.gf('django.db.models.fields.related.ForeignKey')(related_name='anonymous_content', to=orm['forum.Node'])),
+ ('node_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True, primary_key=True)),
+ ))
+ db.send_create_signal('forum', ['AnonymousNode'])
+
+ # Adding model 'FavoriteQuestion'
+ db.create_table(u'favorite_question', (
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(related_name='favourites', to=orm['forum.Question'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='user_favorite_questions', to=orm['forum.User'])),
+ ))
+ db.send_create_signal('forum', ['FavoriteQuestion'])
+
+ # Adding model 'Question'
+ db.create_table(u'question', (
+ ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('last_activity_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='last_active_in_questions', null=True, to=orm['forum.User'])),
+ ('close_reason', self.gf('django.db.models.fields.SmallIntegerField')(null=True, blank=True)),
+ ('last_activity_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('view_count', self.gf('django.db.models.fields.IntegerField')(default=0)),
+ ('node_ptr', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True, primary_key=True)),
+ ('accepted_answer', self.gf('django.db.models.fields.related.OneToOneField')(related_name='question_accepting', unique=True, null=True, to=orm['forum.Answer'])),
+ ('closed', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('wikified_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('closed_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('closed_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='closed_questions', null=True, to=orm['forum.User'], blank=True)),
+ ))
+ db.send_create_signal('forum', ['Question'])
+
+ # Adding field 'Node.deleted_at'
+ db.add_column('forum_node', 'deleted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)
+
+ # Adding field 'Node.last_edited_by'
+ db.add_column('forum_node', 'last_edited_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='last_edited_nodes', null=True, to=orm['forum.User'], blank=True), keep_default=False)
+
+ # Adding field 'Node.deleted'
+ db.add_column('forum_node', 'deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ # Adding field 'Node.deleted_by'
+ db.add_column('forum_node', 'deleted_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='deleted_nodes', null=True, to=orm['forum.User'], blank=True), keep_default=False)
+
+ # Adding field 'Node.last_edited_at'
+ db.add_column('forum_node', 'last_edited_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 23, 43, 52, 301000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 23, 43, 52, 512000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0025_auto__add_field_node_extra_action__add_field_node_deleted__add_field_n.py b/forum/migrations/0025_auto__add_field_node_extra_action__add_field_node_deleted__add_field_n.py
new file mode 100644
index 0000000..2cf638c
--- /dev/null
+++ b/forum/migrations/0025_auto__add_field_node_extra_action__add_field_node_deleted__add_field_n.py
@@ -0,0 +1,267 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'Node.extra_action'
+ db.add_column('forum_node', 'extra_action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='extra_node', null=True, to=orm['forum.Action']), keep_default=False)
+
+ # Adding field 'Node.deleted'
+ db.add_column('forum_node', 'deleted', self.gf('django.db.models.fields.related.ForeignKey')(related_name='deleted_node', unique=True, null=True, to=orm['forum.Action']), keep_default=False)
+
+ # Adding field 'Node.last_edited'
+ db.add_column('forum_node', 'last_edited', self.gf('django.db.models.fields.related.ForeignKey')(related_name='edited_node', unique=True, null=True, to=orm['forum.Action']), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'Node.extra_action'
+ db.delete_column('forum_node', 'extra_action_id')
+
+ # Deleting field 'Node.deleted'
+ db.delete_column('forum_node', 'deleted_id')
+
+ # Deleting field 'Node.last_edited'
+ db.delete_column('forum_node', 'last_edited_id')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 23, 49, 37, 322000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 23, 49, 37, 506000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0026_reset_deleted_and_lastedited_flags.py b/forum/migrations/0026_reset_deleted_and_lastedited_flags.py
new file mode 100644
index 0000000..8521ffd
--- /dev/null
+++ b/forum/migrations/0026_reset_deleted_and_lastedited_flags.py
@@ -0,0 +1,278 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from forum.migrations import ProgressBar
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ n_count = orm.Node.objects.all().count()
+ print "\nReseting %d nodes:" % n_count
+ progress = ProgressBar(n_count)
+
+ for n in orm.Node.objects.all():
+ try:
+ d = orm.Action.objects.get(node=n, action_type="delete", canceled=False)
+ n.deleted_id = d.id
+ except Exception, e:
+ n.deleted = None
+
+ if orm.Action.objects.filter(node=n, action_type="revise").count() > 0:
+ n.last_edited_id = orm.Action.objects.filter(node=n, action_type="revise").order_by('-action_date')[0].id
+ else:
+ n.last_edited = None
+
+
+ if n.node_type == "answer" and n.marked:
+ n.extra_action_id = orm.Action.objects.get(node=n, action_type="acceptanswer", canceled=False).id
+
+ if n.node_type == "question" and n.marked:
+ n.extra_action_id = orm.Action.objects.get(node=n, action_type="close", canceled=False).id
+
+ n.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 23, 55, 36, 647000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 23, 55, 36, 708000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0027_auto__del_activity.py b/forum/migrations/0027_auto__del_activity.py
new file mode 100644
index 0000000..589b5bb
--- /dev/null
+++ b/forum/migrations/0027_auto__del_activity.py
@@ -0,0 +1,254 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting model 'Activity'
+ db.delete_table(u'activity')
+
+
+ def backwards(self, orm):
+
+ # Adding model 'Activity'
+ db.create_table(u'activity', (
+ ('is_auditted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'])),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('active_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('activity_type', self.gf('django.db.models.fields.SmallIntegerField')()),
+ ))
+ db.send_create_signal('forum', ['Activity'])
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 1, 30, 30, 35000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 30, 1, 30, 30, 211000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0028_auto__add_field_action_canceled_ip__add_field_actionrepute_date.py b/forum/migrations/0028_auto__add_field_action_canceled_ip__add_field_actionrepute_date.py
new file mode 100644
index 0000000..1170bf7
--- /dev/null
+++ b/forum/migrations/0028_auto__add_field_action_canceled_ip__add_field_actionrepute_date.py
@@ -0,0 +1,253 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'Action.canceled_ip'
+ db.add_column('forum_action', 'canceled_ip', self.gf('django.db.models.fields.CharField')(default='', max_length=16), keep_default=False)
+
+ # Adding field 'ActionRepute.date'
+ db.add_column('forum_actionrepute', 'date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'Action.canceled_ip'
+ db.delete_column('forum_action', 'canceled_ip')
+
+ # Deleting field 'ActionRepute.date'
+ db.delete_column('forum_actionrepute', 'date')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 21, 20, 24, 880000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 30, 21, 20, 35, 361000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0029_repute_dates.py b/forum/migrations/0029_repute_dates.py
new file mode 100644
index 0000000..14d6e62
--- /dev/null
+++ b/forum/migrations/0029_repute_dates.py
@@ -0,0 +1,259 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from forum.migrations import ProgressBar
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ r_count = orm.ActionRepute.objects.count()
+ print "\nAdding dates to %d repute actions:" % r_count
+ progress = ProgressBar(r_count)
+
+ for r in orm.ActionRepute.objects.all():
+ a = r.action
+
+ if r.by_canceled:
+ r.date = a.canceled_at
+ else:
+ r.date = a.action_date
+
+ r.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 21, 21, 16, 237000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 30, 21, 21, 16, 298000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0030_auto__chg_field_action_extra__chg_field_keyvalue_value.py b/forum/migrations/0030_auto__chg_field_action_extra__chg_field_keyvalue_value.py
new file mode 100644
index 0000000..cd4e1f1
--- /dev/null
+++ b/forum/migrations/0030_auto__chg_field_action_extra__chg_field_keyvalue_value.py
@@ -0,0 +1,253 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Changing field 'Action.extra'
+ db.alter_column('forum_action', 'extra', self.gf('forum.models.utils.PickledObjectField')(null=True))
+
+ # Changing field 'KeyValue.value'
+ db.alter_column('forum_keyvalue', 'value', self.gf('forum.models.utils.PickledObjectField')(null=True))
+
+
+ def backwards(self, orm):
+
+ # Changing field 'Action.extra'
+ db.alter_column('forum_action', 'extra', self.gf('django.db.models.fields.CharField')(max_length=255))
+
+ # Changing field 'KeyValue.value'
+ db.alter_column('forum_keyvalue', 'value', self.gf('forum.models.utils.PickledObjectField')())
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 30, 23, 58, 8, 677000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 1, 23, 58, 8, 841000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0031_alter_pickle_storage.py b/forum/migrations/0031_alter_pickle_storage.py
new file mode 100644
index 0000000..5c8bb7b
--- /dev/null
+++ b/forum/migrations/0031_alter_pickle_storage.py
@@ -0,0 +1,274 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from forum.migrations import ProgressBar
+from forum.models.utils import dbsafe_encode
+
+try:
+ from cPickle import loads, dumps
+except ImportError:
+ from pickle import loads, dumps
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ k_count = orm.KeyValue.objects.count()
+ print "\nConverting %d keyvalue objects:" % k_count
+ progress = ProgressBar(k_count)
+
+ for kv in orm.KeyValue.objects.all():
+ try:
+ o = loads(kv.value.encode('utf-8'))
+ except:
+ o = kv.value
+
+ kv.value = dbsafe_encode(o, compress_object=True)
+ kv.save()
+ progress.update()
+
+ print "\n...done\n"
+
+ a_count = orm.Action.objects.count()
+ print "\nConverting %d actions extra fields:" % a_count
+ progress = ProgressBar(a_count)
+
+ for a in orm.Action.objects.all():
+ a.extra = dbsafe_encode(a.extra, compress_object=True)
+ a.save()
+ progress.update()
+
+ print "\n...done\n"
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 1, 0, 0, 32, 37000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 2, 0, 0, 32, 86000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0032_auto__del_field_user_hide_ignored_questions__del_field_user_questions_.py b/forum/migrations/0032_auto__del_field_user_hide_ignored_questions__del_field_user_questions_.py
new file mode 100644
index 0000000..7a15772
--- /dev/null
+++ b/forum/migrations/0032_auto__del_field_user_hide_ignored_questions__del_field_user_questions_.py
@@ -0,0 +1,263 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting field 'User.hide_ignored_questions'
+ db.delete_column('forum_user', 'hide_ignored_questions')
+
+ # Deleting field 'User.questions_per_page'
+ db.delete_column('forum_user', 'questions_per_page')
+
+ # Deleting field 'User.email_key'
+ db.delete_column('forum_user', 'email_key')
+
+ # Adding field 'Node.in_moderation'
+ db.add_column('forum_node', 'in_moderation', self.gf('django.db.models.fields.related.ForeignKey')(related_name='moderated_node', unique=True, null=True, to=orm['forum.Action']), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Adding field 'User.hide_ignored_questions'
+ db.add_column('forum_user', 'hide_ignored_questions', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ # Adding field 'User.questions_per_page'
+ db.add_column('forum_user', 'questions_per_page', self.gf('django.db.models.fields.SmallIntegerField')(default=10), keep_default=False)
+
+ # Adding field 'User.email_key'
+ db.add_column('forum_user', 'email_key', self.gf('django.db.models.fields.CharField')(max_length=32, null=True), keep_default=False)
+
+ # Deleting field 'Node.in_moderation'
+ db.delete_column('forum_node', 'in_moderation_id')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 2, 4, 54, 13, 72000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 3, 4, 54, 13, 256000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0033_auto__add_flag__add_vote__add_field_badge_cls__del_unique_badge_type_n.py b/forum/migrations/0033_auto__add_flag__add_vote__add_field_badge_cls__del_unique_badge_type_n.py
new file mode 100644
index 0000000..f2b38e8
--- /dev/null
+++ b/forum/migrations/0033_auto__add_flag__add_vote__add_field_badge_cls__del_unique_badge_type_n.py
@@ -0,0 +1,333 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ db.rename_table('award', 'forum_award')
+ db.rename_table('badge', 'forum_badge')
+ db.rename_table('tag', 'forum_tag')
+
+ # Adding model 'Flag'
+ db.create_table('forum_flag', (
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'])),
+ ('action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='flag', unique=True, to=orm['forum.Action'])),
+ ('reason', self.gf('django.db.models.fields.CharField')(max_length=300)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'])),
+ ('flagged_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ))
+ #db.send_create_signal('forum', ['Flag'])
+
+ # Adding model 'Vote'
+ db.create_table('forum_vote', (
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'])),
+ ('action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='vote', unique=True, to=orm['forum.Action'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('value', self.gf('django.db.models.fields.SmallIntegerField')()),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'])),
+ ('voted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
+ ))
+ #db.send_create_signal('forum', ['Vote'])
+
+ # Adding field 'Badge.cls'
+ db.add_column('forum_badge', 'cls', self.gf('django.db.models.fields.CharField')(max_length=50, null=True), keep_default=False)
+
+ # Removing unique constraint on 'Badge', fields ['type', 'name']
+ db.delete_unique(u'forum_badge', ['type', 'name'])
+
+ # Deleting field 'Award.notified'
+ db.delete_column(u'forum_award', 'notified')
+
+ # Adding field 'Award.node'
+ db.add_column('forum_award', 'node', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['forum.Node'], null=True), keep_default=False)
+
+ # Adding field 'Award.trigger'
+ db.add_column('forum_award', 'trigger', self.gf('django.db.models.fields.related.ForeignKey')(related_name='awards', null=True, to=orm['forum.Action']), keep_default=False)
+
+ # Adding field 'Award.action'
+ db.add_column('forum_award', 'action', self.gf('django.db.models.fields.related.ForeignKey')(default=1, related_name='award', to=orm['forum.Action']), keep_default=False)
+
+ # Adding unique constraint on 'Award', fields ['node', 'badge', 'user']
+ #db.create_unique('forum_award', ['node_id', 'badge_id', 'user_id'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Flag'
+ db.delete_table('forum_flag')
+
+ # Deleting model 'Vote'
+ db.delete_table('forum_vote')
+
+ # Deleting field 'Badge.cls'
+ db.delete_column('forum_badge', 'cls')
+
+ # Adding unique constraint on 'Badge', fields ['type', 'name']
+ db.create_unique(u'badge', ['type', 'name'])
+
+ # Adding field 'Award.notified'
+ db.add_column(u'award', 'notified', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ # Deleting field 'Award.node'
+ db.delete_column('forum_award', 'node_id')
+
+ # Deleting field 'Award.trigger'
+ db.delete_column('forum_award', 'trigger_id')
+
+ # Deleting field 'Award.action'
+ db.delete_column('forum_award', 'action_id')
+
+ # Removing unique constraint on 'Award', fields ['node', 'badge', 'user']
+ db.delete_unique('forum_award', ['node_id', 'badge_id', 'user_id'])
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'unique_together': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award'", 'to': "orm['forum.Action']"}),
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'object_name': 'Badge'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.flag': {
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 3, 11, 41, 55, 831000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag'},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 4, 11, 41, 59, 140000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.vote': {
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0034_new_badge_and_award.py b/forum/migrations/0034_new_badge_and_award.py
new file mode 100644
index 0000000..89399f9
--- /dev/null
+++ b/forum/migrations/0034_new_badge_and_award.py
@@ -0,0 +1,344 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from forum.migrations import ProgressBar
+from forum.models.utils import dbsafe_decode
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ b_count = orm.Badge.objects.count()
+ print "\nConverting %d badges:" % b_count
+ progress = ProgressBar(b_count)
+
+ for b in orm.Badge.objects.all():
+ b.cls = "".join([s[0].upper() + s[1:] for s in b.slug.split('-')])
+ b.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+ ctypes = dict([(ct.name, ct.id) for ct in orm['contenttypes.ContentType'].objects.all()])
+
+ a_count = orm.Award.objects.count()
+ print "\nConverting %d awards:" % a_count
+ progress = ProgressBar(a_count)
+
+ for a in orm.Award.objects.all():
+ if a.content_type.id == ctypes['user']:
+ a.node = None
+ else:
+ try:
+ a.node = orm.Node.objects.get(id=a.object_id)
+ except:
+ a.delete()
+ continue
+
+ action = orm.Action(
+ user = a.user,
+ node = a.node,
+ action_type = "award",
+ action_date = a.awarded_at,
+ )
+
+ action.save()
+
+ a.action = action
+ a.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+
+ a_count = orm.Action.objects.filter(action_type__in=("voteup", "votedown", "voteupcomment")).count()
+ print "\nConverting %d votes:" % a_count
+ progress = ProgressBar(a_count)
+
+ for a in orm.Action.objects.filter(action_type__in=("voteup", "votedown", "voteupcomment"), canceled=False):
+ v = orm.Vote(
+ user = a.user,
+ node = a.node,
+ value = (a.action_type in ("voteup", "voteupcomment")) and 1 or -1,
+ action = a,
+ voted_at = a.action_date
+ )
+
+ v.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+ a_count = orm.Action.objects.filter(action_type__in=("voteup", "votedown", "voteupcomment")).count()
+ print "\nConverting %d votes:" % a_count
+ progress = ProgressBar(a_count)
+
+ for a in orm.Action.objects.filter(action_type="flag", canceled=False):
+ f = orm.Flag(
+ user = a.user,
+ node = a.node,
+ reason = a.extra,
+ action = a,
+ flagged_at = a.action_date
+ )
+
+ f.save()
+
+ progress.update()
+
+ print "\n...done\n"
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'unique_together': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award'", 'to': "orm['forum.Action']"}),
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Badge']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'object_name': 'Badge'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.flag': {
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 3, 11, 43, 54, 540000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag'},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 4, 11, 43, 54, 592000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.vote': {
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/migrations/0035_auto__del_field_award_object_id__del_field_award_content_type__add_uni.py b/forum/migrations/0035_auto__del_field_award_object_id__del_field_award_content_type__add_uni.py
new file mode 100644
index 0000000..b566ef0
--- /dev/null
+++ b/forum/migrations/0035_auto__del_field_award_object_id__del_field_award_content_type__add_uni.py
@@ -0,0 +1,296 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting field 'Award.object_id'
+ db.delete_column('forum_award', 'object_id')
+
+ # Deleting field 'Award.content_type'
+ db.delete_column('forum_award', 'content_type_id')
+
+ # Adding unique constraint on 'Award', fields ['action']
+ db.create_unique('forum_award', ['action_id'])
+
+ # Deleting field 'Badge.multiple'
+ db.delete_column('forum_badge', 'multiple')
+
+ # Deleting field 'Badge.name'
+ db.delete_column('forum_badge', 'name')
+
+ # Deleting field 'Badge.slug'
+ db.delete_column('forum_badge', 'slug')
+
+ # Deleting field 'Badge.description'
+ db.delete_column('forum_badge', 'description')
+
+
+ def backwards(self, orm):
+
+ # Adding field 'Award.object_id'
+ db.add_column('forum_award', 'object_id', self.gf('django.db.models.fields.PositiveIntegerField')(default=1), keep_default=False)
+
+ # Adding field 'Award.content_type'
+ db.add_column('forum_award', 'content_type', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['contenttypes.ContentType']), keep_default=False)
+
+ # Removing unique constraint on 'Award', fields ['action']
+ db.delete_unique('forum_award', ['action_id'])
+
+ # Adding field 'Badge.multiple'
+ db.add_column('forum_badge', 'multiple', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)
+
+ # Adding field 'Badge.name'
+ db.add_column('forum_badge', 'name', self.gf('django.db.models.fields.CharField')(default=1, max_length=50), keep_default=False)
+
+ # Adding field 'Badge.slug'
+ db.add_column('forum_badge', 'slug', self.gf('django.db.models.fields.SlugField')(blank=True, default=1, max_length=50, db_index=True), keep_default=False)
+
+ # Adding field 'Badge.description'
+ db.add_column('forum_badge', 'description', self.gf('django.db.models.fields.CharField')(default=1, max_length=300), keep_default=False)
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'forum.action': {
+ 'Meta': {'object_name': 'Action'},
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})
+ },
+ 'forum.actionrepute': {
+ 'Meta': {'object_name': 'ActionRepute'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'forum.authkeyuserassociation': {
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})
+ },
+ 'forum.award': {
+ 'Meta': {'unique_together': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award'", 'unique': 'True', 'to': "orm['forum.Action']"}),
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Badge']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.badge': {
+ 'Meta': {'object_name': 'Badge'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),
+ 'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})
+ },
+ 'forum.flag': {
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ },
+ 'forum.keyvalue': {
+ 'Meta': {'object_name': 'KeyValue'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})
+ },
+ 'forum.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})
+ },
+ 'forum.node': {
+ 'Meta': {'object_name': 'Node'},
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})
+ },
+ 'forum.noderevision': {
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),
+ 'body': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'forum.openidassociation': {
+ 'Meta': {'object_name': 'OpenIdAssociation'},
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})
+ },
+ 'forum.openidnonce': {
+ 'Meta': {'object_name': 'OpenIdNonce'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'forum.questionsubscription': {
+ 'Meta': {'object_name': 'QuestionSubscription'},
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 3, 11, 46, 22, 80000)'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.subscriptionsettings': {
+ 'Meta': {'object_name': 'SubscriptionSettings'},
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})
+ },
+ 'forum.tag': {
+ 'Meta': {'object_name': 'Tag'},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'forum.user': {
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'forum.validationhash': {
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 4, 11, 46, 28, 428000)'}),
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})
+ },
+ 'forum.vote': {
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ }
+ }
+
+ complete_apps = ['forum']
diff --git a/forum/models/__init__.py b/forum/models/__init__.py
index 5b6414a..2c9c997 100644
--- a/forum/models/__init__.py
+++ b/forum/models/__init__.py
@@ -1,11 +1,11 @@
-from question import Question ,QuestionRevision, FavoriteQuestion, QuestionSubscription
+from question import Question ,QuestionRevision, QuestionSubscription
from answer import Answer, AnswerRevision
from tag import Tag, MarkedTag
-from meta import Vote, FlaggedItem
-from user import User, Activity, ValidationHash, AuthKeyUserAssociation, SubscriptionSettings
-from repute import Badge, Award, Repute
-from node import Node, NodeRevision, NodeMetaClass, AnonymousNode
+from user import User, ValidationHash, AuthKeyUserAssociation, SubscriptionSettings
+from node import Node, NodeRevision, NodeMetaClass
from comment import Comment
+from action import Action, ActionRepute
+from meta import Vote, Flag, Badge, Award
from utils import KeyValue
try:
@@ -16,20 +16,13 @@ except:
from base import *
-def is_new(sender, instance, **kwargs):
- try:
- instance._is_new = not bool(instance.id)
- except:
- pass
-
-pre_save.connect(is_new)
-
__all__ = [
- 'Node', 'NodeRevision', 'AnonymousNode',
- 'Question', 'FavoriteQuestion', 'QuestionSubscription', 'QuestionRevision',
+ 'Node', 'NodeRevision',
+ 'Question', 'QuestionSubscription', 'QuestionRevision',
'Answer', 'AnswerRevision',
- 'Tag', 'Comment', 'Vote', 'FlaggedItem', 'MarkedTag', 'Badge', 'Award', 'Repute',
- 'Activity', 'ValidationHash', 'AuthKeyUserAssociation', 'SubscriptionSettings', 'KeyValue', 'User',
+ 'Tag', 'Comment', 'MarkedTag', 'Badge', 'Award',
+ 'ValidationHash', 'AuthKeyUserAssociation', 'SubscriptionSettings', 'KeyValue', 'User',
+ 'Action', 'ActionRepute', 'Vote', 'Flag'
]
@@ -40,4 +33,5 @@ for k, v in get_modules_script_classes('models', models.Model).items():
__all__.append(k)
exec "%s = v" % k
-NodeMetaClass.setup_relations()
\ No newline at end of file
+NodeMetaClass.setup_relations()
+BaseMetaClass.setup_denormalizes()
\ No newline at end of file
diff --git a/forum/models/action.py b/forum/models/action.py
new file mode 100644
index 0000000..10eb165
--- /dev/null
+++ b/forum/models/action.py
@@ -0,0 +1,268 @@
+from django.utils.translation import ugettext as _
+from utils import PickledObjectField
+from threading import Thread
+from base import *
+import re
+
+class ActionManager(models.Manager):
+ use_for_related_fields = True
+
+ def get_query_set(self):
+ qs = super(ActionManager, self).get_query_set().filter(canceled=False)
+
+ if self.model is not Action:
+ return qs.filter(action_type=self.model.get_type())
+ else:
+ return qs
+
+ def get(self, *args, **kwargs):
+ action = super(ActionManager, self).get(*args, **kwargs)
+ if self.model == Action:
+ return action.leaf()
+ return action
+
+ def get_for_types(self, types, *args, **kwargs):
+ kwargs['action_type__in'] = [t.get_type() for t in types]
+ return self.get(*args, **kwargs)
+
+
+
+class Action(models.Model):
+ user = models.ForeignKey('User', related_name="actions")
+ ip = models.CharField(max_length=16)
+ node = models.ForeignKey('Node', null=True, related_name="actions")
+ action_type = models.CharField(max_length=16)
+ action_date = models.DateTimeField(default=datetime.datetime.now)
+
+ extra = PickledObjectField()
+
+ canceled = models.BooleanField(default=False)
+ canceled_by = models.ForeignKey('User', null=True, related_name="canceled_actions")
+ canceled_at = models.DateTimeField(null=True)
+ canceled_ip = models.CharField(max_length=16)
+
+ hooks = {}
+
+ objects = ActionManager()
+
+ @property
+ def at(self):
+ return self.action_date
+
+ @property
+ def by(self):
+ return self.user
+
+ def repute_users(self):
+ pass
+
+ def process_data(self, **data):
+ pass
+
+ def process_action(self):
+ pass
+
+ def cancel_action(self):
+ pass
+
+ def describe(self, viewer=None):
+ return ""
+
+ def repute(self, user, value):
+ repute = ActionRepute(action=self, user=user, value=value)
+ repute.save()
+ return repute
+
+ def cancel_reputes(self):
+ for repute in self.reputes.all():
+ cancel = ActionRepute(action=self, user=repute.user, value=(-repute.value), by_canceled=True)
+ cancel.save()
+
+ def leaf(self):
+ leaf_cls = ActionProxyMetaClass.types.get(self.action_type, None)
+
+ if leaf_cls is None:
+ return self
+
+ leaf = leaf_cls()
+ leaf.__dict__ = self.__dict__
+ return leaf
+
+ @classmethod
+ def get_type(cls):
+ return re.sub(r'action$', '', cls.__name__.lower())
+
+ def save(self, data=None, *args, **kwargs):
+ isnew = False
+
+ if not self.id:
+ self.action_type = self.__class__.get_type()
+ isnew = True
+
+ if data:
+ self.process_data(**data)
+
+ super(Action, self).save(*args, **kwargs)
+
+ if isnew:
+ if (self.node is None) or (not self.node.wiki):
+ self.repute_users()
+ self.process_action()
+ self.trigger_hooks(True)
+
+ return self
+
+ def delete(self):
+ self.cancel_action()
+ super(Action, self).delete()
+
+ def cancel(self, user=None, ip=None):
+ if not self.canceled:
+ self.canceled = True
+ self.canceled_at = datetime.datetime.now()
+ self.canceled_by = (user is None) and self.user or user
+ if ip:
+ self.canceled_ip = ip
+ self.save()
+ self.cancel_reputes()
+ self.cancel_action()
+ #self.trigger_hooks(False)
+
+ @classmethod
+ def get_current(cls, **kwargs):
+ kwargs['canceled'] = False
+
+ try:
+ return cls.objects.get(**kwargs)
+ except cls.MultipleObjectsReturned:
+ logging.error("Got multiple values for action %s with args %s", cls.__name__,
+ ", ".join(["%s='%s'" % i for i in kwargs.items()]))
+ raise
+ except cls.DoesNotExist:
+ return None
+
+ @classmethod
+ def hook(cls, fn):
+ if not Action.hooks.get(cls, None):
+ Action.hooks[cls] = []
+
+ Action.hooks[cls].append(fn)
+
+ def trigger_hooks(self, new=True):
+ thread = Thread(target=trigger_hooks_threaded, args=[self, Action.hooks, new])
+ thread.setDaemon(True)
+ thread.start()
+
+ class Meta:
+ app_label = 'forum'
+
+def trigger_hooks_threaded(action, hooks, new):
+ for cls, hooklist in hooks.items():
+ if isinstance(action, cls):
+ for hook in hooklist:
+ try:
+ hook(action=action, new=new)
+ except Exception, e:
+ logging.error("Error in %s hook: %s" % (cls.__name__, str(e)))
+
+class ActionProxyMetaClass(models.Model.__metaclass__):
+ types = {}
+
+ def __new__(cls, *args, **kwargs):
+ new_cls = super(ActionProxyMetaClass, cls).__new__(cls, *args, **kwargs)
+ cls.types[new_cls.get_type()] = new_cls
+
+ class Meta:
+ proxy = True
+
+ new_cls.Meta = Meta
+ return new_cls
+
+class ActionProxy(Action):
+ __metaclass__ = ActionProxyMetaClass
+
+ def friendly_username(self, viewer, user):
+ return (viewer == user) and _('You') or user.username
+
+ def friendly_ownername(self, owner, user):
+ return (owner == user) and _('your') or user.username
+
+ def hyperlink(self, url, title, **attrs):
+ return '%s ' % (url, " ".join('%s="%s"' % i for i in attrs.items()), title)
+
+ def describe_node(self, viewer, node):
+ node_link = self.hyperlink(node.get_absolute_url(), node.headline)
+
+ if node.parent:
+ node_desc = _("on %(link)s") % {'link': node_link}
+ else:
+ node_desc = node_link
+
+ return _("%(user)s %(node_name)s %(node_desc)s") % {
+ 'user': self.hyperlink(node.author.get_profile_url(), self.friendly_ownername(viewer, node.author)),
+ 'node_name': node.friendly_name, 'node_desc': node_desc,
+ }
+
+ class Meta:
+ proxy = True
+
+class DummyActionProxy(Action):
+ __metaclass__ = ActionProxyMetaClass
+
+ hooks = []
+
+ def process_data(self, **data):
+ pass
+
+ def process_action(self):
+ pass
+
+ def save(self, data=None):
+ self.process_action()
+
+ if data:
+ self.process_data(**data)
+
+ for hook in self.__class__.hooks:
+ hook(self, True)
+
+ @classmethod
+ def get_type(cls):
+ return re.sub(r'action$', '', cls.__name__.lower())
+
+ @classmethod
+ def hook(cls, fn):
+ cls.hooks.append(fn)
+
+
+
+class ActionRepute(models.Model):
+ action = models.ForeignKey(Action, related_name='reputes')
+ date = models.DateTimeField(default=datetime.datetime.now)
+ user = models.ForeignKey('User', related_name='reputes')
+ value = models.IntegerField(default=0)
+ by_canceled = models.BooleanField(default=False)
+
+ @property
+ def positive(self):
+ if self.value > 0: return self.value
+ return 0
+
+ @property
+ def negative(self):
+ if self.value < 0: return self.value
+ return 0
+
+ def save(self, *args, **kwargs):
+ super(ActionRepute, self).save(*args, **kwargs)
+ self.user.reputation = models.F('reputation') + self.value
+ self.user.save()
+
+ def delete(self):
+ self.user.reputation = models.F('reputation') - self.value
+ self.user.save()
+ super(ActionRepute, self).delete()
+
+ class Meta:
+ app_label = 'forum'
+
diff --git a/forum/models/answer.py b/forum/models/answer.py
index 01e0aae..090e19d 100644
--- a/forum/models/answer.py
+++ b/forum/models/answer.py
@@ -1,79 +1,23 @@
from base import *
+from django.utils.translation import ugettext as _
-from question import Question
+class Answer(Node):
+ friendly_name = _("answer")
-class Answer(QandA):
- accepted = models.BooleanField(default=False)
- accepted_at = models.DateTimeField(null=True, blank=True)
- accepted_by = models.ForeignKey(User, null=True)
+ class Meta(Node.Meta):
+ proxy = True
- class Meta(QandA.Meta):
- db_table = u'answer'
+ @property
+ def accepted(self):
+ return self.extra_action
@property
def headline(self):
return self.question.headline
- def mark_accepted(self, user):
- if not self.accepted and not self.question.answer_accepted:
- self.accepted = True
- self.accepted_at = datetime.datetime.now()
- self.accepted_by = user
- self.save()
- self.question.accepted_answer = self
- self.question.save()
- answer_accepted.send(sender=Answer, answer=self, user=user)
- return True
-
- return False
-
- def unmark_accepted(self, user):
- if self.accepted:
- self.accepted = False
- self.save()
- self.question.accepted_answer = None
- self.question.save()
- answer_accepted_canceled.send(sender=Answer, answer=self, user=user)
- return True
-
- return False
-
- def _update_question_answer_count(self, diff):
- self.question.answer_count = self.question.answer_count + diff
- self.question.save()
-
- def activate_revision(self, user, revision):
- super(Answer, self).activate_revision(user, revision)
- self.question.update_last_activity(user)
-
- def mark_deleted(self, user):
- if super(Answer, self).mark_deleted(user):
- self._update_question_answer_count(-1)
-
- def unmark_deleted(self):
- if super(Answer, self).unmark_deleted():
- self._update_question_answer_count(1)
-
- def get_latest_revision(self):
- return self.revisions.all()[0]
-
- def get_question_title(self):
- return self.question.title
-
def get_absolute_url(self):
return '%s#%s' % (self.question.get_absolute_url(), self.id)
- def save(self, *args, **kwargs):
- super(Answer, self).save(*args, **kwargs)
-
- if self._is_new:
- self._update_question_answer_count(1)
-
- def __unicode__(self):
- return self.html
-
-answer_accepted = django.dispatch.Signal(providing_args=['answer', 'user'])
-answer_accepted_canceled = django.dispatch.Signal(providing_args=['answer', 'user'])
class AnswerRevision(NodeRevision):
class Meta:
diff --git a/forum/models/base.py b/forum/models/base.py
index 43668d9..56124a8 100644
--- a/forum/models/base.py
+++ b/forum/models/base.py
@@ -20,15 +20,43 @@ import logging
from forum.const import *
+class LazyQueryList(object):
+ def __init__(self, model, items):
+ self.model = model
+ self.items = items
+
+ def __getitem__(self, k):
+ return self.model.objects.get(id=self.items[k])
+
+ def __iter__(self):
+ for id in self.items:
+ yield self.model.objects.get(id=id)
+
+ def __len__(self):
+ return len(self.items)
+
+class CachedQuerySet(models.query.QuerySet):
+ def lazy(self):
+ if len(self.query.extra) == 0:
+ return LazyQueryList(self.model, list(self.values_list('id', flat=True)))
+ else:
+ return self
+
+from action import Action
+
class CachedManager(models.Manager):
use_for_related_fields = True
int_cache_re = re.compile('^_[\w_]+cache$')
+ def get_query_set(self):
+ return CachedQuerySet(self.model)
+
def cache_obj(self, obj):
int_cache_keys = [k for k in obj.__dict__.keys() if self.int_cache_re.match(k)]
-
+ d = obj.__dict__
for k in int_cache_keys:
- del obj.__dict__[k]
+ if not isinstance(obj.__dict__[k], Action):
+ del obj.__dict__[k]
cache.set(self.model.cache_key(obj.id), obj, 60 * 60)
@@ -59,19 +87,54 @@ class CachedManager(models.Manager):
except:
return super(CachedManager, self).get_or_create(*args, **kwargs)
-denorm_update = django.dispatch.Signal(providing_args=["instance", "field", "old", "new"])
-class DenormalizedField(models.IntegerField):
- __metaclass__ = models.SubfieldBase
+class DenormalizedField(object):
+ def __init__(self, manager, **kwargs):
+ self.manager = manager
+ self.filter = kwargs
+
+ def setup_class(self, cls, name):
+ dict_name = '_%s_cache_' % name
+
+ def getter(inst):
+ val = inst.__dict__.get(dict_name, None)
+
+ if val is None:
+ val = getattr(inst, self.manager).filter(**self.filter).count()
+ inst.__dict__[dict_name] = val
+ inst.__class__.objects.cache_obj(inst)
+
+ return val
+
+ def reset_cache(inst):
+ inst.__dict__.pop(dict_name, None)
+ inst.__class__.objects.cache_obj(inst)
+
+ cls.add_to_class(name, property(getter))
+ cls.add_to_class("reset_%s_cache" % name, reset_cache)
+
+
+class BaseMetaClass(models.Model.__metaclass__):
+ to_denormalize = []
+
+ def __new__(cls, *args, **kwargs):
+ new_cls = super(BaseMetaClass, cls).__new__(cls, *args, **kwargs)
- def contribute_to_class(self, cls, name):
- super (DenormalizedField, self).contribute_to_class(cls, name)
- if not hasattr(cls, '_denormalizad_fields'):
- cls._denormalizad_fields = []
+ BaseMetaClass.to_denormalize.extend(
+ [(new_cls, name, field) for name, field in new_cls.__dict__.items() if isinstance(field, DenormalizedField)]
+ )
+
+ return new_cls
+
+ @classmethod
+ def setup_denormalizes(cls):
+ for new_cls, name, field in BaseMetaClass.to_denormalize:
+ field.setup_class(new_cls, name)
- cls._denormalizad_fields.append(name)
class BaseModel(models.Model):
+ __metaclass__ = BaseMetaClass
+
objects = CachedManager()
class Meta:
@@ -92,35 +155,29 @@ class BaseModel(models.Model):
if self._original_state.get(k, missing) == missing or self._original_state[k] != v])
def save(self, *args, **kwargs):
- put_back = None
-
- if hasattr(self.__class__, '_denormalizad_fields'):
- dirty = self.get_dirty_fields()
- put_back = [f for f in self.__class__._denormalizad_fields if f in dirty]
-
- if put_back:
- for n in put_back:
- self.__dict__[n] = models.F(n) + (self.__dict__[n] - dirty[n])
-
- super(BaseModel, self).save(*args, **kwargs)
+ put_back = [k for k, v in self.__dict__.items() if isinstance(v, models.expressions.ExpressionNode)]
+ super(BaseModel, self).save()
if put_back:
try:
self.__dict__.update(
self.__class__.objects.filter(id=self.id).values(*put_back)[0]
)
- for f in put_back:
- denorm_update.send(sender=self.__class__, instance=self, field=f,
- old=self._original_state[f], new=self.__dict__[f])
except:
- #todo: log this properly
- pass
+ logging.error("Unable to read %s from %s" % (", ".join(put_back), self.__class__.__name__))
+ self.uncache()
self._original_state = dict(self.__dict__)
+ self.cache()
+
+ def cache(self):
self.__class__.objects.cache_obj(self)
- def delete(self):
+ def uncache(self):
cache.delete(self.cache_key(self.pk))
+
+ def delete(self):
+ self.uncache()
super(BaseModel, self).delete()
@@ -170,8 +227,6 @@ class UserContent(models.Model):
app_label = 'forum'
-marked_deleted = django.dispatch.Signal(providing_args=["instance", "deleted_by"])
-
class DeletableContent(models.Model):
deleted = models.BooleanField(default=False)
deleted_at = models.DateTimeField(null=True, blank=True)
@@ -189,7 +244,6 @@ class DeletableContent(models.Model):
self.deleted_at = datetime.datetime.now()
self.deleted_by = user
self.save()
- marked_deleted.send(sender=self.__class__, instance=self, deleted_by=user)
return True
else:
return False
@@ -223,19 +277,6 @@ class CancelableContent(models.Model):
from node import Node, NodeRevision
-class QandA(Node):
- wiki = models.BooleanField(default=False)
- wikified_at = models.DateTimeField(null=True, blank=True)
-
- class Meta:
- abstract = True
- app_label = 'forum'
-
- def wikify(self):
- if not self.wiki:
- self.wiki = True
- self.wikified_at = datetime.datetime.now()
- self.save()
diff --git a/forum/models/comment.py b/forum/models/comment.py
index a2e7425..a70d474 100644
--- a/forum/models/comment.py
+++ b/forum/models/comment.py
@@ -1,7 +1,10 @@
from base import *
+from django.utils.translation import ugettext as _
import re
class Comment(Node):
+ friendly_name = _("comment")
+
class Meta(Node.Meta):
ordering = ('-added_at',)
proxy = True
@@ -13,7 +16,10 @@ class Comment(Node):
@property
def comment(self):
- return self.body
+ if settings.FORM_ALLOW_MARKDOWN_IN_COMMENTS:
+ return self.as_markdown('limitedsyntax')
+ else:
+ return self.body
@property
def headline(self):
@@ -26,21 +32,16 @@ class Comment(Node):
def save(self, *args, **kwargs):
super(Comment,self).save(*args, **kwargs)
- if self._is_new:
- self._update_parent_comment_count(1)
-
- try:
- ping_google()
- except Exception:
- logging.debug('problem pinging google did you register your sitemap with google?')
+ if not self.id:
+ self.parent.reset_comment_count_cache()
def mark_deleted(self, user):
if super(Comment, self).mark_deleted(user):
- self._update_parent_comment_count(-1)
+ self.parent.reset_comment_count_cache()
def unmark_deleted(self):
if super(Comment, self).unmark_deleted():
- self._update_parent_comment_count(1)
+ self.parent.reset_comment_count_cache()
def is_reply_to(self, user):
inreply = re.search('@\w+', self.body)
diff --git a/forum/models/meta.py b/forum/models/meta.py
index 86a479c..1498935 100644
--- a/forum/models/meta.py
+++ b/forum/models/meta.py
@@ -1,75 +1,86 @@
-from base import *
-
-class Vote(MetaContent, CancelableContent, UserContent):
- VOTE_UP = +1
- VOTE_DOWN = -1
- VOTE_CHOICES = (
- (VOTE_UP, u'Up'),
- (VOTE_DOWN, u'Down'),
- )
-
- vote = models.SmallIntegerField(choices=VOTE_CHOICES)
- voted_at = models.DateTimeField(default=datetime.datetime.now)
-
- active = ActiveObjectManager()
-
- class Meta(MetaContent.Meta):
- db_table = u'vote'
-
- def __unicode__(self):
- return '[%s] voted at %s: %s' %(self.user, self.voted_at, self.vote)
-
- def _update_post_vote_count(self, diff):
- post = self.node.leaf
- field = self.vote == 1 and 'vote_up_count' or 'vote_down_count'
- post.__dict__[field] = post.__dict__[field] + diff
- post.save()
-
- def cancel(self):
- if super(Vote, self).cancel():
- self._update_post_vote_count(-1)
-
- def save(self, *args, **kwargs):
- super(Vote, self).save(*args, **kwargs)
- if self._is_new:
- self._update_post_vote_count(1)
-
- def is_upvote(self):
- return self.vote == self.VOTE_UP
-
- def is_downvote(self):
- return self.vote == self.VOTE_DOWN
-
-
-class FlaggedItem(MetaContent, UserContent):
- flagged_at = models.DateTimeField(default=datetime.datetime.now)
- reason = models.CharField(max_length=300, null=True)
- canceled = models.BooleanField(default=False)
-
- active = ActiveObjectManager()
-
- class Meta(MetaContent.Meta):
- db_table = u'flagged_item'
-
- def __unicode__(self):
- return '[%s] flagged at %s' %(self.user, self.flagged_at)
-
- def _update_post_flag_count(self, diff):
- post = self.node
- post.offensive_flag_count = post.offensive_flag_count + diff
- post.save()
-
- def save(self, *args, **kwargs):
- super(FlaggedItem, self).save(*args, **kwargs)
- if self._is_new:
- self._update_post_flag_count(1)
-
- def cancel(self):
- if not self.canceled:
- self.canceled = True
- self.save()
- self._update_post_flag_count(-1)
-
-
-
-
+from django.utils.translation import ugettext as _
+from base import *
+
+class Vote(models.Model):
+ user = models.ForeignKey(User, related_name="votes")
+ node = models.ForeignKey(Node, related_name="votes")
+ value = models.SmallIntegerField()
+ action = models.ForeignKey(Action, unique=True, related_name="vote")
+ voted_at = models.DateTimeField(default=datetime.datetime.now)
+
+ class Meta:
+ app_label = 'forum'
+ unique_together = ('user', 'node')
+
+
+class Flag(models.Model):
+ user = models.ForeignKey(User, related_name="flags")
+ node = models.ForeignKey(Node, related_name="flags")
+ reason = models.CharField(max_length=300)
+ action = models.ForeignKey(Action, unique=True, related_name="flag")
+ flagged_at = models.DateTimeField(default=datetime.datetime.now)
+
+ class Meta:
+ app_label = 'forum'
+ unique_together = ('user', 'node')
+
+class BadgeManager(models.Manager):
+ use_for_related_fields = True
+
+ def get(self, *args, **kwargs):
+ try:
+ pk = [v for (k,v) in kwargs.items() if k in ('pk', 'pk__exact', 'id', 'id__exact')][0]
+ except:
+ return super(BadgeManager, self).get(*args, **kwargs)
+
+ from forum.badges.base import BadgesMeta
+ badge = BadgesMeta.by_id.get(pk, None)
+ if not badge:
+ return super(BadgeManager, self).get(*args, **kwargs)
+ return badge.ondb
+
+class Badge(models.Model):
+ GOLD = 1
+ SILVER = 2
+ BRONZE = 3
+
+ type = models.SmallIntegerField()
+ cls = models.CharField(max_length=50, null=True)
+ awarded_count = models.PositiveIntegerField(default=0)
+
+ awarded_to = models.ManyToManyField(User, through='Award', related_name='badges')
+
+ objects = BadgeManager()
+
+ @property
+ def name(self):
+ cls = self.__dict__.get('_class', None)
+ return cls and cls.name or _("Unknown")
+
+ @property
+ def description(self):
+ cls = self.__dict__.get('_class', None)
+ return cls and cls.description or _("No description available")
+
+ @models.permalink
+ def get_absolute_url(self):
+ return ('badge', [], {'id': self.id, 'slug': slugify(self.name)})
+
+ class Meta:
+ app_label = 'forum'
+
+
+class Award(models.Model):
+ user = models.ForeignKey(User)
+ badge = models.ForeignKey('Badge', related_name="awards")
+ node = models.ForeignKey(Node, null=True)
+
+ awarded_at = models.DateTimeField(default=datetime.datetime.now)
+
+ trigger = models.ForeignKey(Action, related_name="awards", null=True)
+ action = models.ForeignKey(Action, related_name="award", unique=True)
+
+
+ class Meta:
+ unique_together = ('user', 'badge', 'node')
+ app_label = 'forum'
\ No newline at end of file
diff --git a/forum/models/node.py b/forum/models/node.py
index a92dee9..a7e122e 100644
--- a/forum/models/node.py
+++ b/forum/models/node.py
@@ -1,8 +1,9 @@
-from akismet import *
+from forum.akismet import *
from base import *
from tag import Tag
import markdown
+from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
from django.utils.html import strip_tags
from forum.utils.html import sanitize_html
@@ -19,7 +20,10 @@ class NodeContent(models.Model):
@property
def html(self):
- return mark_safe(sanitize_html(markdown.markdown(self.body)))
+ return self.as_markdown()
+
+ def as_markdown(self, *extensions):
+ return mark_safe(sanitize_html(markdown.markdown(self.body, extensions=extensions)))
@property
def headline(self):
@@ -38,14 +42,14 @@ class NodeContent(models.Model):
abstract = True
app_label = 'forum'
-class NodeMetaClass(models.Model.__metaclass__):
+class NodeMetaClass(BaseMetaClass):
types = {}
def __new__(cls, *args, **kwargs):
new_cls = super(NodeMetaClass, cls).__new__(cls, *args, **kwargs)
if not new_cls._meta.abstract and new_cls.__name__ is not 'Node':
- NodeMetaClass.types[new_cls.__name__.lower()] = new_cls
+ NodeMetaClass.types[new_cls.get_type()] = new_cls
return new_cls
@@ -59,10 +63,7 @@ class NodeMetaClass(models.Model.__metaclass__):
name = node_cls.__name__.lower()
def children(self):
- if node_cls._meta.proxy:
- return node_cls.objects.filter(node_type=name, parent=self)
- else:
- return node_cls.objects.filter(parent=self)
+ return node_cls.objects.filter(parent=self)
def parent(self):
p = self.__dict__.get('_%s_cache' % name, None)
@@ -77,35 +78,82 @@ class NodeMetaClass(models.Model.__metaclass__):
Node.add_to_class(name, property(parent))
-node_create = django.dispatch.Signal(providing_args=['instance'])
-node_edit = django.dispatch.Signal(providing_args=['instance'])
+class NodeManager(CachedManager):
+ use_for_related_fields = True
-class Node(BaseModel, NodeContent, DeletableContent):
- __metaclass__ = NodeMetaClass
+ def get_query_set(self):
+ qs = super(NodeManager, self).get_query_set()
+
+ if self.model is not Node:
+ return qs.filter(node_type=self.model.get_type())
+ else:
+ return qs
+
+ def get(self, *args, **kwargs):
+ node = super(NodeManager, self).get(*args, **kwargs)
+ cls = NodeMetaClass.types.get(node.node_type, None)
+
+ if cls and node.__class__ is not cls:
+ return node.leaf
+ return node
+
+ def get_for_types(self, types, *args, **kwargs):
+ kwargs['node_type__in'] = [t.get_type() for t in types]
+ return self.get(*args, **kwargs)
- node_type = models.CharField(max_length=16, default='node')
- parent = models.ForeignKey('Node', related_name='children', null=True)
- abs_parent = models.ForeignKey('Node', related_name='all_children', null=True)
- added_at = models.DateTimeField(default=datetime.datetime.now)
+class Node(BaseModel, NodeContent):
+ __metaclass__ = NodeMetaClass
- tags = models.ManyToManyField('Tag', related_name='%(class)ss')
+ node_type = models.CharField(max_length=16, default='node')
+ parent = models.ForeignKey('Node', related_name='children', null=True)
+ abs_parent = models.ForeignKey('Node', related_name='all_children', null=True)
- score = DenormalizedField(default=0)
- vote_up_count = DenormalizedField(default=0)
- vote_down_count = models.IntegerField(default=0)
+ added_at = models.DateTimeField(default=datetime.datetime.now)
+ score = models.IntegerField(default=0)
- comment_count = DenormalizedField(default=0)
- offensive_flag_count = DenormalizedField(default=0)
+ deleted = models.ForeignKey('Action', null=True, unique=True, related_name="deleted_node")
+ in_moderation = models.ForeignKey('Action', null=True, unique=True, related_name="moderated_node")
+ last_edited = models.ForeignKey('Action', null=True, unique=True, related_name="edited_node")
- last_edited_at = models.DateTimeField(null=True, blank=True)
- last_edited_by = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_%(class)ss')
+ last_activity_by = models.ForeignKey(User, null=True)
+ last_activity_at = models.DateTimeField(null=True, blank=True)
+ tags = models.ManyToManyField('Tag', related_name='%(class)ss')
active_revision = models.OneToOneField('NodeRevision', related_name='active', null=True)
+ extra_ref = models.ForeignKey('Node', null=True)
+ extra_count = models.IntegerField(default=0)
+ extra_action = models.ForeignKey('Action', null=True, related_name="extra_node")
+
+ marked = models.BooleanField(default=False)
+ wiki = models.BooleanField(default=False)
+
+ comment_count = DenormalizedField("children", node_type="comment", canceled=False)
+ flag_count = DenormalizedField("flags")
+
+ friendly_name = _("post")
+
+ objects = NodeManager()
+
+ @classmethod
+ def cache_key(cls, pk):
+ return '%s.node:%s' % (settings.APP_URL, pk)
+
+ @classmethod
+ def get_type(cls):
+ return cls.__name__.lower()
+
@property
def leaf(self):
- return NodeMetaClass.types[self.node_type].objects.get(id=self.id)
+ leaf_cls = NodeMetaClass.types.get(self.node_type, None)
+
+ if leaf_cls is None:
+ return self
+
+ leaf = leaf_cls()
+ leaf.__dict__ = self.__dict__
+ return leaf
@property
def absolute_parent(self):
@@ -118,40 +166,40 @@ class Node(BaseModel, NodeContent, DeletableContent):
def summary(self):
return strip_tags(self.html)[:300]
- def create_revision(self, user, **kwargs):
- revision = NodeRevision(author=user, **kwargs)
-
- if not self.id:
- self.author = user
- self.save()
- revision.revision = 1
- else:
- revision.revision = self.revisions.aggregate(last=models.Max('revision'))['last'] + 1
+ def update_last_activity(self, user):
+ self.last_activity_by = user
+ self.last_activity_at = datetime.datetime.now()
- revision.node_id = self.id
+ if self.parent:
+ self.parent.update_last_activity(user)
+
+ def _create_revision(self, user, number, **kwargs):
+ revision = NodeRevision(author=user, revision=number, node=self, **kwargs)
revision.save()
- self.activate_revision(user, revision)
+ return revision
+
+ def create_revision(self, user, action=None, **kwargs):
+ number = self.revisions.aggregate(last=models.Max('revision'))['last'] + 1
+ revision = self._create_revision(user, number, **kwargs)
+ self.activate_revision(user, revision, action)
+ return revision
- def activate_revision(self, user, revision):
+ def activate_revision(self, user, revision, action=None):
self.title = revision.title
self.tagnames = revision.tagnames
self.body = revision.body
- old_revision = self.active_revision
self.active_revision = revision
+ self.update_last_activity(user)
- if not old_revision:
- signal = node_create
- else:
- self.last_edited_at = datetime.datetime.now()
- self.last_edited_by = user
- signal = node_edit
+ if action:
+ self.last_edited = action
self.save()
- signal.send(sender=self.__class__, instance=self)
def get_tag_list_if_changed(self):
dirty = self.get_dirty_fields()
+ active_user = self.last_edited and self.last_edited.by or self.author
if 'tagnames' in dirty:
new_tags = self.tagname_list()
@@ -168,7 +216,7 @@ class Node(BaseModel, NodeContent, DeletableContent):
try:
tag = Tag.objects.get(name=name)
except:
- tag = Tag.objects.create(name=name, created_by=self.last_edited_by or self.author)
+ tag = Tag.objects.create(name=name, created_by=active_user or self.author)
tag_list.append(tag)
@@ -182,7 +230,7 @@ class Node(BaseModel, NodeContent, DeletableContent):
tag = Tag.objects.get(name=name)
tag.used_count = tag.used_count - 1
if tag.used_count == 0:
- tag.mark_deleted(self.last_edited_by or self.author)
+ tag.mark_deleted(active_user)
tag.save()
return tag_list
@@ -191,13 +239,14 @@ class Node(BaseModel, NodeContent, DeletableContent):
def save(self, *args, **kwargs):
if not self.id:
- self.node_type = self.__class__.__name__.lower()
+ self.node_type = self.get_type()
+ super(BaseModel, self).save(*args, **kwargs)
+ self.active_revision = self._create_revision(self.author, 1, title=self.title, tagnames=self.tagnames, body=self.body)
+ self.update_last_activity(self.author)
if self.parent_id and not self.abs_parent_id:
self.abs_parent = self.parent.absolute_parent
-
- self.__dict__['score'] = self.__dict__['vote_up_count'] - self.__dict__['vote_down_count']
-
+
tags = self.get_tag_list_if_changed()
super(Node, self).save(*args, **kwargs)
if tags is not None: self.tags = tags
@@ -205,8 +254,9 @@ class Node(BaseModel, NodeContent, DeletableContent):
@staticmethod
def isSpam(comment, data):
api = Akismet()
- if api.key is None:
- print "problem" # raise APIKeyError
+
+ if not api.key:
+ return False
else:
if api.comment_check(comment, data):
return True
@@ -229,11 +279,3 @@ class NodeRevision(BaseModel, NodeContent):
app_label = 'forum'
-from user import ValidationHash
-
-class AnonymousNode(Node):
- validation_hash = models.ForeignKey(Node, related_name='anonymous_content')
- convertible_to = models.CharField(max_length=16, default='node')
-
- class Meta:
- app_label = 'forum'
\ No newline at end of file
diff --git a/forum/models/question.py b/forum/models/question.py
index da8083f..5484016 100644
--- a/forum/models/question.py
+++ b/forum/models/question.py
@@ -4,29 +4,26 @@ from django.utils.translation import ugettext as _
question_view = django.dispatch.Signal(providing_args=['instance', 'user'])
-class Question(QandA):
- accepted_answer = models.OneToOneField('Answer', null=True, related_name="question_accepting")
- closed = models.BooleanField(default=False)
- closed_by = models.ForeignKey(User, null=True, blank=True, related_name='closed_questions')
- closed_at = models.DateTimeField(null=True, blank=True)
- close_reason = models.SmallIntegerField(choices=CLOSE_REASONS, null=True, blank=True)
- subscribers = models.ManyToManyField(User, related_name='subscriptions', through='QuestionSubscription')
-
- # Denormalised data
- answer_count = models.PositiveIntegerField(default=0)
- view_count = models.IntegerField(default=0)
- favourite_count = models.IntegerField(default=0)
- last_activity_at = models.DateTimeField(default=datetime.datetime.now)
- last_activity_by = models.ForeignKey(User, related_name='last_active_in_questions', null=True)
-
- favorited_by = models.ManyToManyField(User, through='FavoriteQuestion', related_name='favorite_questions')
-
- class Meta(QandA.Meta):
- db_table = u'question'
+class Question(Node):
+ class Meta(Node.Meta):
+ proxy = True
+
+ answer_count = DenormalizedField("children", node_type="answer", deleted=None)
+ favorite_count = DenormalizedField("actions", action_type="favorite", canceled=False)
+
+ friendly_name = _("question")
+
+ @property
+ def closed(self):
+ return self.extra_action
+
+ @property
+ def view_count(self):
+ return self.extra_count
@property
def headline(self):
- if self.closed:
+ if self.marked:
return _('[closed] ') + self.title
if self.deleted:
@@ -36,43 +33,16 @@ class Question(QandA):
@property
def answer_accepted(self):
- return self.accepted_answer is not None
+ return self.extra_ref is not None
- def save(self, *args, **kwargs):
- if not self.last_activity_by:
- self.last_activity_by = self.author
- super(Question, self).save(*args, **kwargs)
-
- def update_last_activity(self, user):
- self.last_activity_by = user
- self.last_activity_at = datetime.datetime.now()
- self.save()
-
- def activate_revision(self, user, revision):
- super(Question, self).activate_revision(user, revision)
- self.update_last_activity(user)
+ @property
+ def accepted_answer(self):
+ return self.extra_ref
@models.permalink
def get_absolute_url(self):
return ('question', (), {'id': self.id, 'slug': django_urlquote(slugify(self.title))})
- def get_answer_count_by_user(self, user_id):
- from answer import Answer
- query_set = Answer.objects.filter(author__id=user_id)
- return query_set.filter(question=self).count()
-
- def get_question_title(self):
- if self.closed:
- attr = CONST['closed']
- elif self.deleted:
- attr = CONST['deleted']
- else:
- attr = None
- if attr is not None:
- return u'%s %s' % (self.title, attr)
- else:
- return self.title
-
def get_revision_url(self):
return reverse('question_revisions', args=[self.id])
@@ -82,49 +52,22 @@ class Question(QandA):
if related_list is None:
related_list = Question.objects.values('id').filter(tags__id__in=[t.id for t in self.tags.all()]
- ).exclude(id=self.id).exclude(deleted=True).annotate(frequency=models.Count('id')).order_by('-frequency')[:count]
+ ).exclude(id=self.id).filter(deleted=None).annotate(frequency=models.Count('id')).order_by('-frequency')[:count]
cache.set(cache_key, related_list, 60 * 60)
return [Question.objects.get(id=r['id']) for r in related_list]
- def __unicode__(self):
- return self.title
def question_viewed(instance, **kwargs):
- instance.view_count += 1
+ instance.extra_count += 1
instance.save()
question_view.connect(question_viewed)
-class FavoriteQuestion(models.Model):
- question = models.ForeignKey('Question')
- user = models.ForeignKey(User, related_name='user_favorite_questions')
- added_at = models.DateTimeField(default=datetime.datetime.now)
-
- class Meta:
- unique_together = ('question', 'user')
- app_label = 'forum'
- db_table = u'favorite_question'
-
- def __unicode__(self):
- return '[%s] favorited at %s' %(self.user, self.added_at)
-
- def _update_question_fav_count(self, diff):
- self.question.favourite_count = self.question.favourite_count + diff
- self.question.save()
-
- def save(self, *args, **kwargs):
- super(FavoriteQuestion, self).save(*args, **kwargs)
- if self._is_new:
- self._update_question_fav_count(1)
-
- def delete(self):
- self._update_question_fav_count(-1)
- super(FavoriteQuestion, self).delete()
class QuestionSubscription(models.Model):
user = models.ForeignKey(User)
- question = models.ForeignKey(Question)
+ question = models.ForeignKey(Node)
auto_subscription = models.BooleanField(default=True)
last_view = models.DateTimeField(default=datetime.datetime.now())
diff --git a/forum/models/repute.py b/forum/models/repute.py
deleted file mode 100644
index 0c54c1b..0000000
--- a/forum/models/repute.py
+++ /dev/null
@@ -1,127 +0,0 @@
-from base import *
-from django.contrib.contenttypes.models import ContentType
-from forum.models import User
-
-from django.utils.translation import ugettext as _
-
-class Badge(BaseModel):
- """Awarded for notable actions performed on the site by Users."""
- GOLD = 1
- SILVER = 2
- BRONZE = 3
- TYPE_CHOICES = (
- (GOLD, _('gold')),
- (SILVER, _('silver')),
- (BRONZE, _('bronze')),
- )
-
- name = models.CharField(max_length=50)
- type = models.SmallIntegerField(choices=TYPE_CHOICES)
- slug = models.SlugField(max_length=50, blank=True)
- description = models.CharField(max_length=300)
- multiple = models.BooleanField(default=False)
- # Denormalised data
- awarded_count = models.PositiveIntegerField(default=0)
- awarded_to = models.ManyToManyField(User, through='Award', related_name='badges')
-
- class Meta:
- app_label = 'forum'
- db_table = u'badge'
- ordering = ('name',)
- unique_together = ('name', 'type')
-
- def __unicode__(self):
- return u'%s: %s' % (self.get_type_display(), self.name)
-
- def save(self, *args, **kwargs):
- if not self.slug:
- self.slug = self.name#slugify(self.name)
- super(Badge, self).save(*args, **kwargs)
-
- def get_absolute_url(self):
- return '%s%s/' % (reverse('badge', args=[self.id]), self.slug)
-
-
-class AwardManager(models.Manager):
- def get_recent_awards(self):
- awards = super(AwardManager, self).extra(
- select={'badge_id': 'badge.id', 'badge_name':'badge.name',
- 'badge_description': 'badge.description', 'badge_type': 'badge.type',
- 'user_id': 'auth_user.id', 'user_name': 'auth_user.username'
- },
- tables=['award', 'badge', 'auth_user'],
- order_by=['-awarded_at'],
- where=['auth_user.id=award.user_id AND badge_id=badge.id'],
- ).values('badge_id', 'badge_name', 'badge_description', 'badge_type', 'user_id', 'user_name')
- return awards
-
-class Award(GenericContent, UserContent):
- """The awarding of a Badge to a User."""
- badge = models.ForeignKey('Badge', related_name='award_badge')
- awarded_at = models.DateTimeField(default=datetime.datetime.now)
- notified = models.BooleanField(default=False)
-
- objects = AwardManager()
-
- def __unicode__(self):
- return u'[%s] is awarded a badge [%s] at %s' % (self.user.username, self.badge.name, self.awarded_at)
-
- def save(self, *args, **kwargs):
- super(Award, self).save(*args, **kwargs)
-
- if self._is_new:
- self.badge.awarded_count += 1
- self.badge.save()
-
- if self.badge.type == Badge.GOLD:
- self.user.gold += 1
- if self.badge.type == Badge.SILVER:
- self.user.silver += 1
- if self.badge.type == Badge.BRONZE:
- self.user.bronze += 1
- self.user.save()
-
- class Meta:
- #unique_together = ('content_type', 'object_id', 'user', 'badge')
- app_label = 'forum'
- db_table = u'award'
-
-
-class Repute(MetaContent, CancelableContent, UserContent):
- value = models.SmallIntegerField(default=0)
- question = models.ForeignKey('Question')
- reputed_at = models.DateTimeField(default=datetime.datetime.now)
- reputation_type = models.SmallIntegerField(choices=TYPE_REPUTATION)
- user_previous_rep = models.IntegerField(default=0)
-
- def __unicode__(self):
- return u'[%s]\' reputation changed at %s' % (self.user.username, self.reputed_at)
-
- @property
- def positive(self):
- if self.value > 0: return self.value
- return 0
-
- @property
- def negative(self):
- if self.value < 0: return self.value
- return 0
-
- @property
- def reputation(self):
- return self.user_previous_rep + self.value
-
- def cancel(self):
- if super(Repute, self).cancel():
- self.user.reputation = self.user.reputation - self.value
- self.user.save()
-
- def save(self, *args, **kwargs):
- self.user_previous_rep = self.user.reputation
- self.user.reputation = self.user.reputation + self.value
- self.user.save()
- super(Repute, self).save(*args, **kwargs)
-
- class Meta:
- app_label = 'forum'
- db_table = u'repute'
diff --git a/forum/models/tag.py b/forum/models/tag.py
index 50eb5aa..16f1c6c 100644
--- a/forum/models/tag.py
+++ b/forum/models/tag.py
@@ -18,7 +18,6 @@ class Tag(BaseModel, DeletableContent):
active = ActiveTagManager()
class Meta(DeletableContent.Meta):
- db_table = u'tag'
ordering = ('-used_count', 'name')
def __unicode__(self):
diff --git a/forum/models/user.py b/forum/models/user.py
index abb3989..53b5ee2 100644
--- a/forum/models/user.py
+++ b/forum/models/user.py
@@ -6,7 +6,8 @@ from django.db.models import Q
try:
from hashlib import md5
except:
- import md5
+ from md5 import new as md5
+
import string
from random import Random
@@ -26,7 +27,7 @@ class UserManager(CachedManager):
class AnonymousUser(DjangoAnonymousUser):
def get_visible_answers(self, question):
- return question.answers.filter(deleted=False)
+ return question.answers.filter(deleted=None)
def can_view_deleted_post(self, post):
return False
@@ -76,18 +77,19 @@ class AnonymousUser(DjangoAnonymousUser):
def can_upload_files(self):
return False
+def true_if_is_super_or_staff(fn):
+ def decorated(self, *args, **kwargs):
+ return self.is_superuser or self.is_staff or fn(self, *args, **kwargs)
+ return decorated
+
class User(BaseModel, DjangoUser):
is_approved = models.BooleanField(default=False)
email_isvalid = models.BooleanField(default=False)
- email_key = models.CharField(max_length=32, null=True)
- reputation = DenormalizedField(default=1)
- gold = DenormalizedField(default=0)
- silver = DenormalizedField(default=0)
- bronze = DenormalizedField(default=0)
-
- questions_per_page = models.SmallIntegerField(choices=QUESTIONS_PER_PAGE_CHOICES, default=10)
- hide_ignored_questions = models.BooleanField(default=False)
+ reputation = models.PositiveIntegerField(default=0)
+ gold = models.PositiveIntegerField(default=0)
+ silver = models.PositiveIntegerField(default=0)
+ bronze = models.PositiveIntegerField(default=0)
last_seen = models.DateTimeField(default=datetime.datetime.now)
real_name = models.CharField(max_length=100, blank=True)
@@ -95,7 +97,12 @@ class User(BaseModel, DjangoUser):
location = models.CharField(max_length=100, blank=True)
date_of_birth = models.DateField(null=True, blank=True)
about = models.TextField(blank=True)
-
+
+ subscriptions = models.ManyToManyField('Node', related_name='subscribers', through='QuestionSubscription')
+
+ vote_up_count = DenormalizedField("actions", canceled=False, action_type="voteup")
+ vote_down_count = DenormalizedField("actions", canceled=False, action_type="votedown")
+
objects = UserManager()
@property
@@ -104,10 +111,16 @@ class User(BaseModel, DjangoUser):
def save(self, *args, **kwargs):
if self.reputation < 0:
- self.reputation = 1
+ self.reputation = 0
+
+ new = not bool(self.id)
super(User, self).save(*args, **kwargs)
+ if new:
+ sub_settings = SubscriptionSettings(user=self)
+ sub_settings.save()
+
def get_absolute_url(self):
return self.get_profile_url()
@@ -127,15 +140,13 @@ class User(BaseModel, DjangoUser):
profile_link = u'%s ' % (self.get_profile_url(),self.username)
return mark_safe(profile_link)
+ def get_visible_answers(self, question):
+ return question.answers.filter(deleted=None, in_moderation=None)
+
def get_vote_count_today(self):
today = datetime.date.today()
- return self.votes.filter(voted_at__range=(today - datetime.timedelta(days=1), today)).count()
-
- def get_up_vote_count(self):
- return self.votes.filter(vote=1).count()
-
- def get_down_vote_count(self):
- return self.votes.filter(vote=-1).count()
+ return self.actions.filter(canceled=False, action_type__in=("voteup", "votedown"),
+ action_date__range=(today - datetime.timedelta(days=1), today)).count()
def get_reputation_by_upvoted_today(self):
today = datetime.datetime.now()
@@ -149,130 +160,87 @@ class User(BaseModel, DjangoUser):
def get_flagged_items_count_today(self):
today = datetime.date.today()
- return self.flaggeditems.filter(flagged_at__range=(today - datetime.timedelta(days=1), today)).count()
-
- def get_visible_answers(self, question):
- if self.is_superuser:
- return question.answers
- else:
- return question.answers.filter(models.Q(deleted=False) | models.Q(deleted_by=self))
+ return self.actions.filter(canceled=False, action_type="flag",
+ action_date__range=(today - datetime.timedelta(days=1), today)).count()
+ @true_if_is_super_or_staff
def can_view_deleted_post(self, post):
- return self.is_superuser or post.author == self
+ return post.author == self
+ @true_if_is_super_or_staff
def can_vote_up(self):
- return self.reputation >= int(settings.REP_TO_VOTE_UP) or self.is_superuser
+ return self.reputation >= int(settings.REP_TO_VOTE_UP)
+ @true_if_is_super_or_staff
def can_vote_down(self):
- return self.reputation >= int(settings.REP_TO_VOTE_DOWN) or self.is_superuser
+ return self.reputation >= int(settings.REP_TO_VOTE_DOWN)
def can_flag_offensive(self, post=None):
if post is not None and post.author == self:
return False
- return self.is_superuser or self.reputation >= int(settings.REP_TO_FLAG)
+ return self.is_superuser or self.is_staff or self.reputation >= int(settings.REP_TO_FLAG)
+ @true_if_is_super_or_staff
def can_view_offensive_flags(self, post=None):
if post is not None and post.author == self:
return True
- return self.is_superuser or self.reputation >= int(settings.REP_TO_VIEW_FLAGS)
+ return self.reputation >= int(settings.REP_TO_VIEW_FLAGS)
+ @true_if_is_super_or_staff
def can_comment(self, post):
return self == post.author or self.reputation >= int(settings.REP_TO_COMMENT
- ) or self.is_superuser or (post.__class__.__name__ == "Answer" and self == post.question.author)
+ ) or (post.__class__.__name__ == "Answer" and self == post.question.author)
+ @true_if_is_super_or_staff
def can_like_comment(self, comment):
- return self != comment.user and (self.reputation >= int(settings.REP_TO_LIKE_COMMENT) or self.is_superuser)
+ return self != comment.author and (self.reputation >= int(settings.REP_TO_LIKE_COMMENT))
+ @true_if_is_super_or_staff
def can_edit_comment(self, comment):
- return (comment.user == self and comment.added_at >= datetime.datetime.now() - datetime.timedelta(minutes=60)
+ return (comment.author == self and comment.added_at >= datetime.datetime.now() - datetime.timedelta(minutes=60)
) or self.is_superuser
+ @true_if_is_super_or_staff
def can_delete_comment(self, comment):
- return self == comment.user or self.reputation >= int(settings.REP_TO_DELETE_COMMENTS) or self.is_superuser
+ return self == comment.author or self.reputation >= int(settings.REP_TO_DELETE_COMMENTS)
+ @true_if_is_super_or_staff
def can_accept_answer(self, answer):
- return self.is_superuser or self == answer.question.author
+ return self == answer.question.author
+ @true_if_is_super_or_staff
def can_edit_post(self, post):
- return self.is_superuser or self == post.author or self.reputation >= int(settings.REP_TO_EDIT_OTHERS
+ return self == post.author or self.reputation >= int(settings.REP_TO_EDIT_OTHERS
) or (post.wiki and self.reputation >= int(settings.REP_TO_EDIT_WIKI))
+ @true_if_is_super_or_staff
def can_retag_questions(self):
return self.reputation >= int(settings.REP_TO_RETAG)
+ @true_if_is_super_or_staff
def can_close_question(self, question):
- return self.is_superuser or (self == question.author and self.reputation >= int(settings.REP_TO_CLOSE_OWN)
+ return (self == question.author and self.reputation >= int(settings.REP_TO_CLOSE_OWN)
) or self.reputation >= int(settings.REP_TO_CLOSE_OTHERS)
+ @true_if_is_super_or_staff
def can_reopen_question(self, question):
- return self.is_superuser or (self == question.author and self.reputation >= settings.REP_TO_REOPEN_OWN)
+ return self == question.author and self.reputation >= settings.REP_TO_REOPEN_OWN
+ @true_if_is_super_or_staff
def can_delete_post(self, post):
- return self.is_superuser or (self == post.author and (post.__class__.__name__ == "Answer" or
- not post.answers.filter(~Q(author=self)).count()))
+ if post.node_type == "comment":
+ return self.can_delete_comment(post)
+
+ return (self == post.author and (post.__class__.__name__ == "Answer" or
+ not post.answers.exclude(author=self).count()))
+ @true_if_is_super_or_staff
def can_upload_files(self):
- return self.is_superuser or self.reputation >= int(settings.REP_TO_UPLOAD)
+ return self.reputation >= int(settings.REP_TO_UPLOAD)
class Meta:
app_label = 'forum'
-class Activity(GenericContent):
- """
- We keep some history data for user activities
- """
- user = models.ForeignKey(User)
- activity_type = models.SmallIntegerField(choices=TYPE_ACTIVITY)
- active_at = models.DateTimeField(default=datetime.datetime.now)
- is_auditted = models.BooleanField(default=False)
-
- class Meta:
- app_label = 'forum'
- db_table = u'activity'
-
- def __unicode__(self):
- return u'[%s] was active at %s' % (self.user.username, self.active_at)
-
- def save(self, *args, **kwargs):
- super(Activity, self).save(*args, **kwargs)
- if self._is_new:
- activity_record.send(sender=self.activity_type, instance=self)
-
- @property
- def node(self):
- if self.activity_type in (const.TYPE_ACTIVITY_ANSWER, const.TYPE_ACTIVITY_ASK_QUESTION,
- const.TYPE_ACTIVITY_MARK_ANSWER, const.TYPE_ACTIVITY_COMMENT_QUESTION, const.TYPE_ACTIVITY_COMMENT_ANSWER):
- return self.content_object.leaf
-
- if self.activity_type in (const.TYPE_ACTIVITY_UPDATE_ANSWER, const.TYPE_ACTIVITY_UPDATE_QUESTION):
- return self.content_object.node.leaf
-
- raise NotImplementedError()
-
- @property
- def type_as_string(self):
- if self.activity_type == const.TYPE_ACTIVITY_ASK_QUESTION:
- return _("asked")
- elif self.activity_type == const.TYPE_ACTIVITY_ANSWER:
- return _("answered")
- elif self.activity_type == const.TYPE_ACTIVITY_MARK_ANSWER:
- return _("marked an answer")
- elif self.activity_type == const.TYPE_ACTIVITY_UPDATE_QUESTION:
- return _("edited a question")
- elif self.activity_type == const.TYPE_ACTIVITY_COMMENT_QUESTION:
- return _("commented a question")
- elif self.activity_type == const.TYPE_ACTIVITY_COMMENT_ANSWER:
- return _("commented an answer")
- elif self.activity_type == const.TYPE_ACTIVITY_UPDATE_ANSWER:
- return _("edited an answer")
- elif self.activity_type == const.TYPE_ACTIVITY_PRIZE:
- return _("received badge")
- else:
- raise NotImplementedError()
-
-
-activity_record = django.dispatch.Signal(providing_args=['instance'])
-
class SubscriptionSettings(models.Model):
user = models.OneToOneField(User, related_name='subscription_settings')
diff --git a/forum/models/utils.py b/forum/models/utils.py
index 984a55c..5ac8900 100644
--- a/forum/models/utils.py
+++ b/forum/models/utils.py
@@ -1,44 +1,84 @@
from django.db import models
from django.core.cache import cache
from django.conf import settings
-#try:
-# import cPickle as pickle
-#except ImportError:
-import pickle
-import django.dispatch
+from django.utils.encoding import force_unicode
+
+try:
+ from cPickle import loads, dumps
+except ImportError:
+ from pickle import loads, dumps
+
+from copy import deepcopy
+from base64 import b64encode, b64decode
+from zlib import compress, decompress
+
class PickledObject(str):
- pass
+ pass
+
+def dbsafe_encode(value, compress_object=True):
+ if not compress_object:
+ value = b64encode(dumps(deepcopy(value)))
+ else:
+ value = b64encode(compress(dumps(deepcopy(value))))
+ return PickledObject(value)
+
+def dbsafe_decode(value, compress_object=True):
+ if not compress_object:
+ value = loads(b64decode(value))
+ else:
+ value = loads(decompress(b64decode(value)))
+ return value
class PickledObjectField(models.Field):
__metaclass__ = models.SubfieldBase
+ def __init__(self, *args, **kwargs):
+ self.compress = kwargs.pop('compress', True)
+ self.protocol = kwargs.pop('protocol', 2)
+ kwargs.setdefault('null', True)
+ kwargs.setdefault('editable', False)
+ super(PickledObjectField, self).__init__(*args, **kwargs)
+
+ def get_default(self):
+ if self.has_default():
+ if callable(self.default):
+ return self.default()
+ return self.default
+
+ return super(PickledObjectField, self).get_default()
+
def to_python(self, value):
- if isinstance (value, PickledObject):
- return value
-
- try:
- return pickle.loads(value.encode('utf-8'))
- except:
- return value
-
- def get_db_prep_save(self, value):
if value is not None:
- if isinstance(value, PickledObject):
- return str(value)
- else:
- value = pickle.dumps(value)
+ try:
+ value = dbsafe_decode(value, self.compress)
+ except:
+ if isinstance(value, PickledObject):
+ raise
+ return value
+ def get_db_prep_value(self, value):
+ if value is not None and not isinstance(value, PickledObject):
+ value = force_unicode(dbsafe_encode(value, self.compress))
return value
+ def value_to_string(self, obj):
+ value = self._get_val_from_obj(obj)
+ return self.get_db_prep_value(value)
+
def get_internal_type(self):
return 'TextField'
+ def get_db_prep_lookup(self, lookup_type, value):
+ if lookup_type not in ['exact', 'in', 'isnull']:
+ raise TypeError('Lookup type %s is not supported.' % lookup_type)
+ return super(PickledObjectField, self).get_db_prep_lookup(lookup_type, value)
+
class KeyValueManager(models.Manager):
def create_cache_key(self, key):
- return "%s:key_value:%s" % (settings.APP_URL, key)
+ return "%s:keyvalue:%s" % (settings.APP_URL, key)
def save_to_cache(self, instance):
cache.set(self.create_cache_key(instance.key), instance, 2592000)
diff --git a/forum/modules.py b/forum/modules/__init__.py
similarity index 97%
rename from forum/modules.py
rename to forum/modules/__init__.py
index 10bbf65..023b464 100644
--- a/forum/modules.py
+++ b/forum/modules/__init__.py
@@ -7,7 +7,7 @@ from django.conf import settings
MODULES_PACKAGE = 'forum_modules'
-MODULES_FOLDER = os.path.join(os.path.dirname(__file__), '../' + MODULES_PACKAGE)
+MODULES_FOLDER = os.path.join(os.path.dirname(__file__), '../../' + MODULES_PACKAGE)
DISABLED_MODULES = getattr(settings, 'DISABLED_MODULES', [])
diff --git a/forum/modules/decorators.py b/forum/modules/decorators.py
new file mode 100644
index 0000000..17d248b
--- /dev/null
+++ b/forum/modules/decorators.py
@@ -0,0 +1,53 @@
+import inspect
+
+class DecoratableObject(object):
+ def __init__(self, fn):
+ self._callable = fn
+
+ def decorate(self, fn, needs_origin):
+ origin = self._callable
+
+ if needs_origin:
+ self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs)
+ else:
+ self._callable = lambda *args, **kwargs: fn(*args, **kwargs)
+
+ def __call__(self, *args, **kwargs):
+ return self._callable(*args, **kwargs)
+
+
+def decoratable(fn):
+ return DecoratableObject(fn)
+
+def decoratable_method(fn):
+ obj = DecoratableObject(fn)
+ def decorated(self, *args, **kwargs):
+ return obj(self, *args, **kwargs)
+
+ decorated.__obj = obj
+ return decorated
+
+decoratable.method = decoratable_method
+
+def decorate(origin, needs_origin=True):
+ if not isinstance(origin, DecoratableObject):
+ if hasattr(origin, '__obj'):
+ def decorator(fn):
+ origin.__obj.decorate(fn, needs_origin)
+ return origin
+ return decorator
+
+ raise Exception('Not an decoratable function: %s' % origin.name)
+
+ def decorator(fn):
+ origin.decorate(fn, needs_origin)
+ return origin
+
+ return decorator
+
+
+
+
+
+
+
diff --git a/forum/reputation.py b/forum/reputation.py
deleted file mode 100644
index 71f9d65..0000000
--- a/forum/reputation.py
+++ /dev/null
@@ -1,101 +0,0 @@
-from django.db.models.signals import post_save
-from forum.models.base import mark_canceled
-from forum.models.answer import answer_accepted, answer_accepted_canceled
-
-from forum.models import *
-from forum.const import *
-import settings
-
-def on_flagged_item(instance, created, **kwargs):
- if not created:
- return
-
- post = instance.content_object.leaf
- question = (post.__class__ == Question) and post or post.question
-
- post.author.reputes.create(value=-int(settings.REP_LOST_BY_FLAGGED), question=question,
- reputation_type=TYPE_REPUTATION_LOST_BY_FLAGGED)
-
-
- if post.offensive_flag_count == settings.FLAG_COUNT_TO_HIDE_POST:
- post.author.reputes.create(value=-int(settings.REP_LOST_BY_FLAGGED_3_TIMES),
- question=question, reputation_type=TYPE_REPUTATION_LOST_BY_FLAGGED_3_TIMES)
-
- if post.offensive_flag_count == settings.FLAG_COUNT_TO_DELETE_POST:
- post.author.reputes.create(value=-int(settings.REP_LOST_BY_FLAGGED_5_TIMES),
- question=question, reputation_type=TYPE_REPUTATION_LOST_BY_FLAGGED_5_TIMES)
-
- post.mark_deleted(User.objects.get_site_owner())
-
-post_save.connect(on_flagged_item, sender=FlaggedItem)
-
-def on_answer_accepted(answer, user, **kwargs):
- if user == answer.question.author and not user == answer.author:
- user.reputes.create(
- value=int(settings.REP_GAIN_BY_ACCEPTING), question=answer.question,
- reputation_type=TYPE_REPUTATION_GAIN_BY_ACCEPTING_ANSWER)
-
- if not user == answer.author:
- answer.author.reputes.create(
- value=int(settings.REP_GAIN_BY_ACCEPTED), question=answer.question,
- reputation_type=TYPE_REPUTATION_GAIN_BY_ANSWER_ACCEPTED)
-
-answer_accepted.connect(on_answer_accepted)
-
-
-def on_answer_accepted_canceled(answer, user, **kwargs):
- if user == answer.accepted_by:
- user.reputes.create(
- value=-int(settings.REP_LOST_BY_CANCELING_ACCEPTED), question=answer.question,
- reputation_type=TYPE_REPUTATION_LOST_BY_CANCELLING_ACCEPTED_ANSWER)
-
- if not user == answer.author:
- answer.author.reputes.create(
- value=-int(settings.REP_LOST_BY_ACCEPTED_CANCELED), question=answer.question,
- reputation_type=TYPE_REPUTATION_LOST_BY_ACCEPTED_ANSWER_CANCELED)
-
-answer_accepted_canceled.connect(on_answer_accepted)
-
-
-def on_vote(instance, created, **kwargs):
- if created and (instance.content_object.node_type in ("question", "answer") and not instance.content_object.wiki):
- post = instance.content_object.leaf
- question = (post.__class__ == Question) and post or post.question
-
- if instance.vote == -1:
- instance.user.reputes.create(value=-int(settings.REP_LOST_BY_DOWNVOTING),
- question=question, reputation_type=TYPE_REPUTATION_LOST_BY_DOWNVOTING)
-
- if instance.vote == 1 and post.author.get_reputation_by_upvoted_today() >= int(settings.MAX_REP_BY_UPVOTE_DAY):
- return
-
- repute_type, repute_value = (instance.vote == 1) and (
- TYPE_REPUTATION_GAIN_BY_UPVOTED, int(settings.REP_GAIN_BY_UPVOTED)) or (
- TYPE_REPUTATION_LOST_BY_DOWNVOTED, -int(settings.REP_LOST_BY_DOWNVOTED))
-
- post.author.reputes.create(value=repute_value, question=question, reputation_type=repute_type)
-
-post_save.connect(on_vote, sender=Vote)
-
-
-def on_vote_canceled(instance, **kwargs):
- if instance.content_object.node_type in ("question", "answer") and not instance.content_object.wiki:
- post = instance.content_object.leaf
- question = (post.__class__ == Question) and post or post.question
-
- if instance.vote == -1:
- instance.user.reputes.create(value=int(settings.REP_GAIN_BY_CANCELING_DOWNVOTE),
- question=question, reputation_type=TYPE_REPUTATION_GAIN_BY_CANCELING_DOWNVOTE)
-
- repute_type, repute_value = (instance.vote == 1) and (
- TYPE_REPUTATION_LOST_BY_UPVOTE_CANCELED, -int(settings.REP_LOST_BY_UPVOTE_CANCELED)) or (
- TYPE_REPUTATION_GAIN_BY_DOWNVOTE_CANCELED, int(settings.REP_GAIN_BY_DOWNVOTE_CANCELED))
-
- post.author.reputes.create(value=repute_value, question=question, reputation_type=repute_type)
-
-mark_canceled.connect(on_vote_canceled, sender=Vote)
-
-
-
-
-
diff --git a/forum/settings/__init__.py b/forum/settings/__init__.py
index 58ed460..a8530ee 100644
--- a/forum/settings/__init__.py
+++ b/forum/settings/__init__.py
@@ -18,6 +18,7 @@ from upload import *
from about import *
from faq import *
from form import *
+from moderation import *
BADGES_SET = SettingSet('badges', _('Badges config'), _("Configure badges on your OSQA site."), 500)
diff --git a/forum/settings/base.py b/forum/settings/base.py
index dc01577..5bcf5fc 100644
--- a/forum/settings/base.py
+++ b/forum/settings/base.py
@@ -8,12 +8,32 @@ class SettingSet(list):
self.description = description
self.weight = weight
self.markdown = markdown
+
class BaseSetting(object):
- def __init__(self, name, default, field_context):
+ @classmethod
+ def add_to_class(cls, name):
+ def wrapper(self, *args, **kwargs):
+ return self.value.__getattribute__(name)(*args, **kwargs)
+
+ setattr(cls, name, wrapper)
+
+ def __init__(self, name, default, set=None, field_context=None):
self.name = name
self.default = default
- self.field_context = field_context
+ self.field_context = field_context or {}
+
+ if set is not None:
+ if not set.name in Setting.sets:
+ Setting.sets[set.name] = set
+
+ Setting.sets[set.name].append(self)
+
+ def __str__(self):
+ return str(self.value)
+
+ def __unicode__(self):
+ return unicode(self.value)
@property
def value(self):
@@ -29,112 +49,44 @@ class BaseSetting(object):
def set_value(self, new_value):
new_value = self._parse(new_value)
+ self.save(new_value)
+
+ def save(self, value):
from forum.models import KeyValue
try:
kv = KeyValue.objects.get(key=self.name)
- old_value = kv.value
except:
kv = KeyValue(key=self.name)
- old_value = self.default
- kv.value = new_value
+ kv.value = value
kv.save()
- setting_update.send(sender=self, old_value=old_value, new_value=new_value)
-
def to_default(self):
self.set_value(self.default)
def _parse(self, value):
return value
- def __str__(self):
- return str(self.value)
-
- def __unicode__(self):
- return unicode(self.value)
-
- def __nonzero__(self):
- return bool(self.value)
-
-
-class StringSetting(BaseSetting):
- def _parse(self, value):
- if isinstance(value, unicode):
- return value.encode('utf8')
- else:
- return str(value)
-
- def __unicode__(self):
- return unicode(self.value.decode('utf8'))
-
- def __add__(self, other):
- return "%s%s" % (unicode(self), other)
-
- def __cmp__(self, other):
- return cmp(str(self), str(other))
-
-class IntegerSetting(BaseSetting):
- def _parse(self, value):
- return int(value)
-
- def __int__(self):
- return int(self.value)
-
- def __add__(self, other):
- return int(self) + int(other)
-
- def __sub__(self, other):
- return int(self) - int(other)
-
- def __cmp__(self, other):
- return int(self) - int(other)
-
-class FloatSetting(BaseSetting):
- def _parse(self, value):
- return float(value)
-
- def __int__(self):
- return int(self.value)
-
- def __float__(self):
- return float(self.value)
-
- def __add__(self, other):
- return float(self) + float(other)
-
- def __sub__(self, other):
- return float(self) - float(other)
-
- def __cmp__(self, other):
- return float(self) - float(other)
-
-class BoolSetting(BaseSetting):
- def _parse(self, value):
- return bool(value)
class Setting(object):
+ emulators = {}
sets = {}
- def __new__(cls, name, default, set=None, field_context={}):
- if isinstance(default, bool):
- instance = BoolSetting(name, default, field_context)
- elif isinstance(default, str):
- instance = StringSetting(name, default, field_context)
- elif isinstance(default, float):
- instance = FloatSetting(name, default, field_context)
- elif isinstance(default, int):
- instance = IntegerSetting(name, default, field_context)
+ def __new__(cls, name, default, set=None, field_context=None):
+ deftype = type(default)
+
+ if deftype in Setting.emulators:
+ emul = Setting.emulators[deftype]
else:
- instance = BaseSetting(name, default, field_context)
+ emul = type(deftype.__name__ + cls.__name__, (BaseSetting,), {})
+ fns = [n for n, f in [(p, getattr(deftype, p)) for p in dir(deftype) if not p in dir(cls)] if callable(f)]
- if set is not None:
- if not set.name in cls.sets:
- cls.sets[set.name] = set
+ for n in fns:
+ emul.add_to_class(n)
+
+ Setting.emulators[deftype] = emul
- cls.sets[set.name].append(instance)
+ return emul(name, default, set, field_context)
- return instance
-setting_update = django.dispatch.Signal(providing_args=['old_value', 'new_value'])
diff --git a/forum/settings/basic.py b/forum/settings/basic.py
index 80c8a62..23427ea 100644
--- a/forum/settings/basic.py
+++ b/forum/settings/basic.py
@@ -6,7 +6,7 @@ from forms import ImageFormWidget
from django.utils.translation import ugettext_lazy as _
from django.forms.widgets import Textarea
-BASIC_SET = SettingSet('basic', _('Basic Settings'), _("The basic settings for your application"), 1)
+BASIC_SET = SettingSet('basic', _('Basic settings'), _("The basic settings for your application"), 1)
APP_LOGO = Setting('APP_LOGO', '/m/default/media/images/logo.png', BASIC_SET, dict(
label = _("Application logo"),
diff --git a/forum/settings/email.py b/forum/settings/email.py
index d95a164..fb49f99 100644
--- a/forum/settings/email.py
+++ b/forum/settings/email.py
@@ -2,7 +2,7 @@ from base import Setting, SettingSet
from django.utils.translation import ugettext_lazy as _
from django.forms.widgets import PasswordInput
-EMAIL_SET = SettingSet('email', _('Email Settings'), _("Email server and other email related settings."), 50)
+EMAIL_SET = SettingSet('email', _('Email settings'), _("Email server and other email related settings."), 50)
EMAIL_HOST = Setting('EMAIL_HOST', '', EMAIL_SET, dict(
label = _("Email Server"),
diff --git a/forum/settings/extkeys.py b/forum/settings/extkeys.py
index a2e8222..abe860b 100644
--- a/forum/settings/extkeys.py
+++ b/forum/settings/extkeys.py
@@ -8,11 +8,10 @@ label = _("Google sitemap code"),
help_text = _("This is the code you get when you register your site at Google webmaster central ."),
required=False))
-GOOGLE_ANALYTICS_KEY = Setting('GOOGLE_ANALYTICS_KEY', '', EXT_KEYS_SET, dict(
+GOOGLE_ANALYTICS_KEY = Setting('GOOGLE_ANALYTICS_KEY', '', EXT_KEYS_SET, dict(
label = _("Google analytics key"),
help_text = _("Your Google analytics key. You can get one at the Google analytics official website "),
required=False))
-
WORDPRESS_API_KEY = Setting('WORDPRESS_API_KEY', '', EXT_KEYS_SET, dict(
label = _("Wordpress API key"),
help_text = _("Your Wordpress API key. You can get one at http://wordpress.com/ "),
diff --git a/forum/settings/form.py b/forum/settings/form.py
index 5cb1aee..7329d5f 100644
--- a/forum/settings/form.py
+++ b/forum/settings/form.py
@@ -37,4 +37,14 @@ help_text = _("The minimum number of characters a user must enter into the body
FORM_MAX_COMMENT_BODY = Setting('FORM_MAX_COMMENT_BODY', 600, FORUM_SET, dict(
label = _("Maximum length of comment"),
-help_text = _("The maximum number of characters a user can enter into the body of a comment.")))
\ No newline at end of file
+help_text = _("The maximum number of characters a user can enter into the body of a comment.")))
+
+FORM_ALLOW_MARKDOWN_IN_COMMENTS = Setting('FORM_ALLOW_MARKDOWN_IN_COMMENTS', True, FORUM_SET, dict(
+label = _("Allow markdown in comments"),
+help_text = _("Allow users to use markdown in comments."),
+required=False))
+
+FORM_GRAVATAR_IN_COMMENTS = Setting('FORM_GRAVATAR_IN_COMMENTS', False, FORUM_SET, dict(
+label = _("Show author gravatar in comments"),
+help_text = _("Show the gravatar image of a comment author."),
+required=False))
\ No newline at end of file
diff --git a/forum/settings/forms.py b/forum/settings/forms.py
index 337dea1..aa5a352 100644
--- a/forum/settings/forms.py
+++ b/forum/settings/forms.py
@@ -1,9 +1,17 @@
import os
from django import forms
-from base import Setting, StringSetting, IntegerSetting, BoolSetting, FloatSetting
+from base import Setting
from django.utils.translation import ugettext as _
from django.core.files.storage import FileSystemStorage
+class DummySetting:
+ pass
+
+class UnfilteredField(forms.CharField):
+ def clean(self, value):
+ return value
+
+
class SettingsSetForm(forms.Form):
def __init__(self, set, data=None, *args, **kwargs):
if data is None:
@@ -12,16 +20,16 @@ class SettingsSetForm(forms.Form):
super(SettingsSetForm, self).__init__(data, *args, **kwargs)
for setting in set:
- if isinstance(setting, StringSetting):
+ if isinstance(setting, Setting.emulators.get(str, DummySetting)):
field = forms.CharField(**setting.field_context)
- elif isinstance(setting, FloatSetting):
+ elif isinstance(setting, Setting.emulators.get(float, DummySetting)):
field = forms.FloatField(**setting.field_context)
- elif isinstance(setting, IntegerSetting):
+ elif isinstance(setting, Setting.emulators.get(int, DummySetting)):
field = forms.IntegerField(**setting.field_context)
- elif isinstance(setting, BoolSetting):
+ elif isinstance(setting, Setting.emulators.get(bool, DummySetting)):
field = forms.BooleanField(**setting.field_context)
else:
- field = forms.CharField(**setting.field_context)
+ field = UnfilteredField(**setting.field_context)
self.fields[setting.name] = field
@@ -60,4 +68,28 @@ class ImageFormWidget(forms.Widget):
elif name in data:
return data[name]
+class StringListWidget(forms.Widget):
+ def render(self, name, value, attrs=None):
+ ret = ""
+ for s in value:
+ ret += """
+
+
+ -
+
+ """ % {'name': name, 'value': s}
+
+ return """
+
+ """ % dict(name=name, ret=ret)
+
+ def value_from_datadict(self, data, files, name):
+ if 'submit' in data:
+ return data.getlist(name)
+ else:
+ return data[name]
+
diff --git a/forum/settings/moderation.py b/forum/settings/moderation.py
new file mode 100644
index 0000000..6af5401
--- /dev/null
+++ b/forum/settings/moderation.py
@@ -0,0 +1,24 @@
+from base import Setting, SettingSet
+from forms import StringListWidget
+
+from django.utils.translation import ugettext_lazy as _
+from django.forms.widgets import Textarea
+
+MODERATION_SET = SettingSet('moderation', _('Moderation settings'), _("Define the moderation workflow of your site"), 100)
+
+FLAG_TYPES = Setting('FLAG_TYPES',
+["Spam", "Advertising", "Offensive, Abusive, or Inappropriate", "Content violates terms of use", "Copyright Violation",
+ "Misleading", "Someone is not being nice", "Not relevant/off-topic", "Other"],
+MODERATION_SET, dict(
+label = _("Flag Reasons"),
+help_text = _("Create some flag reasons to use in the flag post popup."),
+widget=StringListWidget))
+
+
+CLOSE_TYPES = Setting('CLOSE_TYPES',
+["Duplicate Question", "Question is off-topic or not relevant", "Too subjective and argumentative",
+ "The question is answered, right answer was accepted", "Problem is not reproducible or outdated", "Other"],
+MODERATION_SET, dict(
+label = _("Close Reasons"),
+help_text = _("Create some close reasons to use in the close question popup."),
+widget=StringListWidget))
diff --git a/forum/skins/default/media/images/openid/aol.gif b/forum/skins/default/media/images/openid/aol.gif
index decc4f1..dd629cb 100644
Binary files a/forum/skins/default/media/images/openid/aol.gif and b/forum/skins/default/media/images/openid/aol.gif differ
diff --git a/forum/skins/default/media/images/openid/blogger.png b/forum/skins/default/media/images/openid/blogger.png
new file mode 100644
index 0000000..3c46818
Binary files /dev/null and b/forum/skins/default/media/images/openid/blogger.png differ
diff --git a/forum/skins/default/media/images/openid/claimid.png b/forum/skins/default/media/images/openid/claimid.png
new file mode 100644
index 0000000..441c0ed
Binary files /dev/null and b/forum/skins/default/media/images/openid/claimid.png differ
diff --git a/forum/skins/default/media/images/openid/facebook.gif b/forum/skins/default/media/images/openid/facebook.gif
index b997b35..9a32529 100644
Binary files a/forum/skins/default/media/images/openid/facebook.gif and b/forum/skins/default/media/images/openid/facebook.gif differ
diff --git a/forum/skins/default/media/images/openid/flickr.png b/forum/skins/default/media/images/openid/flickr.png
new file mode 100644
index 0000000..6c443e1
Binary files /dev/null and b/forum/skins/default/media/images/openid/flickr.png differ
diff --git a/forum/skins/default/media/images/openid/google.gif b/forum/skins/default/media/images/openid/google.gif
index 1b6cd07..be451e5 100644
Binary files a/forum/skins/default/media/images/openid/google.gif and b/forum/skins/default/media/images/openid/google.gif differ
diff --git a/forum/skins/default/media/images/openid/livejournal.png b/forum/skins/default/media/images/openid/livejournal.png
new file mode 100644
index 0000000..9f2f6dd
Binary files /dev/null and b/forum/skins/default/media/images/openid/livejournal.png differ
diff --git a/forum/skins/default/media/images/openid/myopenid.png b/forum/skins/default/media/images/openid/myopenid.png
new file mode 100644
index 0000000..e5df78d
Binary files /dev/null and b/forum/skins/default/media/images/openid/myopenid.png differ
diff --git a/forum/skins/default/media/images/openid/technorati.png b/forum/skins/default/media/images/openid/technorati.png
new file mode 100644
index 0000000..7216641
Binary files /dev/null and b/forum/skins/default/media/images/openid/technorati.png differ
diff --git a/forum/skins/default/media/images/openid/twitter.png b/forum/skins/default/media/images/openid/twitter.png
index 9a6552d..6178f9c 100644
Binary files a/forum/skins/default/media/images/openid/twitter.png and b/forum/skins/default/media/images/openid/twitter.png differ
diff --git a/forum/skins/default/media/images/openid/verisign.png b/forum/skins/default/media/images/openid/verisign.png
new file mode 100644
index 0000000..bc5c5f3
Binary files /dev/null and b/forum/skins/default/media/images/openid/verisign.png differ
diff --git a/forum/skins/default/media/images/openid/wordpress.png b/forum/skins/default/media/images/openid/wordpress.png
new file mode 100644
index 0000000..f261705
Binary files /dev/null and b/forum/skins/default/media/images/openid/wordpress.png differ
diff --git a/forum/skins/default/media/images/openid/yahoo.gif b/forum/skins/default/media/images/openid/yahoo.gif
index 0f0eb8e..1ebaa7f 100644
Binary files a/forum/skins/default/media/images/openid/yahoo.gif and b/forum/skins/default/media/images/openid/yahoo.gif differ
diff --git a/forum/skins/default/media/js/jquery.openid.js b/forum/skins/default/media/js/jquery.openid.js
index af7d8cb..a1316c1 100644
--- a/forum/skins/default/media/js/jquery.openid.js
+++ b/forum/skins/default/media/js/jquery.openid.js
@@ -57,11 +57,6 @@ var providers_small = {
label: 'Your Verisign username',
url: 'http://{username}.pip.verisignlabs.com/'
},
- vidoop: {
- name: 'Vidoop',
- label: 'Your Vidoop username',
- url: 'http://{username}.myvidoop.com/'
- },
verisign: {
name: 'Verisign',
label: 'Your Verisign username',
@@ -101,7 +96,7 @@ var openid = {
if (providers_small) {
openid_btns.append(' ');
for (id in providers_small) {
- openid_btns.append(this.getBoxHTML(providers_small[id], 'small', '.ico'));
+ openid_btns.append(this.getBoxHTML(providers_small[id], 'small', '.png'));
}
}
diff --git a/forum/skins/default/media/js/osqa.admin.js b/forum/skins/default/media/js/osqa.admin.js
new file mode 100644
index 0000000..ce0fc79
--- /dev/null
+++ b/forum/skins/default/media/js/osqa.admin.js
@@ -0,0 +1,21 @@
+$(function() {
+ $('.string_list_widget_button').live('click', function() {
+ $but = $(this);
+
+ if ($but.is('.add')) {
+ $new = $("" +
+ " " +
+ "- " +
+ "
");
+
+ $but.before($new);
+ $new.slideDown('fast');
+ } else {
+ $but.parent().slideUp('fast', function() {
+ $but.parent().remove();
+ });
+ }
+
+ return false;
+ })
+});
\ No newline at end of file
diff --git a/forum/skins/default/media/js/osqa.main.js b/forum/skins/default/media/js/osqa.main.js
index 6264fb4..06b2cc9 100644
--- a/forum/skins/default/media/js/osqa.main.js
+++ b/forum/skins/default/media/js/osqa.main.js
@@ -1,4 +1,8 @@
var response_commands = {
+ refresh_page: function() {
+ window.location.reload(true)
+ },
+
update_post_score: function(id, inc) {
var $score_board = $('#post-' + id + '-score');
var current = parseInt($score_board.html())
@@ -68,7 +72,7 @@ var response_commands = {
});
},
- insert_comment: function(post_id, comment_id, comment, username, profile_url, delete_url) {
+ insert_comment: function(post_id, comment_id, comment, username, profile_url, delete_url, edit_url) {
var $container = $('#comments-container-' + post_id);
var skeleton = $('#new-comment-skeleton-' + post_id).html().toString();
@@ -76,7 +80,8 @@ var response_commands = {
.replace(new RegExp('%COMMENT%', 'g'), comment)
.replace(new RegExp('%USERNAME%', 'g'), username)
.replace(new RegExp('%PROFILE_URL%', 'g'), profile_url)
- .replace(new RegExp('%DELETE_URL%', 'g'), delete_url);
+ .replace(new RegExp('%DELETE_URL%', 'g'), delete_url)
+ .replace(new RegExp('%EDIT_URL%', 'g'), edit_url);
$container.append(skeleton);
@@ -100,6 +105,16 @@ var response_commands = {
}
},
+ unmark_deleted: function(post_type, post_id) {
+ if (post_type == 'answer') {
+ var $answer = $('#answer-container-' + post_id);
+ $answer.removeClass('deleted');
+ } else {
+ var $container = $('#question-table');
+ $container.removeClass('deleted');
+ }
+ },
+
set_subscription_button: function(text) {
$('.subscription_switch').html(text);
},
@@ -109,38 +124,127 @@ var response_commands = {
}
}
-function show_message(object, msg) {
+function show_message(object, msg, callback) {
var div = $('
' + msg + ' (' +
'click to close' + ')
');
div.click(function(event) {
- $(".vote-notification").fadeOut("fast", function() { $(this).remove(); });
+ $(".vote-notification").fadeOut("fast", function() {
+ $(this).remove();
+ if (callback) {
+ callback();
+ }
+ });
});
object.parent().append(div);
div.fadeIn("fast");
}
-function process_ajax_response(data, el) {
+function load_prompt(object, url) {
+ var $box = $('' +
+ '
' +
+ '
');
+
+
+ object.parent().append($box);
+ $box.fadeIn("fast");
+
+ $box.load(url, function() {
+ $box.find('.prompt-cancel').click(function() {
+ $box.fadeOut('fast', function() {
+ $box.remove();
+ });
+ return false;
+ });
+
+ $box.find('.prompt-submit').click(function() {
+ start_command();
+ $.post(url, {prompt: $box.find('textarea').val()}, function(data) {
+ $box.fadeOut('fast', function() {
+ $box.remove();
+ });
+ process_ajax_response(data, object);
+ }, 'json');
+ return false;
+ });
+ });
+}
+
+function show_prompt(object, msg, callback) {
+ var div = $('' + msg + ' ' +
+ ' ' +
+ 'Cancel ' +
+ 'OK ' +
+ '
');
+
+ function fade_out() {
+ div.fadeOut("fast", function() { div.remove(); });
+ }
+
+ div.find('.prompt-cancel').click(fade_out);
+
+ div.find('.prompt-ok').click(function(event) {
+ callback(div.find('.command-prompt').val());
+ fade_out();
+ });
+
+ object.parent().append(div);
+ div.fadeIn("fast");
+}
+
+function process_ajax_response(data, el, callback) {
if (!data.success && data['error_message'] != undefined) {
- show_message(el, data.error_message)
+ show_message(el, data.error_message, function() {if (callback) callback(true);});
+ end_command(false);
} else if (typeof data['commands'] != undefined){
for (var command in data.commands) {
response_commands[command].apply(null, data.commands[command])
}
if (data['message'] != undefined) {
- show_message(el, data.message)
+ show_message(el, data.message, function() {if (callback) callback(false);})
+ } else {
+ if (callback) callback(false);
}
+ end_command(true);
+ }
+}
+
+var running = false;
+
+function start_command() {
+ $('body').append($('
'));
+ running = true;
+}
+
+function end_command(success) {
+ if (success) {
+ $('#command-loader').addClass('success');
+ $('#command-loader').fadeOut("slow", function() {
+ $('#command-loader').remove();
+ running = false;
+ });
+ } else {
+ $('#command-loader').remove();
+ running = false;
}
}
$(function() {
$('a.ajax-command').live('click', function() {
+ if (running) return false;
+
var el = $(this);
- $.getJSON(el.attr('href'), function(data) {
- process_ajax_response(data, el);
- });
+
+ if (el.is('.withprompt')) {
+ load_prompt(el, el.attr('href'));
+ } else {
+ start_command();
+ $.getJSON(el.attr('href'), function(data) {
+ process_ajax_response(data, el);
+ });
+ }
return false
});
@@ -149,50 +253,105 @@ $(function() {
var $container = $(this);
var $form = $container.find('form');
var $textarea = $container.find('textarea');
- var $button = $container.find('input[type="submit"]');
- var $chars_left_message = $('.comment-chars-left');
+ var textarea = $textarea.get(0);
+ var $button = $container.find('.comment-submit');
+ var $cancel = $container.find('.comment-cancel');
+ var $chars_left_message = $container.find('.comments-chars-left-msg');
+ var $chars_togo_message = $container.find('.comments-chars-togo-msg');
var $chars_counter = $container.find('.comments-char-left-count');
var $comment_tools = $container.parent().find('.comment-tools');
var $add_comment_link = $comment_tools.find('.add-comment-link');
var $comments_container = $container.parent().find('.comments-container');
- var max_length = parseInt($chars_counter.html());
+ var chars_limits = $chars_counter.html().split('|');
+
+ var min_length = parseInt(chars_limits[0]);
+ var max_length = parseInt(chars_limits[1]);
+
+ var warn_length = max_length - 30;
+ var current_length = 0;
var comment_in_form = false;
+ var interval = null;
+
+ var hcheck = !($.browser.msie || $.browser.opera);
+
+ $textarea.css("padding-top", 0).css("padding-bottom", 0).css("resize", "none");
+ textarea.style.overflow = 'hidden';
+
function cleanup_form() {
$textarea.val('');
+ $textarea.css('height', 80);
$chars_counter.html(max_length);
$chars_left_message.removeClass('warn');
comment_in_form = false;
+ current_length = 0;
+
+ $chars_left_message.hide();
+ $chars_togo_message.show();
+
+ $chars_counter.removeClass('warn');
+ $chars_counter.html(min_length);
+ $button.attr("disabled","disabled");
+
+ interval = null;
}
cleanup_form();
- function calculate_chars_left() {
+ function process_form_changes() {
var length = $textarea.val().length;
- var allow = true;
- if (length < max_length) {
- if (length < max_length * 0.75) {
- $chars_left_message.removeClass('warn');
- } else {
- $chars_left_message.addClass('warn');
- }
+ if (current_length == length)
+ return;
+
+ if (length < warn_length && current_length >= warn_length) {
+ $chars_counter.removeClass('warn');
+ } else if (current_length < warn_length && length >= warn_length){
+ $chars_counter.addClass('warn');
+ }
+
+ if (length < min_length) {
+ $chars_left_message.hide();
+ $chars_togo_message.show();
+ $chars_counter.html(min_length - length);
+ } else {
+ $chars_togo_message.hide();
+ $chars_left_message.show();
+ $chars_counter.html(max_length - length);
+ }
+
+ if (length > max_length || length < min_length) {
+ $button.attr("disabled","disabled");
} else {
- allow = false;
+ $button.removeAttr("disabled");
}
- $chars_counter.html(max_length - length);
- return allow;
+ var current_height = textarea.style.height;
+ if (hcheck)
+ textarea.style.height = "0px";
+
+ var h = Math.max(80, textarea.scrollHeight);
+ textarea.style.height = current_height;
+ $textarea.animate({height: h + 'px'}, 50);
+
+ current_length = length;
}
function show_comment_form() {
$container.slideDown('slow');
$add_comment_link.fadeOut('slow');
+ window.setInterval(function() {
+ process_form_changes();
+ }, 200);
}
function hide_comment_form() {
+ if (interval != null) {
+ window.clearInterval(interval);
+ interval = null;
+ }
$container.slideUp('slow');
$add_comment_link.fadeIn('slow');
}
@@ -213,37 +372,48 @@ $(function() {
$('#' + $comments_container.attr('id') + ' .comment-edit').live('click', function() {
var $link = $(this);
var comment_id = /comment-(\d+)-edit/.exec($link.attr('id'))[1];
- var $comment = $link.parents('.comment');
- var comment_text = $comment.find('.comment-text').text().trim();
+ var $comment = $('#comment-' + comment_id);
comment_in_form = comment_id;
- $textarea.val(comment_text);
- calculate_chars_left();
+
+ $.get($link.attr('href'), function(data) {
+ $textarea.val(data);
+ });
+
$comment.slideUp('slow');
show_comment_form();
return false;
});
- $textarea.keyup(calculate_chars_left);
-
$button.click(function() {
- if ($textarea.val().length > max_length) {
- show_message($button, "Your comment exceeds the max number of characters allowed.");
- } else {
- var post_data = {
- comment: $textarea.val()
- }
+ if (running) return false;
- if (comment_in_form) {
- post_data['id'] = comment_in_form;
- }
+ var post_data = {
+ comment: $textarea.val()
+ }
- $.post($form.attr('action'), post_data, function(data) {
- process_ajax_response(data, $button);
- cleanup_form();
- }, "json")
+ if (comment_in_form) {
+ post_data['id'] = comment_in_form;
}
+ start_command();
+ $.post($form.attr('action'), post_data, function(data) {
+ process_ajax_response(data, $button, function(error) {
+ if (!error) {
+ cleanup_form();
+ hide_comment_form();
+ }
+ });
+
+ }, "json");
+
+ return false;
+ });
+
+ $cancel.click(function() {
+ if (comment_in_form) {
+ $comment = $('#comment-' + comment_in_form).slideDown('slow');
+ }
hide_comment_form();
return false;
});
diff --git a/forum/skins/default/media/style/admin.css b/forum/skins/default/media/style/admin.css
index 673e9b4..4fcfad5 100644
--- a/forum/skins/default/media/style/admin.css
+++ b/forum/skins/default/media/style/admin.css
@@ -2,7 +2,7 @@
border-spacing: 10px;
}
-#admin_form input[type="text"], #admin_form input[type="submit"], #admin_form textarea {
+#admin_form input[type="text"], #admin_form input[type="submit"], #admin_form textarea, .string_list_widget_button {
line-height: 22px;
font-size: 140%;
font-family: sans-serif;
@@ -10,7 +10,7 @@
color: black;
}
-#admin_form input[type="text"], #admin_form input[type="submit"] {
+#admin_form input[type="text"], #admin_form input[type="submit"], .string_list_widget_button {
height: 28px;
}
@@ -30,4 +30,19 @@
#admin_page_description {
color: gray;
padding-bottom: 20px;
+}
+
+.string_list_widget input[type=text] {
+ width: 520px;
+}
+
+.string_list_widget_button {
+ width: 28px;
+ font-size: 20px;
+ font-weight: bold;
+}
+
+.string_list_widget_button.add {
+ position: relative;
+ left: 554px;
}
\ No newline at end of file
diff --git a/forum/skins/default/media/style/auth.css b/forum/skins/default/media/style/auth.css
index 3370275..0734ce0 100644
--- a/forum/skins/default/media/style/auth.css
+++ b/forum/skins/default/media/style/auth.css
@@ -3,24 +3,42 @@
padding: 0px;
width:600px;
margin:0px 0px 5px 0px;
+ clear:both;
}
.provider_logo {
- display: inline-block;
- padding: 4px;
+ display: block;
border: 1px solid #DDD;
text-align: center;
- vertical-align: middle;
}
.provider_logo.big {
- height: 40px;
- width: 90px;
+ display: block;
+ border:1px solid #DDDDDD;
+ float:left;
+ height:60px;
+ margin:3px;
+ width:110px;
+}
+
+.provider_logo.big .inner {
+ display:block;
+ margin: 0px auto;
+ margin-top: 18px;
}
.provider_logo.small {
- height: 32px;
- width: 32px;
+ border:1px solid #DDDDDD;
+ float:left;
+ height:30px;
+ margin:3px;
+ width:30px;
+}
+
+.provider_logo.small .inner {
+ display:block;
+ margin: 0px auto;
+ margin-top: 6px;
}
.provider_logo.selected {
@@ -31,18 +49,36 @@
display: none;
}
+.signin_form {
+ clear:both;
+}
+
+.signin_form fieldset {
+ padding: 10px;
+}
+
.signin_form input[type="text"], .signin_form input[type="password"], .signin_form input[type="submit"] {
height: 28px;
line-height: 22px;
font-size: 140%;
border: 1px solid #999;
+ padding-left:5px;
+ margin-right:5px;
+}
+
+.signin_form input[type="text"], .signin_form input[type="password"] {
+ padding-top:4px; /* balance of alignment between firefox/safari and IE */
}
.signin_form .icon_input {
padding-left: 20px;
}
+.signin_form #openid_identifier {
+ padding-left: 18px;
+}
+
.or_label {
margin-top: 20px;
margin-bottom: 10px;
-}
\ No newline at end of file
+}
diff --git a/forum/skins/default/media/style/style.css b/forum/skins/default/media/style/style.css
index dee175b..9932037 100644
--- a/forum/skins/default/media/style/style.css
+++ b/forum/skins/default/media/style/style.css
@@ -663,8 +663,6 @@ ul.errorlist li {
margin-top: 5px;
}
-div.comments-container { padding: 0; }
-
.answer {
border-bottom: 1px solid #CCCCCE;
padding-top: 10px;
@@ -677,13 +675,13 @@ div.comments-container { padding: 0; }
min-height: 80px;
}
+.answered-by-owner { background: none repeat scroll 0 0 #E9E9FF; }
+
.accepted-answer {
background-color: #EBFFE6;
border-bottom-color: #9BD59B;
}
-.accepted-answer .comments-container { background-color: #CCFFBF; }
-
.answered {
background: none repeat scroll 0 0 #E5EBF8;
color: #314362;
@@ -699,9 +697,6 @@ div.comments-container { padding: 0; }
color: #6B2B28;
}
-.answered-by-owner { background: none repeat scroll 0 0 #E9E9FF; }
-.answered-by-owner .comments-container { background-color: #E6ECFF; }
-
.tagsList {
list-style-type: none;
margin: 0;
@@ -1111,7 +1106,6 @@ ul.form-horizontal-rows li input {
}
.post-controls {
- float: left;
font-size: 11px;
line-height: 12px;
margin-bottom: 5px;
@@ -1120,11 +1114,6 @@ ul.form-horizontal-rows li input {
#question-controls .tags { margin: 0 0 3px; }
-.post-update-info-container {
- float: right;
- min-width: 190px;
-}
-
.post-update-info {
display: inline-block;
float: right;
@@ -1145,21 +1134,6 @@ ul.form-horizontal-rows li input {
width: 32px;
}
-.comments-container { clear: both; }
-
-.admin {
- background-color: #FFF380;
- border: 1px solid darkred;
- padding: 0 5px;
-}
-
-.admin p { margin-bottom: 3px; }
-
-.admin #action_status {
- font-weight: bold;
- text-align: center;
-}
-
#tagSelector { padding-bottom: 2px; }
#hideIgnoredTagsControl { margin: 5px 0 0; }
#hideIgnoredTagsCb { margin: 0 2px 0 1px; }
@@ -1192,10 +1166,10 @@ a.post-vote.down.on,a.post-vote.down:hover { background: url("../images/vote-arr
a.accept-answer { background: url("../images/vote-accepted.png") no-repeat scroll center center transparent; }
a.accept-answer.on,a.accept-answer:hover { background: url("../images/vote-accepted-on.png") no-repeat scroll center center transparent; }
-.post-score {
+.post-score, .comments-char-left-count {
color: #777777;
font-family: Arial;
- font-size: 140%;
+ font-size: 165%;
font-weight: bold;
padding: 0 0 3px;
}
@@ -1211,10 +1185,15 @@ a.accept-answer.on,a.accept-answer:hover { background: url("../images/vote-accep
padding: 0;
}
+.comments-container { clear: both; }
+.comments-container { padding: 0; }
+.answered-by-owner .comments-container { background-color: #E6ECFF; }
+.accepted-answer .comments-container { background-color: #CCFFBF; }
+
.comment {
border-top: 1px dotted #CCCCCE;
margin: 0;
- width: 100%;
+ position: relative;
}
.comment.not_top_scorer { display: none; }
@@ -1226,27 +1205,39 @@ a.accept-answer.on,a.accept-answer:hover { background: url("../images/vote-accep
font-weight: bold;
padding-top: 3px;
vertical-align: top;
+ float: left;
width: 22px;
+ height: 100%;
+ text-align: center;
}
.comment-text {
color: #444444;
- font-size: 11px;
+ font-size: 12px;
margin: 0 0 0 22px;
padding: 0;
}
+.comment-text p {
+ font-size: 12px;
+}
+
.comment-info {
font-size: 11px;
- margin: 0;
- text-align: right;
+ margin: 0 0 4px 0;
+ text-align: right;
+ height: 18px;
+ vertical-align: middle;
}
-a.comment-like,a.comment-delete,a.comment-edit {
- float: right;
+.comment-info * {
+ float: right;
height: 18px;
+ margin-left: 4px;
+}
+
+a.comment-like,a.comment-delete,a.comment-edit {
margin-left: 2px;
- position: relative;
width: 18px;
}
@@ -1265,8 +1256,9 @@ a.comment-edit:hover { background: url("../images/comment-edit-hover.png") no-re
.comment-form-widgets-container input { vertical-align: top; }
.comment-form-widgets-container textarea {
- height: 6em;
+ height: 80px;
width: 80%;
+ float: left;
}
span.comment-chars-left {
@@ -1312,3 +1304,69 @@ div.comment-tools a:hover {
}
.action-link-separator { color: #CCCCCC; }
+
+.deleted {background-color: #F4E7E7;}
+
+#command-loader {
+ position: fixed;
+ bottom: 0px;
+ left: 0px;
+ width: 24px;
+ height: 24px;
+ background: url('/m/default/media/images/indicator.gif')
+}
+
+#command-loader.success {
+ background: url('/m/default/media/images/vote-accepted-on.png')
+}
+
+.user-prompt {
+ width: 300px;
+}
+
+.user-prompt select, .user-prompt textarea {
+ width: 100%;
+ padding: 0;
+ border: 0;
+}
+
+.user-prompt .prompt-buttons {
+ text-align: right;
+}
+
+.comment-form-buttons {
+ width: 18%;
+ height: 100%;
+ float: right;
+}
+
+.comment-form-buttons input, .user-prompt .prompt-buttons button {
+ height: 16px;
+ line-height: 12px;
+ font-size: 110%;
+ border: 1px solid #999;
+}
+
+.comment-form-buttons input {
+ width: 100%;
+ height: 22px;
+ vertical-align: center;
+ margin-top: 6px;
+}
+
+.comments-char-left-count.warn {
+ color: orange;
+}
+
+.moderation {
+ background-color: #FFF380;
+ border: 1px solid darkred;
+ padding: 0 5px;
+}
+
+.moderation p { margin-bottom: 3px; }
+
+.moderation #action_status {
+ font-weight: bold;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/forum/skins/default/templates/ask.html b/forum/skins/default/templates/ask.html
index a925e9d..35a6c2c 100644
--- a/forum/skins/default/templates/ask.html
+++ b/forum/skins/default/templates/ask.html
@@ -25,7 +25,7 @@
$('#pre-collapse').text(txt);
});
- // Tags autocomplete action
+ //Tags autocomplete action
$("#id_tags").autocomplete("/matching_tags", {
minChars: 1,
matchContains: true,
diff --git a/forum/skins/default/templates/auth/signin.html b/forum/skins/default/templates/auth/signin.html
index 798faeb..6f653f8 100644
--- a/forum/skins/default/templates/auth/signin.html
+++ b/forum/skins/default/templates/auth/signin.html
@@ -36,7 +36,10 @@
{% trans 'Or...' %}
{% endif %}
- {% trans "Click to sign in through any of these services." %}
+ {% blocktrans %}
+ External login services use
OpenID technology, where your password always stays confidential between
+ you and your login provider and you don't have to remember another one.
+ {% endblocktrans %}
{% if request.user.is_anonymous %}
@@ -47,34 +50,38 @@
{% for provider in bigicon_providers %}
- {% ifequal provider.type "DIRECT" %}
-
-
-
- {% endifequal %}
- {% ifequal provider.type "CUSTOM" %}
- {% include provider.code_template %}
- {% endifequal %}
- {% ifequal provider.type "SIMPLE_FORM" %}
-
- {% endifequal %}
+
+ {% ifequal provider.type "DIRECT" %}
+
+
+
+ {% endifequal %}
+ {% ifequal provider.type "CUSTOM" %}
+ {% include provider.code_template %}
+ {% endifequal %}
+ {% ifequal provider.type "SIMPLE_FORM" %}
+
+ {% endifequal %}
+
{% endfor %}
{% for provider in smallicon_providers %}
- {% ifequal provider.type "DIRECT" %}
-
-
-
- {% endifequal %}
- {% ifequal provider.type "CUSTOM" %}
- {% include provider.code_template %}
- {% endifequal %}
- {% ifequal provider.type "SIMPLE_FORM" %}
-
- {% endifequal %}
+
+ {% ifequal provider.type "DIRECT" %}
+
+
+
+ {% endifequal %}
+ {% ifequal provider.type "CUSTOM" %}
+ {% include provider.code_template %}
+ {% endifequal %}
+ {% ifequal provider.type "SIMPLE_FORM" %}
+
+ {% endifequal %}
+
{% endfor %}
@@ -90,9 +97,11 @@
{% endfor %}
{% trans 'Or...' %}
-
- {% trans 'Click' %} here {% trans "if you're having troubles signing in." %}
-
+
diff --git a/forum/skins/default/templates/node/post_controls.html b/forum/skins/default/templates/node/post_controls.html
index 5b5fc86..c24660b 100644
--- a/forum/skins/default/templates/node/post_controls.html
+++ b/forum/skins/default/templates/node/post_controls.html
@@ -1,7 +1,7 @@
{% spaceless %}
{% for control in controls %}
- {{ control.text }}
{% ifnotequal controls|last control %}
diff --git a/forum/skins/default/templates/node/report.html b/forum/skins/default/templates/node/report.html
new file mode 100644
index 0000000..dbc8630
--- /dev/null
+++ b/forum/skins/default/templates/node/report.html
@@ -0,0 +1,19 @@
+{% load i18n %}
+
+
+ {% trans "Please select a reason bellow or use the text box to input your own reason." %}
+
+ {% for type in types %}
+ {{ type }}
+ {% endfor %}
+
+
+
+ {% trans "Cancel" %} {% trans "Send" %}
+
+
+
\ No newline at end of file
diff --git a/forum/skins/default/templates/osqaadmin/base.html b/forum/skins/default/templates/osqaadmin/base.html
index e35a705..2acdc15 100644
--- a/forum/skins/default/templates/osqaadmin/base.html
+++ b/forum/skins/default/templates/osqaadmin/base.html
@@ -5,6 +5,7 @@
{% block forejs %}
+
{% block adminjs %}{% endblock %}
{% endblock %}
@@ -23,12 +24,12 @@
{% block sidebar %}
-
{% trans "Administration menu" %}
-
+
{% trans "Administration menu" %}
+
{% if markdown %}
@@ -65,5 +66,4 @@
{% endif %}
{% endblock %}
-
-
+
diff --git a/forum/skins/default/templates/osqaadmin/index.html b/forum/skins/default/templates/osqaadmin/index.html
index 9e35a35..64670f5 100644
--- a/forum/skins/default/templates/osqaadmin/index.html
+++ b/forum/skins/default/templates/osqaadmin/index.html
@@ -65,7 +65,7 @@
{% trans "Recent activity" %}
{% for activity in recent_activity %}
- {% activity_item activity %}
+ {% activity_item activity request.user %}
{% endfor %}
diff --git a/forum/skins/default/templates/post_contributor_info.html b/forum/skins/default/templates/post_contributor_info.html
index 9997be5..2770644 100644
--- a/forum/skins/default/templates/post_contributor_info.html
+++ b/forum/skins/default/templates/post_contributor_info.html
@@ -35,20 +35,20 @@
{% get_score_badge post.author %}
{% endif %}
{% else %}
- {% if post.last_edited_at %}
+ {% if post.last_edited %}
{% ifequal post_type 'question' %}
{% else %}
{% endifequal %}
- {% trans "updated" %} {% diff_date post.last_edited_at %}
+ {% trans "updated" %} {% diff_date post.last_edited.at %}
- {% if post.author != post.last_edited_by or wiki %}
- {% gravatar post.last_edited_by 32 %}
- {{post.last_edited_by.get_profile_link}}
- {% get_score_badge post.last_edited_by %}
+ {% if post.author != post.last_edited.by or wiki %}
+ {% gravatar post.last_edited.by 32 %}
+ {{post.last_edited.by.get_profile_link}}
+ {% get_score_badge post.last_edited.by %}
{% endif %}
{% endif %}
{% endifequal %}
diff --git a/forum/skins/default/templates/question.html b/forum/skins/default/templates/question.html
index 7a265c6..b6300d5 100644
--- a/forum/skins/default/templates/question.html
+++ b/forum/skins/default/templates/question.html
@@ -7,7 +7,7 @@
{% load humanize %}
{% load i18n %}
{% load cache %}
-{% block title %}{% spaceless %}{{ question.get_question_title }}{% endspaceless %}{% endblock %}
+{% block title %}{% spaceless %}{{ question.headline }}{% endspaceless %}{% endblock %}
{% block forejs %}
@@ -19,8 +19,6 @@
{% endif %}
+
+
+
+
+