--- /dev/null
+from meta import *\r
+from node import *\r
+from user import *
\ No newline at end of file
--- /dev/null
+from django.utils.translation import ugettext as _\r
+from django.db.models import F\r
+from forum.models.action import ActionProxy, DummyActionProxy\r
+from forum.models import Vote, Flag\r
+import settings\r
+\r
+class VoteAction(ActionProxy):\r
+ def update_node_score(self, inc):\r
+ self.node.score = F('score') + inc\r
+ self.node.save()\r
+\r
+ def process_vote_action(self, value):\r
+ self.update_node_score(value)\r
+ vote = Vote(node=self.node, user=self.user, action=self, value=value)\r
+ vote.save()\r
+\r
+ def cancel_action(self):\r
+ vote = self.vote.all()[0]\r
+ self.update_node_score(-vote.value)\r
+ vote.delete()\r
+\r
+ @classmethod\r
+ def get_for(cls, user, node):\r
+ try:\r
+ vote = Vote.objects.get(user=user, node=node)\r
+ return vote.value\r
+ except:\r
+ return None\r
+\r
+ def describe_vote(self, vote_desc, viewer=None):\r
+ return _("%(user)s %(vote_desc)s %(post_desc)s") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'vote_desc': vote_desc, 'post_desc': self.describe_node(viewer, self.node)\r
+ }\r
+\r
+\r
+class VoteUpAction(VoteAction):\r
+ def repute_users(self):\r
+ self.repute(self.node.author, int(settings.REP_GAIN_BY_UPVOTED))\r
+\r
+ def process_action(self):\r
+ self.process_vote_action(1)\r
+ self.user.reset_vote_up_count_cache()\r
+\r
+ def cancel_action(self):\r
+ super(VoteUpAction, self).cancel_action()\r
+ self.user.reset_vote_up_count_cache()\r
+\r
+ def describe(self, viewer=None):\r
+ return self.describe_vote(_("voted up"), viewer)\r
+\r
+class VoteDownAction(VoteAction):\r
+ def repute_users(self):\r
+ self.repute(self.node.author, -int(settings.REP_LOST_BY_DOWNVOTED))\r
+ self.repute(self.user, -int(settings.REP_LOST_BY_DOWNVOTING))\r
+\r
+ def process_action(self):\r
+ self.process_vote_action(-1)\r
+ self.user.reset_vote_down_count_cache()\r
+\r
+ def cancel_action(self):\r
+ super(VoteDownAction, self).cancel_action()\r
+ self.user.reset_vote_down_count_cache()\r
+\r
+ def describe(self, viewer=None):\r
+ return self.describe_vote(_("voted down"), viewer)\r
+\r
+\r
+class VoteUpCommentAction(VoteUpAction):\r
+ def repute_users(self):\r
+ pass\r
+\r
+ def process_action(self):\r
+ self.process_vote_action(1)\r
+\r
+ def cancel_action(self):\r
+ super(VoteUpAction, self).cancel_action()\r
+\r
+ def describe(self, viewer=None):\r
+ return self.describe_vote(_("liked"), viewer)\r
+\r
+\r
+class FlagAction(ActionProxy):\r
+ def repute_users(self):\r
+ self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED))\r
+\r
+ def process_action(self):\r
+ flag = Flag(user=self.user, node=self.node, action=self, reason=self.extra)\r
+ flag.save()\r
+ self.node.reset_flag_count_cache()\r
+\r
+ if self.node.flag_count == int(settings.FLAG_COUNT_TO_HIDE_POST):\r
+ self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED_3_TIMES))\r
+\r
+ if self.node.flag_count == int(settings.FLAG_COUNT_TO_DELETE_POST):\r
+ self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED_5_TIMES))\r
+ if not self.node.deleted:\r
+ DeleteAction(node=self.node, user=self.user, extra="BYFLAGGED").save()\r
+\r
+ def cancel_action(self):\r
+ self.flag.all()[0].delete()\r
+ self.node.reset_flag_count_cache()\r
+\r
+ @classmethod\r
+ def get_for(cls, user, node):\r
+ try:\r
+ flag = Flag.objects.get(user=user, node=node)\r
+ return flag.reason or _("No reason given")\r
+ except:\r
+ return None\r
+\r
+ def describe(self, viewer=None):\r
+ return _("%(user)s flagged %(post_desc)s: %(reason)s") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'post_desc': self.describe_node(viewer, self.node), 'reason': self.extra\r
+ }\r
+\r
+\r
+class AcceptAnswerAction(ActionProxy):\r
+ def repute_users(self):\r
+ if (self.user == self.node.parent.author) and (not self.user == self.node.author):\r
+ self.repute(self.user, int(settings.REP_GAIN_BY_ACCEPTING))\r
+\r
+ if self.user != self.node.author:\r
+ self.repute(self.node.author, int(settings.REP_GAIN_BY_ACCEPTED))\r
+\r
+ def process_action(self):\r
+ self.node.parent.extra_ref = self.node\r
+ self.node.parent.save()\r
+ self.node.marked = True\r
+ self.node.extra_action = self\r
+ self.node.save()\r
+\r
+ def cancel_action(self):\r
+ self.node.parent.extra_ref = None\r
+ self.node.parent.save()\r
+ self.node.marked = False\r
+ self.node.extra_action = None\r
+ self.node.save()\r
+\r
+ def describe(self, viewer=None):\r
+ answer = self.node\r
+ question = answer.parent\r
+\r
+ if self.user == question.author:\r
+ asker = (self.user == viewer) and _("your") or _("his")\r
+ else:\r
+ asker = self.hyperlink(question.author.get_profile_url(), question.author.username)\r
+\r
+ return _("%(user)s accepted %(answerer)s answer on %(asker)s question %(question)s") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'answerer': self.hyperlink(answer.author.get_profile_url(), self.friendly_username(viewer, answer.author)),\r
+ 'asker': asker,\r
+ 'question': self.hyperlink(question.get_absolute_url(), question.title)\r
+ }\r
+\r
+\r
+class FavoriteAction(ActionProxy):\r
+ def process_action(self):\r
+ self.node.reset_favorite_count_cache()\r
+\r
+ def cancel_action(self):\r
+ self.process_action()\r
+\r
+ def describe(self, viewer=None):\r
+ return _("%(user)s marked %(post_desc)s as favorite") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'post_desc': self.describe_node(viewer, self.node),\r
+ }\r
+\r
+\r
+class DeleteAction(ActionProxy):\r
+ def process_action(self):\r
+ self.node.deleted = self\r
+ self.node.save()\r
+ \r
+ if self.node.node_type == "answer":\r
+ self.node.question.reset_answer_count_cache()\r
+\r
+ def cancel_action(self):\r
+ self.node.deleted = None\r
+ self.node.save()\r
+\r
+ if self.node.node_type == "answer":\r
+ self.node.question.reset_answer_count_cache()\r
+\r
+ def describe(self, viewer=None):\r
+ return _("%(user)s deleted %(post_desc)s: %(reason)s") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'post_desc': self.describe_node(viewer, self.node), 'reason': self.reason(),\r
+ }\r
+\r
+ def reason(self):\r
+ if self.extra != "BYFLAGGED":\r
+ return self.extra\r
+ else:\r
+ return _("flagged by multiple users: ") + "; ".join([f.extra for f in FlagAction.objects.filter(node=self.node)])\r
+\r
+\r
+class QuestionViewAction(DummyActionProxy):\r
+ def __init__(self, question, user):\r
+ self.viewuser = user\r
+ self.question = question\r
+\r
+ def process_action(self):\r
+ self.question.extra_count = F('extra_count') + 1\r
+ self.question.save()\r
--- /dev/null
+from django.utils.html import strip_tags\r
+from django.utils.translation import ugettext as _\r
+from forum.models.action import ActionProxy\r
+from forum.models import Comment, Question, Answer, NodeRevision\r
+\r
+class NodeEditAction(ActionProxy):\r
+ def create_revision_data(self, initial=False, **data):\r
+ revision_data = dict(summary=data.get('summary', (initial and _('Initial revision' or ''))), body=data['text'])\r
+\r
+ if data.get('title', None):\r
+ revision_data['title'] = strip_tags(data['title'].strip())\r
+\r
+ if data.get('tags', None):\r
+ revision_data['tagnames'] = data['tags'].strip()\r
+\r
+ return revision_data\r
+\r
+class AskAction(NodeEditAction):\r
+ def process_data(self, **data):\r
+ question = Question(author=self.user, **self.create_revision_data(True, **data))\r
+ question.save()\r
+ self.node = question\r
+\r
+ def describe(self, viewer=None):\r
+ return _("%(user)s asked %(question)s") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'question': self.hyperlink(self.node.get_absolute_url(), self.node.title)\r
+ }\r
+\r
+class AnswerAction(NodeEditAction):\r
+ def process_data(self, **data):\r
+ answer = Answer(author=self.user, parent=data['question'], **self.create_revision_data(True, **data))\r
+ answer.save()\r
+ self.node = answer\r
+\r
+ def process_action(self):\r
+ self.node.question.reset_answer_count_cache()\r
+\r
+ def describe(self, viewer=None):\r
+ question = self.node.parent\r
+ return _("%(user)s answered %(asker)s %(question)s") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'asker': self.hyperlink(question.author.get_profile_url(), self.friendly_username(viewer, question.author)),\r
+ 'question': self.hyperlink(self.node.get_absolute_url(), question.title)\r
+ }\r
+\r
+class CommentAction(ActionProxy):\r
+ def process_data(self, text='', parent=None):\r
+ comment = Comment(author=self.user, parent=parent, body=text)\r
+ comment.save()\r
+ self.node = comment\r
+\r
+ def describe(self, viewer=None):\r
+ return _("%(user)s commented on %(post_desc)s") % {\r
+ 'user': self.hyperlink(self.node.author.get_profile_url(), self.friendly_username(viewer, self.node.author)),\r
+ 'post_desc': self.describe_node(viewer, self.node.parent)\r
+ }\r
+\r
+class ReviseAction(NodeEditAction):\r
+ def process_data(self, **data):\r
+ revision_data = self.create_revision_data(**data)\r
+ revision = self.node.create_revision(self.user, action=self, **revision_data)\r
+ self.extra = revision.revision\r
+\r
+ def describe(self, viewer=None):\r
+ return _("%(user)s edited %(post_desc)s") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'post_desc': self.describe_node(viewer, self.node)\r
+ }\r
+\r
+class RetagAction(ActionProxy):\r
+ def process_data(self, tagnames=''):\r
+ active = self.node.active_revision\r
+ revision_data = dict(summary=_('Retag'), title=active.title, tagnames=strip_tags(tagnames.strip()), body=active.body)\r
+ self.node.create_revision(self.user, action=self, **revision_data)\r
+\r
+ def describe(self, viewer=None):\r
+ return _("%(user)s retagged %(post_desc)s") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'post_desc': self.describe_node(viewer, self.node)\r
+ }\r
+\r
+class RollbackAction(ActionProxy):\r
+ def process_data(self, activate=None):\r
+ previous = self.node.active_revision\r
+ self.node.activate_revision(self.user, activate, self)\r
+ self.extra = "%d:%d" % (previous.revision, activate.revision)\r
+\r
+ def describe(self, viewer=None):\r
+ revisions = [NodeRevision.objects.get(node=self.node, revision=int(n)) for n in self.extra.split(':')]\r
+\r
+ return _("%(user)s reverted %(post_desc)s from revision %(initial)d (%(initial_sum)s) to revision %(final)d (%(final_sum)s)") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'post_desc': self.describe_node(viewer, self.node),\r
+ 'initial': revisions[0].revision, 'initial_sum': revisions[0].summary,\r
+ 'final': revisions[1].revision, 'final_sum': revisions[1].summary,\r
+ }\r
+\r
+class CloseAction(ActionProxy):\r
+ def process_action(self):\r
+ self.node.extra_action = self\r
+ self.node.marked = True\r
+ self.node.save()\r
+\r
+ def cancel_action(self):\r
+ self.node.extra_action = None\r
+ self.node.marked = False\r
+ self.node.save()\r
+\r
+ def describe(self, viewer=None):\r
+ return _("%(user)s closed %(post_desc)s: %(reason)s") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'post_desc': self.describe_node(viewer, self.node),\r
+ 'reason': self.extra\r
+ }
\ No newline at end of file
--- /dev/null
+from django.utils.translation import ugettext as _\r
+from django.db.models import F\r
+from forum.models.action import ActionProxy\r
+from forum.models import Award\r
+from forum import settings\r
+\r
+class UserJoinsAction(ActionProxy):\r
+ def repute_users(self):\r
+ self.repute(self.user, int(settings.INITIAL_REP))\r
+\r
+class EditProfileAction(ActionProxy):\r
+ pass\r
+\r
+class AwardAction(ActionProxy):\r
+ def process_data(self, badge, trigger):\r
+ self.__dict__['_badge'] = badge\r
+ self.__dict__['_trigger'] = trigger\r
+\r
+ def process_action(self):\r
+ badge = self.__dict__['_badge']\r
+ trigger = self.__dict__['_trigger']\r
+\r
+ award = Award(user=self.user, badge=badge, trigger=trigger, action=self)\r
+ if self.node:\r
+ award.node = self.node\r
+\r
+ award.save()\r
+ award.badge.awarded_count = F('awarded_count') + 1\r
+ award.badge.save()\r
+ self.user.message_set.create(message=_("Congratulations, you have received a badge '%(badge_name)s'. " \\r
+ + u"Check out <a href=\"%(profile_url)s\">your profile</a>.") % dict(badge_name=award.badge.name,\r
+ profile_url=self.user.get_profile_url()))\r
+\r
+ def cancel_action(self):\r
+ award = self.award\r
+ badge = award.badge\r
+ badge.awarded_count = F('awarded_count') - 1\r
+ badge.save()\r
+ award.delete()\r
+\r
+ @classmethod\r
+ def get_for(cls, user, node, badge):\r
+ try:\r
+ award = Award.objects.get(user=user, node=node, badge=badge)\r
+ return award.action\r
+ except:\r
+ return None\r
+\r
+ def describe(self, viewer=None):\r
+ return _("%(user)s was awarded the %(badge_name)s badge") % {\r
+ 'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),\r
+ 'badge_name': self.award.all()[0].badge.name,\r
+ }
\ No newline at end of file
+++ /dev/null
-import datetime\r
-from django.db.models.signals import post_save\r
-from forum.models import *\r
-from forum.models.base import marked_deleted, mark_canceled\r
-from forum.models.node import node_create\r
-from forum.models.answer import answer_accepted\r
-from forum.authentication import user_updated\r
-from forum.const import *\r
-\r
-def record_ask_event(instance, **kwargs):\r
- activity = Activity(user=instance.author, active_at=instance.added_at, content_object=instance, activity_type=TYPE_ACTIVITY_ASK_QUESTION)\r
- activity.save()\r
-\r
-node_create.connect(record_ask_event, sender=Question)\r
-\r
-\r
-def record_answer_event(instance, **kwargs):\r
- activity = Activity(user=instance.author, active_at=instance.added_at, content_object=instance, activity_type=TYPE_ACTIVITY_ANSWER)\r
- activity.save()\r
-\r
-node_create.connect(record_answer_event, sender=Answer)\r
-\r
-\r
-def record_comment_event(instance, **kwargs):\r
- act_type = (instance.content_object.__class__ is Question) and TYPE_ACTIVITY_COMMENT_QUESTION or TYPE_ACTIVITY_COMMENT_ANSWER\r
- activity = Activity(user=instance.user, active_at=instance.added_at, content_object=instance, activity_type=act_type)\r
- activity.save()\r
-\r
-node_create.connect(record_comment_event, sender=Comment)\r
-\r
-\r
-def record_revision_event(instance, created, **kwargs):\r
- if created and instance.revision <> 1 and instance.node.node_type in ('question', 'answer',):\r
- activity_type = instance.node.node_type == 'question' and TYPE_ACTIVITY_UPDATE_QUESTION or TYPE_ACTIVITY_UPDATE_ANSWER\r
- activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=activity_type)\r
- activity.save()\r
-\r
-post_save.connect(record_revision_event, sender=NodeRevision)\r
-\r
-\r
-def record_award_event(instance, created, **kwargs):\r
- if created:\r
- activity = Activity(user=instance.user, active_at=instance.awarded_at, content_object=instance,\r
- activity_type=TYPE_ACTIVITY_PRIZE)\r
- activity.save()\r
-\r
-post_save.connect(record_award_event, sender=Award)\r
-\r
-\r
-def record_answer_accepted(answer, user, **kwargs):\r
- activity = Activity(user=user, active_at=datetime.datetime.now(), content_object=answer, activity_type=TYPE_ACTIVITY_MARK_ANSWER)\r
- activity.save()\r
-\r
-answer_accepted.connect(record_answer_accepted)\r
-\r
-\r
-def update_last_seen(instance, **kwargs):\r
- user = instance.user\r
- user.last_seen = datetime.datetime.now()\r
- user.save()\r
-\r
-post_save.connect(update_last_seen, sender=Activity)\r
-\r
-\r
-def record_vote(instance, created, **kwargs):\r
- if created:\r
- act_type = (instance.vote == 1) and TYPE_ACTIVITY_VOTE_UP or TYPE_ACTIVITY_VOTE_DOWN\r
-\r
- activity = Activity(user=instance.user, active_at=instance.voted_at, content_object=instance, activity_type=act_type)\r
- activity.save()\r
-\r
-post_save.connect(record_vote, sender=Vote)\r
-\r
-\r
-def record_cancel_vote(instance, **kwargs):\r
- act_type = (instance.vote == 1) and TYPE_ACTIVITY_CANCEL_VOTE_UP or TYPE_ACTIVITY_CANCEL_VOTE_DOWN\r
- activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=act_type)\r
- activity.save()\r
-\r
-mark_canceled.connect(record_cancel_vote, sender=Vote)\r
-\r
-\r
-def record_delete_post(instance, **kwargs):\r
- act_type = (instance.__class__ is Question) and TYPE_ACTIVITY_DELETE_QUESTION or TYPE_ACTIVITY_DELETE_ANSWER\r
- activity = Activity(user=instance.deleted_by, active_at=datetime.datetime.now(), content_object=instance, activity_type=act_type)\r
- activity.save()\r
-\r
-marked_deleted.connect(record_delete_post, sender=Question)\r
-marked_deleted.connect(record_delete_post, sender=Answer)\r
-\r
-\r
-def record_update_tags(instance, created, **kwargs):\r
- if not created and 'tagnames' in instance.get_dirty_fields():\r
- activity = Activity(user=instance.author, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_TAGS)\r
- activity.save()\r
-\r
-post_save.connect(record_update_tags, sender=Question)\r
-\r
-\r
-def record_mark_offensive(instance, created, **kwargs):\r
- if created:\r
- activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance.content_object, activity_type=TYPE_ACTIVITY_MARK_OFFENSIVE)\r
- activity.save()\r
-\r
-post_save.connect(record_mark_offensive, sender=FlaggedItem)\r
-\r
-\r
-def record_favorite_question(instance, created, **kwargs):\r
- if created:\r
- activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_FAVORITE)\r
- activity.save()\r
-\r
-post_save.connect(record_favorite_question, sender=FavoriteQuestion)\r
-\r
-\r
-def record_user_full_updated(instance, **kwargs):\r
- activity = Activity(user=instance, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_USER_FULL_UPDATED)\r
- activity.save()\r
-\r
-user_updated.connect(record_user_full_updated, sender=User)\r
-\r
class AnonymousQuestionAdmin(admin.ModelAdmin):
"""AnonymousQuestion admin class"""
-class QuestionAdmin(admin.ModelAdmin):
+class NodeAdmin(admin.ModelAdmin):
"""Question admin class"""
class TagAdmin(admin.ModelAdmin):
class ReputeAdmin(admin.ModelAdmin):
""" admin class"""
-class ActivityAdmin(admin.ModelAdmin):
+class ActionAdmin(admin.ModelAdmin):
""" admin class"""
#class BookAdmin(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)
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):
#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
-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')
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
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
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)
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
# Adding field 'Question.accepted_answer'\r
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)\r
\r
- if db.backend_name == "postgres" and not "pgfulltext" in settings.DISABLED_MODULES:\r
- pass\r
- db.execute("DROP TRIGGER tsvectorupdate ON question;")\r
- db.execute("ALTER TABLE question DROP COLUMN tsv;")\r
+ #if db.backend_name == "postgres" and not "pgfulltext" in settings.DISABLED_MODULES:\r
+ # db.execute("DROP TRIGGER tsvectorupdate ON question;")\r
+ # db.execute("ALTER TABLE question DROP COLUMN tsv;")\r
\r
def backwards(self, orm):\r
\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+ \r
+ def forwards(self, orm):\r
+ \r
+ print "# Adding model 'ActionRepute'"\r
+ db.create_table('forum_actionrepute', (\r
+ ('action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reputes', to=orm['forum.Action'])),\r
+ ('by_canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+ ('value', self.gf('django.db.models.fields.IntegerField')(default=0)),\r
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'])),\r
+ ))\r
+ db.send_create_signal('forum', ['ActionRepute'])\r
+\r
+ print "# Adding model 'Action'"\r
+ db.create_table('forum_action', (\r
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True)),\r
+ ('extra', self.gf('django.db.models.fields.CharField')(max_length=255)),\r
+ ('canceled_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='canceled_actions', null=True, to=orm['forum.User'])),\r
+ ('canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ('action_date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='actions', to=orm['forum.User'])),\r
+ ('action_type', self.gf('django.db.models.fields.CharField')(max_length=16)),\r
+ ('canceled_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),\r
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+ ('ip', self.gf('django.db.models.fields.CharField')(max_length=16, null=True)),\r
+ ))\r
+ db.send_create_signal('forum', ['Action'])\r
+\r
+ print "# Deleting field 'Node.vote_up_count'"\r
+ db.delete_column('forum_node', 'vote_up_count')\r
+\r
+ print "# Deleting field 'Node.comment_count'"\r
+ db.delete_column('forum_node', 'comment_count')\r
+\r
+ print "# Deleting field 'Node.offensive_flag_count'"\r
+ db.delete_column('forum_node', 'offensive_flag_count')\r
+\r
+ print "# Deleting field 'Node.vote_down_count'"\r
+ db.delete_column('forum_node', 'vote_down_count')\r
+\r
+ print "# Adding field 'Node.wiki'"\r
+ db.add_column('forum_node', 'wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+ print "# Adding field 'Node.marked'"\r
+ db.add_column('forum_node', 'marked', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+ print "# Adding field 'Node.extra_count'"\r
+ db.add_column('forum_node', 'extra_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+ print "# Adding field 'Node.last_activity_by'"\r
+ 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)\r
+\r
+ print "# Adding field 'Node.extra_ref'"\r
+ db.add_column('forum_node', 'extra_ref', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True), keep_default=False)\r
+\r
+ print "# Adding field 'Node.last_activity_at'"\r
+ db.add_column('forum_node', 'last_activity_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)\r
+\r
+ # Changing field 'Answer.node_ptr'\r
+ #db.alter_column(u'answer', 'node_ptr_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True, primary_key=True))\r
+\r
+ print "# Changing field 'QuestionSubscription.question'"\r
+ db.alter_column('forum_questionsubscription', 'question_id', self.gf('django.db.models.fields.IntegerField')())\r
+\r
+ # Removing unique constraint on 'Award', fields ['badge', 'object_id', 'content_type', 'user']\r
+ #db.delete_unique(u'award', ['badge_id', 'object_id', 'content_type_id', 'user_id'])\r
+\r
+ print "# Changing field 'User.gold'"\r
+ db.alter_column('forum_user', 'gold', self.gf('django.db.models.fields.PositiveIntegerField')())\r
+\r
+ print "# Changing field 'User.silver'"\r
+ db.alter_column('forum_user', 'silver', self.gf('django.db.models.fields.PositiveIntegerField')())\r
+\r
+ print "# Changing field 'User.bronze'"\r
+ db.alter_column('forum_user', 'bronze', self.gf('django.db.models.fields.PositiveIntegerField')())\r
+\r
+ print "# Deleting field 'Question.answer_count'"\r
+ db.delete_column(u'question', 'answer_count')\r
+\r
+ print "# Deleting field 'Question.favourite_count'"\r
+ db.delete_column(u'question', 'favourite_count')\r
+\r
+ # Changing field 'Question.node_ptr'\r
+ #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))\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ \r
+ # Deleting model 'ActionRepute'\r
+ db.delete_table('forum_actionrepute')\r
+\r
+ # Deleting model 'Action'\r
+ db.delete_table('forum_action')\r
+\r
+ # Deleting model 'FavoriteNode'\r
+ db.delete_table('forum_favoritenode')\r
+\r
+ # Adding field 'Node.vote_up_count'\r
+ db.add_column('forum_node', 'vote_up_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+ # Adding field 'Node.comment_count'\r
+ db.add_column('forum_node', 'comment_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0), keep_default=False)\r
+\r
+ # Adding field 'Node.offensive_flag_count'\r
+ db.add_column('forum_node', 'offensive_flag_count', self.gf('django.db.models.fields.SmallIntegerField')(default=0), keep_default=False)\r
+\r
+ # Adding field 'Node.vote_down_count'\r
+ db.add_column('forum_node', 'vote_down_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+ # Deleting field 'Node.wiki'\r
+ db.delete_column('forum_node', 'wiki')\r
+\r
+ # Deleting field 'Node.marked'\r
+ db.delete_column('forum_node', 'marked')\r
+\r
+ # Deleting field 'Node.extra_count'\r
+ db.delete_column('forum_node', 'extra_count')\r
+\r
+ # Deleting field 'Node.last_activity_by'\r
+ db.delete_column('forum_node', 'last_activity_by_id')\r
+\r
+ # Deleting field 'Node.extra_ref'\r
+ db.delete_column('forum_node', 'extra_ref_id')\r
+\r
+ # Deleting field 'Node.last_activity_at'\r
+ db.delete_column('forum_node', 'last_activity_at')\r
+\r
+ # Changing field 'Answer.node_ptr'\r
+ db.alter_column(u'answer', 'node_ptr_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True, primary_key=True))\r
+\r
+ # Adding unique constraint on 'Award', fields ['badge', 'object_id', 'content_type', 'user']\r
+ db.create_unique(u'award', ['badge_id', 'object_id', 'content_type_id', 'user_id'])\r
+\r
+ # Changing field 'User.gold'\r
+ db.alter_column('forum_user', 'gold', self.gf('django.db.models.fields.SmallIntegerField')())\r
+\r
+ # Changing field 'User.silver'\r
+ db.alter_column('forum_user', 'silver', self.gf('django.db.models.fields.SmallIntegerField')())\r
+\r
+ # Changing field 'User.bronze'\r
+ db.alter_column('forum_user', 'bronze', self.gf('django.db.models.fields.SmallIntegerField')())\r
+\r
+ # Adding field 'Question.answer_count'\r
+ db.add_column(u'question', 'answer_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0), keep_default=False)\r
+\r
+ # Adding field 'Question.favourite_count'\r
+ db.add_column(u'question', 'favourite_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False)\r
+\r
+ # Changing field 'Question.node_ptr'\r
+ db.alter_column(u'question', 'node_ptr_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True))\r
+ \r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.activity': {\r
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.anonymousnode': {\r
+ 'Meta': {'object_name': 'AnonymousNode', '_ormbases': ['forum.Node']},\r
+ 'convertible_to': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'validation_hash': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_content'", 'to': "orm['forum.Node']"})\r
+ },\r
+ 'forum.answer': {\r
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.favoritequestion': {\r
+ 'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'favourites'", 'to': "orm['forum.Question']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.flaggeditem': {\r
+ 'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.question': {\r
+ 'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+ 'accepted_answer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'question_accepting'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Answer']"}),\r
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),\r
+ 'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 27, 11, 37, 29, 356000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.repute': {\r
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 11, 37, 29, 624000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.vote': {\r
+ 'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import DataMigration\r
+from django.db import models\r
+from forum.migrations import ProgressBar\r
+\r
+GAIN_BY_UPVOTED = 1\r
+GAIN_BY_ANSWER_ACCEPTED = 2\r
+GAIN_BY_ACCEPTING_ANSWER = 3\r
+GAIN_BY_DOWNVOTE_CANCELED = 4\r
+GAIN_BY_CANCELING_DOWNVOTE = 5\r
+LOST_BY_CANCELLING_ACCEPTED_ANSWER = -1\r
+LOST_BY_ACCEPTED_ANSWER_CANCELED = -2\r
+LOST_BY_DOWNVOTED = -3\r
+LOST_BY_FLAGGED = -4\r
+LOST_BY_DOWNVOTING = -5\r
+LOST_BY_FLAGGED_3_TIMES = -6\r
+LOST_BY_FLAGGED_5_TIMES = -7\r
+LOST_BY_UPVOTE_CANCELED = -8\r
+\r
+class Migration(DataMigration):\r
+ \r
+ def forwards(self, orm):\r
+ rephist = dict([(t, []) for t in range(-8, 6) if t != 0])\r
+\r
+ r_count = orm.Repute.objects.count()\r
+ print "\nCalculating rep gain/losses history through %d records:" % r_count\r
+ progress = ProgressBar(r_count)\r
+\r
+ for r in orm.Repute.objects.all():\r
+ l = rephist.get(r.reputation_type, None)\r
+ if l is None: continue\r
+\r
+ if (len(l) == 0) or (l[-1][1] != r.value):\r
+ l.append((r.reputed_at, r.value))\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+\r
+ def repval_at(reptype, repdate, default):\r
+ l = rephist.get(reptype, None)\r
+\r
+ if l is None: return 0\r
+ if len(l) == 0: return default\r
+\r
+ for r in l:\r
+ if r[0] <= repdate:\r
+ return r[1] or default\r
+\r
+\r
+ q_count = orm.Question.objects.count()\r
+ print "\nConverting %d questions:" % q_count\r
+ progress = ProgressBar(q_count)\r
+\r
+ for q in orm.Question.objects.all():\r
+ n = q.node_ptr\r
+ n.last_activity_at = q.last_activity_at\r
+ n.last_activity_by = q.last_activity_by\r
+\r
+ if q.accepted_answer:\r
+ n.extra_ref = q.accepted_answer.node_ptr\r
+ \r
+ n.extra_count = q.view_count\r
+\r
+ n.marked = q.closed\r
+ n.wiki = q.wiki\r
+\r
+ n.save()\r
+\r
+ ask = orm.Action(\r
+ user = n.author,\r
+ action_date = n.added_at,\r
+ node = n,\r
+ action_type = "ask",\r
+ extra = ''\r
+ )\r
+\r
+ ask.save()\r
+\r
+ if n.deleted:\r
+ action = orm.Action(\r
+ user = n.deleted_by,\r
+ node = n,\r
+ action_type = "delete",\r
+ action_date = n.deleted_at or datetime.datetime.now(),\r
+ extra = ''\r
+ )\r
+\r
+ action.save()\r
+\r
+\r
+ if n.marked:\r
+ action = orm.Action(\r
+ user = q.closed_by,\r
+ node = n,\r
+ action_type = "close",\r
+ extra = q.close_reason,\r
+ action_date = q.closed_at or datetime.datetime.now(),\r
+ )\r
+\r
+ action.save()\r
+\r
+ if n.wiki:\r
+ action = orm.Action(\r
+ user = n.author,\r
+ node = n,\r
+ action_type = "wikify",\r
+ action_date = q.wikified_at or datetime.datetime.now(),\r
+ extra = ''\r
+ )\r
+\r
+ action.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ a_count = orm.Answer.objects.count()\r
+ print "\nConverting %d answers:" % a_count\r
+ progress = ProgressBar(a_count)\r
+\r
+ for a in orm.Answer.objects.all():\r
+ n = a.node_ptr\r
+\r
+ n.marked = a.accepted\r
+ n.wiki = a.wiki\r
+\r
+ n.save()\r
+\r
+ ans = orm.Action(\r
+ user = n.author,\r
+ action_date = n.added_at,\r
+ node = n,\r
+ action_type = "answer",\r
+ extra = ''\r
+ )\r
+\r
+ ans.save()\r
+\r
+ if n.deleted:\r
+ action = orm.Action(\r
+ user = n.deleted_by,\r
+ node = n,\r
+ action_type = "delete",\r
+ action_date = n.deleted_at or datetime.datetime.now(),\r
+ extra = ''\r
+ )\r
+\r
+ action.save()\r
+\r
+ if a.accepted:\r
+ action = orm.Action(\r
+ user = a.accepted_by,\r
+ node = n,\r
+ action_type = "acceptanswer",\r
+ action_date = a.accepted_at or datetime.datetime.now(),\r
+ extra = ''\r
+ )\r
+\r
+ action.save()\r
+\r
+ if not a.wiki or a.wikified_at > action.action_date:\r
+ if action.user == n.author:\r
+ rep = orm.ActionRepute(\r
+ action = action,\r
+ user = action.user,\r
+ value = repval_at(GAIN_BY_ACCEPTING_ANSWER, action.action_date, 2)\r
+ )\r
+ rep.save()\r
+\r
+ if n.author != n.parent.author:\r
+ rep = orm.ActionRepute(\r
+ action = action,\r
+ user = n.author,\r
+ value = repval_at(GAIN_BY_ANSWER_ACCEPTED, action.action_date, 15)\r
+ )\r
+ rep.save()\r
+\r
+ if n.wiki:\r
+ action = orm.Action(\r
+ user = n.author,\r
+ node = n,\r
+ action_type = "wikify",\r
+ action_date = a.wikified_at or datetime.datetime.now(),\r
+ extra = ''\r
+ )\r
+\r
+ action.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ v_count = orm.Vote.objects.count()\r
+ print "\nConverting %d votes:" % v_count\r
+ progress = ProgressBar(v_count)\r
+\r
+ for v in orm.Vote.objects.exclude(canceled=True):\r
+ a = orm.Action(\r
+ action_type = (v.vote == 1) and ((v.node.node_type == "comment") and "voteupcomment" or "voteup") or "votedown",\r
+ user = v.user,\r
+ node = v.node,\r
+ action_date = v.voted_at,\r
+ canceled = v.canceled,\r
+ extra = ''\r
+ )\r
+\r
+ a.save()\r
+\r
+ def impl(node):\r
+ if node.node_type == "question":\r
+ return orm.Question.objects.get(node_ptr=node)\r
+ else:\r
+ return orm.Answer.objects.get(node_ptr=node)\r
+\r
+ if a.node.node_type in ("question", "answer") and (not a.node.wiki or impl(a.node).wikified_at > a.action_date):\r
+ reptype, default = (v.vote == 1) and (GAIN_BY_UPVOTED, 10) or (LOST_BY_DOWNVOTED, 2)\r
+ rep = orm.ActionRepute(\r
+ action = a,\r
+ user = a.node.author,\r
+ value = repval_at(reptype, a.action_date, default) or default\r
+ )\r
+ rep.save()\r
+\r
+ if v.vote == -1:\r
+ rep = orm.ActionRepute(\r
+ action = a,\r
+ user = a.node.author,\r
+ value = repval_at(LOST_BY_DOWNVOTING, a.action_date, 1) or default\r
+ )\r
+ rep.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ f_count = orm.FlaggedItem.objects.count()\r
+ print "\nConverting %d flags:" % f_count\r
+ progress = ProgressBar(f_count)\r
+\r
+ for f in orm.FlaggedItem.objects.all():\r
+ a = orm.Action(\r
+ action_type = "flag",\r
+ user = f.user,\r
+ node = f.node,\r
+ action_date = f.flagged_at,\r
+ extra = f.reason or ''\r
+ )\r
+\r
+ a.save()\r
+\r
+ rep = orm.ActionRepute(\r
+ action = a,\r
+ user = a.node.author,\r
+ value = repval_at(LOST_BY_FLAGGED, a.action_date, 2) or 2\r
+ )\r
+ rep.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ n_count = orm.Node.objects.all().count()\r
+ print "\nChecking flag count of %d nodes:" % n_count\r
+ progress = ProgressBar(n_count)\r
+\r
+ for n in orm.Node.objects.all():\r
+ flags = list(orm.Action.objects.filter(action_type="flag", node=n, canceled=False).order_by('-action_date'))\r
+\r
+ if len(flags) >= 3:\r
+ a = flags[2]\r
+ rep = orm.ActionRepute(\r
+ action = a,\r
+ user = n.author,\r
+ value = repval_at(LOST_BY_FLAGGED_3_TIMES, a.action_date, 30)\r
+ )\r
+ rep.save()\r
+\r
+\r
+ if len(flags) >= 5:\r
+ a = flags[4]\r
+ rep = orm.ActionRepute(\r
+ action = a,\r
+ user = n.author,\r
+ value = repval_at(LOST_BY_FLAGGED_5_TIMES, a.action_date, 100)\r
+ )\r
+ rep.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ c_count = orm.Node.objects.filter(node_type="comment").count()\r
+ print "\nCreating %d comment actions:" % c_count\r
+ progress = ProgressBar(c_count)\r
+\r
+ for c in orm.Node.objects.filter(node_type="comment").all():\r
+ a = orm.Action(\r
+ action_type = "comment",\r
+ user = c.author,\r
+ node = c,\r
+ action_date = c.added_at,\r
+ extra = ''\r
+ )\r
+\r
+ a.save()\r
+\r
+ if c.deleted:\r
+ action = orm.Action(\r
+ user = c.deleted_by,\r
+ node = c,\r
+ action_type = "delete",\r
+ action_date = c.deleted_at or datetime.datetime.now(),\r
+ extra = ''\r
+ )\r
+\r
+ action.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+\r
+ r_count = orm.NodeRevision.objects.exclude(revision=1).count()\r
+ print "\nCreating %d edit actions:" % r_count\r
+ progress = ProgressBar(r_count)\r
+\r
+ for r in orm.NodeRevision.objects.exclude(revision=1):\r
+ a = orm.Action(\r
+ action_type = "revise",\r
+ user = r.author,\r
+ node = r.node,\r
+ action_date = r.revised_at,\r
+ extra = r.revision\r
+ )\r
+\r
+ a.save()\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ u_count = orm.User.objects.all().count()\r
+ print "\nCreating %d user join actions and reputation recalculation:" % u_count\r
+ progress = ProgressBar(u_count)\r
+\r
+ for u in orm.User.objects.all():\r
+ a = orm.Action(\r
+ user = u,\r
+ action_date = u.date_joined,\r
+ action_type = "userjoins",\r
+ )\r
+\r
+ a.save()\r
+\r
+ rep = orm.ActionRepute(\r
+ action = a,\r
+ user = u,\r
+ value = 1\r
+ )\r
+ rep.save()\r
+\r
+ new_rep = orm.ActionRepute.objects.filter(user=u).aggregate(reputation=models.Sum('value'))['reputation']\r
+\r
+ if new_rep < 0:\r
+ new_rep = 1\r
+\r
+ u.reputation = new_rep\r
+ u.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ "Write your backwards methods here."\r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.activity': {\r
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.anonymousnode': {\r
+ 'Meta': {'object_name': 'AnonymousNode', '_ormbases': ['forum.Node']},\r
+ 'convertible_to': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'node_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['forum.Node']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'validation_hash': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_content'", 'to': "orm['forum.Node']"})\r
+ },\r
+ 'forum.answer': {\r
+ 'Meta': {'object_name': 'Answer', 'db_table': "u'answer'"},\r
+ 'accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'accepted_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.favoritequestion': {\r
+ 'Meta': {'unique_together': "(('question', 'user'),)", 'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'favourites'", 'to': "orm['forum.Question']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.flaggeditem': {\r
+ 'Meta': {'object_name': 'FlaggedItem', 'db_table': "u'flagged_item'"},\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flaggeditems'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_nodes'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.question': {\r
+ 'Meta': {'object_name': 'Question', 'db_table': "u'question'"},\r
+ 'accepted_answer': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'question_accepting'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Answer']"}),\r
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'closed_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'favorite_questions'", 'through': "'FavoriteQuestion'", 'to': "orm['forum.User']"}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'last_active_in_questions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'node_ptr': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True', 'primary_key': 'True'}),\r
+ 'view_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 27, 11, 40, 32, 68000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.repute': {\r
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Question']"}),\r
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'user_previous_rep': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 11, 40, 32, 153000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.vote': {\r
+ 'Meta': {'object_name': 'Vote', 'db_table': "u'vote'"},\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['forum.User']"}),\r
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+ \r
+ def forwards(self, orm):\r
+ \r
+ # Deleting model 'Repute'\r
+ db.delete_table(u'repute')\r
+\r
+ # Deleting model 'Vote'\r
+ db.delete_table(u'vote')\r
+\r
+ # Deleting model 'Answer'\r
+ db.delete_table(u'answer')\r
+\r
+ # Deleting model 'FlaggedItem'\r
+ db.delete_table(u'flagged_item')\r
+\r
+ # Deleting model 'AnonymousNode'\r
+ db.delete_table('forum_anonymousnode')\r
+\r
+ # Deleting model 'FavoriteQuestion'\r
+ db.delete_table(u'favorite_question')\r
+\r
+ # Deleting model 'Question'\r
+ db.delete_table(u'question')\r
+\r
+ # Deleting field 'Node.deleted_at'\r
+ db.delete_column('forum_node', 'deleted_at')\r
+\r
+ # Deleting field 'Node.last_edited_by'\r
+ db.delete_column('forum_node', 'last_edited_by_id')\r
+\r
+ # Deleting field 'Node.deleted'\r
+ db.delete_column('forum_node', 'deleted')\r
+\r
+ # Deleting field 'Node.deleted_by'\r
+ db.delete_column('forum_node', 'deleted_by_id')\r
+\r
+ # Deleting field 'Node.last_edited_at'\r
+ db.delete_column('forum_node', 'last_edited_at')\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ \r
+ # Adding model 'Repute'\r
+ db.create_table(u'repute', (\r
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reputes', null=True, to=orm['forum.Node'])),\r
+ ('reputed_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Question'])),\r
+ ('value', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),\r
+ ('canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ('reputation_type', self.gf('django.db.models.fields.SmallIntegerField')()),\r
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reputes', to=orm['forum.User'])),\r
+ ('user_previous_rep', self.gf('django.db.models.fields.IntegerField')(default=0)),\r
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+ ))\r
+ db.send_create_signal('forum', ['Repute'])\r
+\r
+ # Adding model 'Vote'\r
+ db.create_table(u'vote', (\r
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='votes', null=True, to=orm['forum.Node'])),\r
+ ('vote', self.gf('django.db.models.fields.SmallIntegerField')()),\r
+ ('canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='votes', to=orm['forum.User'])),\r
+ ('voted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+ ))\r
+ db.send_create_signal('forum', ['Vote'])\r
+\r
+ # Adding model 'Answer'\r
+ db.create_table(u'answer', (\r
+ ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ('accepted_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'], null=True)),\r
+ ('accepted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),\r
+ ('wikified_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),\r
+ ('node_ptr', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True, primary_key=True)),\r
+ ('accepted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ))\r
+ db.send_create_signal('forum', ['Answer'])\r
+\r
+ # Adding model 'FlaggedItem'\r
+ db.create_table(u'flagged_item', (\r
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(related_name='flaggeditems', null=True, to=orm['forum.Node'])),\r
+ ('flagged_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+ ('canceled', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ('reason', self.gf('django.db.models.fields.CharField')(max_length=300, null=True)),\r
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='flaggeditems', to=orm['forum.User'])),\r
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+ ))\r
+ db.send_create_signal('forum', ['FlaggedItem'])\r
+\r
+ # Adding model 'AnonymousNode'\r
+ db.create_table('forum_anonymousnode', (\r
+ ('convertible_to', self.gf('django.db.models.fields.CharField')(default='node', max_length=16)),\r
+ ('validation_hash', self.gf('django.db.models.fields.related.ForeignKey')(related_name='anonymous_content', to=orm['forum.Node'])),\r
+ ('node_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['forum.Node'], unique=True, primary_key=True)),\r
+ ))\r
+ db.send_create_signal('forum', ['AnonymousNode'])\r
+\r
+ # Adding model 'FavoriteQuestion'\r
+ db.create_table(u'favorite_question', (\r
+ ('question', self.gf('django.db.models.fields.related.ForeignKey')(related_name='favourites', to=orm['forum.Question'])),\r
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+ ('added_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='user_favorite_questions', to=orm['forum.User'])),\r
+ ))\r
+ db.send_create_signal('forum', ['FavoriteQuestion'])\r
+\r
+ # Adding model 'Question'\r
+ db.create_table(u'question', (\r
+ ('wiki', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ('last_activity_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='last_active_in_questions', null=True, to=orm['forum.User'])),\r
+ ('close_reason', self.gf('django.db.models.fields.SmallIntegerField')(null=True, blank=True)),\r
+ ('last_activity_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+ ('view_count', self.gf('django.db.models.fields.IntegerField')(default=0)),\r
+ ('node_ptr', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'], null=True, primary_key=True)),\r
+ ('accepted_answer', self.gf('django.db.models.fields.related.OneToOneField')(related_name='question_accepting', unique=True, null=True, to=orm['forum.Answer'])),\r
+ ('closed', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ('wikified_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),\r
+ ('closed_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),\r
+ ('closed_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='closed_questions', null=True, to=orm['forum.User'], blank=True)),\r
+ ))\r
+ db.send_create_signal('forum', ['Question'])\r
+\r
+ # Adding field 'Node.deleted_at'\r
+ db.add_column('forum_node', 'deleted_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)\r
+\r
+ # Adding field 'Node.last_edited_by'\r
+ 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)\r
+\r
+ # Adding field 'Node.deleted'\r
+ db.add_column('forum_node', 'deleted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+ # Adding field 'Node.deleted_by'\r
+ 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)\r
+\r
+ # Adding field 'Node.last_edited_at'\r
+ db.add_column('forum_node', 'last_edited_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False)\r
+ \r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.activity': {\r
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 23, 43, 52, 301000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 23, 43, 52, 512000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+ \r
+ def forwards(self, orm):\r
+ \r
+ # Adding field 'Node.extra_action'\r
+ db.add_column('forum_node', 'extra_action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='extra_node', null=True, to=orm['forum.Action']), keep_default=False)\r
+\r
+ # Adding field 'Node.deleted'\r
+ db.add_column('forum_node', 'deleted', self.gf('django.db.models.fields.related.ForeignKey')(related_name='deleted_node', unique=True, null=True, to=orm['forum.Action']), keep_default=False)\r
+\r
+ # Adding field 'Node.last_edited'\r
+ 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)\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ \r
+ # Deleting field 'Node.extra_action'\r
+ db.delete_column('forum_node', 'extra_action_id')\r
+\r
+ # Deleting field 'Node.deleted'\r
+ db.delete_column('forum_node', 'deleted_id')\r
+\r
+ # Deleting field 'Node.last_edited'\r
+ db.delete_column('forum_node', 'last_edited_id')\r
+ \r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.activity': {\r
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 23, 49, 37, 322000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 23, 49, 37, 506000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import DataMigration\r
+from django.db import models\r
+from forum.migrations import ProgressBar\r
+\r
+class Migration(DataMigration):\r
+ \r
+ def forwards(self, orm):\r
+ n_count = orm.Node.objects.all().count()\r
+ print "\nReseting %d nodes:" % n_count\r
+ progress = ProgressBar(n_count)\r
+\r
+ for n in orm.Node.objects.all():\r
+ try:\r
+ d = orm.Action.objects.get(node=n, action_type="delete", canceled=False)\r
+ n.deleted_id = d.id\r
+ except Exception, e:\r
+ n.deleted = None\r
+\r
+ if orm.Action.objects.filter(node=n, action_type="revise").count() > 0:\r
+ n.last_edited_id = orm.Action.objects.filter(node=n, action_type="revise").order_by('-action_date')[0].id\r
+ else:\r
+ n.last_edited = None\r
+\r
+\r
+ if n.node_type == "answer" and n.marked:\r
+ n.extra_action_id = orm.Action.objects.get(node=n, action_type="acceptanswer", canceled=False).id\r
+\r
+ if n.node_type == "question" and n.marked:\r
+ n.extra_action_id = orm.Action.objects.get(node=n, action_type="close", canceled=False).id\r
+\r
+ n.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ "Write your backwards methods here."\r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.activity': {\r
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},\r
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 28, 23, 55, 36, 647000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 23, 55, 36, 708000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+ \r
+ def forwards(self, orm):\r
+ \r
+ # Deleting model 'Activity'\r
+ db.delete_table(u'activity')\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ \r
+ # Adding model 'Activity'\r
+ db.create_table(u'activity', (\r
+ ('is_auditted', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)),\r
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),\r
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'])),\r
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),\r
+ ('active_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+ ('activity_type', self.gf('django.db.models.fields.SmallIntegerField')()),\r
+ ))\r
+ db.send_create_signal('forum', ['Activity'])\r
+ \r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 1, 30, 30, 35000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 30, 1, 30, 30, 211000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+ \r
+ def forwards(self, orm):\r
+ \r
+ # Adding field 'Action.canceled_ip'\r
+ db.add_column('forum_action', 'canceled_ip', self.gf('django.db.models.fields.CharField')(default='', max_length=16), keep_default=False)\r
+\r
+ # Adding field 'ActionRepute.date'\r
+ db.add_column('forum_actionrepute', 'date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now), keep_default=False)\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ \r
+ # Deleting field 'Action.canceled_ip'\r
+ db.delete_column('forum_action', 'canceled_ip')\r
+\r
+ # Deleting field 'ActionRepute.date'\r
+ db.delete_column('forum_actionrepute', 'date')\r
+ \r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 21, 20, 24, 880000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 30, 21, 20, 35, 361000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import DataMigration\r
+from django.db import models\r
+from forum.migrations import ProgressBar\r
+\r
+class Migration(DataMigration):\r
+ \r
+ def forwards(self, orm):\r
+ r_count = orm.ActionRepute.objects.count()\r
+ print "\nAdding dates to %d repute actions:" % r_count\r
+ progress = ProgressBar(r_count)\r
+\r
+ for r in orm.ActionRepute.objects.all():\r
+ a = r.action\r
+\r
+ if r.by_canceled:\r
+ r.date = a.canceled_at\r
+ else:\r
+ r.date = a.action_date\r
+\r
+ r.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ "Write your backwards methods here."\r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'extra': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 29, 21, 21, 16, 237000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 30, 21, 21, 16, 298000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+ \r
+ def forwards(self, orm):\r
+ \r
+ # Changing field 'Action.extra'\r
+ db.alter_column('forum_action', 'extra', self.gf('forum.models.utils.PickledObjectField')(null=True))\r
+\r
+ # Changing field 'KeyValue.value'\r
+ db.alter_column('forum_keyvalue', 'value', self.gf('forum.models.utils.PickledObjectField')(null=True))\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ \r
+ # Changing field 'Action.extra'\r
+ db.alter_column('forum_action', 'extra', self.gf('django.db.models.fields.CharField')(max_length=255))\r
+\r
+ # Changing field 'KeyValue.value'\r
+ db.alter_column('forum_keyvalue', 'value', self.gf('forum.models.utils.PickledObjectField')())\r
+ \r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 4, 30, 23, 58, 8, 677000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 1, 23, 58, 8, 841000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import DataMigration\r
+from django.db import models\r
+from forum.migrations import ProgressBar\r
+from forum.models.utils import dbsafe_encode\r
+\r
+try:\r
+ from cPickle import loads, dumps\r
+except ImportError:\r
+ from pickle import loads, dumps\r
+\r
+class Migration(DataMigration):\r
+ \r
+ def forwards(self, orm):\r
+ k_count = orm.KeyValue.objects.count()\r
+ print "\nConverting %d keyvalue objects:" % k_count\r
+ progress = ProgressBar(k_count)\r
+\r
+ for kv in orm.KeyValue.objects.all():\r
+ try:\r
+ o = loads(kv.value.encode('utf-8'))\r
+ except:\r
+ o = kv.value\r
+\r
+ kv.value = dbsafe_encode(o, compress_object=True)\r
+ kv.save()\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ a_count = orm.Action.objects.count()\r
+ print "\nConverting %d actions extra fields:" % a_count\r
+ progress = ProgressBar(a_count)\r
+\r
+ for a in orm.Action.objects.all():\r
+ a.extra = dbsafe_encode(a.extra, compress_object=True)\r
+ a.save()\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ "Write your backwards methods here."\r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 1, 0, 0, 32, 37000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'hide_ignored_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 2, 0, 0, 32, 86000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+ \r
+ def forwards(self, orm):\r
+ \r
+ # Deleting field 'User.hide_ignored_questions'\r
+ db.delete_column('forum_user', 'hide_ignored_questions')\r
+\r
+ # Deleting field 'User.questions_per_page'\r
+ db.delete_column('forum_user', 'questions_per_page')\r
+\r
+ # Deleting field 'User.email_key'\r
+ db.delete_column('forum_user', 'email_key')\r
+\r
+ # Adding field 'Node.in_moderation'\r
+ db.add_column('forum_node', 'in_moderation', self.gf('django.db.models.fields.related.ForeignKey')(related_name='moderated_node', unique=True, null=True, to=orm['forum.Action']), keep_default=False)\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ \r
+ # Adding field 'User.hide_ignored_questions'\r
+ db.add_column('forum_user', 'hide_ignored_questions', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+ # Adding field 'User.questions_per_page'\r
+ db.add_column('forum_user', 'questions_per_page', self.gf('django.db.models.fields.SmallIntegerField')(default=10), keep_default=False)\r
+\r
+ # Adding field 'User.email_key'\r
+ db.add_column('forum_user', 'email_key', self.gf('django.db.models.fields.CharField')(max_length=32, null=True), keep_default=False)\r
+\r
+ # Deleting field 'Node.in_moderation'\r
+ db.delete_column('forum_node', 'in_moderation_id')\r
+ \r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'unique_together': "(('name', 'type'),)", 'object_name': 'Badge', 'db_table': "u'badge'"},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 2, 4, 54, 13, 72000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag', 'db_table': "u'tag'"},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 3, 4, 54, 13, 256000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+ \r
+ def forwards(self, orm):\r
+ db.rename_table('award', 'forum_award')\r
+ db.rename_table('badge', 'forum_badge')\r
+ db.rename_table('tag', 'forum_tag')\r
+ \r
+ # Adding model 'Flag'\r
+ db.create_table('forum_flag', (\r
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'])),\r
+ ('action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='flag', unique=True, to=orm['forum.Action'])),\r
+ ('reason', self.gf('django.db.models.fields.CharField')(max_length=300)),\r
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'])),\r
+ ('flagged_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+ ))\r
+ #db.send_create_signal('forum', ['Flag'])\r
+\r
+ # Adding model 'Vote'\r
+ db.create_table('forum_vote', (\r
+ ('node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.Node'])),\r
+ ('action', self.gf('django.db.models.fields.related.ForeignKey')(related_name='vote', unique=True, to=orm['forum.Action'])),\r
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),\r
+ ('value', self.gf('django.db.models.fields.SmallIntegerField')()),\r
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['forum.User'])),\r
+ ('voted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),\r
+ ))\r
+ #db.send_create_signal('forum', ['Vote'])\r
+\r
+ # Adding field 'Badge.cls'\r
+ db.add_column('forum_badge', 'cls', self.gf('django.db.models.fields.CharField')(max_length=50, null=True), keep_default=False)\r
+\r
+ # Removing unique constraint on 'Badge', fields ['type', 'name']\r
+ db.delete_unique(u'forum_badge', ['type', 'name'])\r
+\r
+ # Deleting field 'Award.notified'\r
+ db.delete_column(u'forum_award', 'notified')\r
+\r
+ # Adding field 'Award.node'\r
+ 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)\r
+\r
+ # Adding field 'Award.trigger'\r
+ 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)\r
+\r
+ # Adding field 'Award.action'\r
+ 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)\r
+\r
+ # Adding unique constraint on 'Award', fields ['node', 'badge', 'user']\r
+ #db.create_unique('forum_award', ['node_id', 'badge_id', 'user_id'])\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ \r
+ # Deleting model 'Flag'\r
+ db.delete_table('forum_flag')\r
+\r
+ # Deleting model 'Vote'\r
+ db.delete_table('forum_vote')\r
+\r
+ # Deleting field 'Badge.cls'\r
+ db.delete_column('forum_badge', 'cls')\r
+\r
+ # Adding unique constraint on 'Badge', fields ['type', 'name']\r
+ db.create_unique(u'badge', ['type', 'name'])\r
+\r
+ # Adding field 'Award.notified'\r
+ db.add_column(u'award', 'notified', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+ # Deleting field 'Award.node'\r
+ db.delete_column('forum_award', 'node_id')\r
+\r
+ # Deleting field 'Award.trigger'\r
+ db.delete_column('forum_award', 'trigger_id')\r
+\r
+ # Deleting field 'Award.action'\r
+ db.delete_column('forum_award', 'action_id')\r
+\r
+ # Removing unique constraint on 'Award', fields ['node', 'badge', 'user']\r
+ db.delete_unique('forum_award', ['node_id', 'badge_id', 'user_id'])\r
+ \r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'unique_together': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award'", 'to': "orm['forum.Action']"}),\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'object_name': 'Badge'},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.flag': {\r
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 3, 11, 41, 55, 831000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag'},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 4, 11, 41, 59, 140000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.vote': {\r
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import DataMigration\r
+from django.db import models\r
+from forum.migrations import ProgressBar\r
+from forum.models.utils import dbsafe_decode\r
+\r
+class Migration(DataMigration):\r
+\r
+ def forwards(self, orm):\r
+ b_count = orm.Badge.objects.count()\r
+ print "\nConverting %d badges:" % b_count\r
+ progress = ProgressBar(b_count)\r
+\r
+ for b in orm.Badge.objects.all():\r
+ b.cls = "".join([s[0].upper() + s[1:] for s in b.slug.split('-')])\r
+ b.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ ctypes = dict([(ct.name, ct.id) for ct in orm['contenttypes.ContentType'].objects.all()])\r
+\r
+ a_count = orm.Award.objects.count()\r
+ print "\nConverting %d awards:" % a_count\r
+ progress = ProgressBar(a_count)\r
+\r
+ for a in orm.Award.objects.all():\r
+ if a.content_type.id == ctypes['user']:\r
+ a.node = None\r
+ else:\r
+ try:\r
+ a.node = orm.Node.objects.get(id=a.object_id)\r
+ except:\r
+ a.delete()\r
+ continue\r
+\r
+ action = orm.Action(\r
+ user = a.user,\r
+ node = a.node,\r
+ action_type = "award",\r
+ action_date = a.awarded_at,\r
+ )\r
+\r
+ action.save()\r
+\r
+ a.action = action\r
+ a.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+\r
+ a_count = orm.Action.objects.filter(action_type__in=("voteup", "votedown", "voteupcomment")).count()\r
+ print "\nConverting %d votes:" % a_count\r
+ progress = ProgressBar(a_count)\r
+\r
+ for a in orm.Action.objects.filter(action_type__in=("voteup", "votedown", "voteupcomment"), canceled=False):\r
+ v = orm.Vote(\r
+ user = a.user,\r
+ node = a.node,\r
+ value = (a.action_type in ("voteup", "voteupcomment")) and 1 or -1,\r
+ action = a,\r
+ voted_at = a.action_date\r
+ )\r
+\r
+ v.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+\r
+ a_count = orm.Action.objects.filter(action_type__in=("voteup", "votedown", "voteupcomment")).count()\r
+ print "\nConverting %d votes:" % a_count\r
+ progress = ProgressBar(a_count)\r
+\r
+ for a in orm.Action.objects.filter(action_type="flag", canceled=False):\r
+ f = orm.Flag(\r
+ user = a.user,\r
+ node = a.node,\r
+ reason = a.extra,\r
+ action = a,\r
+ flagged_at = a.action_date\r
+ )\r
+\r
+ f.save()\r
+\r
+ progress.update()\r
+\r
+ print "\n...done\n"\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ "Write your backwards methods here."\r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'unique_together': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award'", 'to': "orm['forum.Action']"}),\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Badge']"}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'object_name': 'Badge'},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),\r
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'multiple': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '50', 'blank': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.flag': {\r
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 3, 11, 43, 54, 540000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag'},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 4, 11, 43, 54, 592000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.vote': {\r
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
--- /dev/null
+# encoding: utf-8\r
+import datetime\r
+from south.db import db\r
+from south.v2 import SchemaMigration\r
+from django.db import models\r
+\r
+class Migration(SchemaMigration):\r
+ \r
+ def forwards(self, orm):\r
+ \r
+ # Deleting field 'Award.object_id'\r
+ db.delete_column('forum_award', 'object_id')\r
+\r
+ # Deleting field 'Award.content_type'\r
+ db.delete_column('forum_award', 'content_type_id')\r
+\r
+ # Adding unique constraint on 'Award', fields ['action']\r
+ db.create_unique('forum_award', ['action_id'])\r
+\r
+ # Deleting field 'Badge.multiple'\r
+ db.delete_column('forum_badge', 'multiple')\r
+\r
+ # Deleting field 'Badge.name'\r
+ db.delete_column('forum_badge', 'name')\r
+\r
+ # Deleting field 'Badge.slug'\r
+ db.delete_column('forum_badge', 'slug')\r
+\r
+ # Deleting field 'Badge.description'\r
+ db.delete_column('forum_badge', 'description')\r
+ \r
+ \r
+ def backwards(self, orm):\r
+ \r
+ # Adding field 'Award.object_id'\r
+ db.add_column('forum_award', 'object_id', self.gf('django.db.models.fields.PositiveIntegerField')(default=1), keep_default=False)\r
+\r
+ # Adding field 'Award.content_type'\r
+ db.add_column('forum_award', 'content_type', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['contenttypes.ContentType']), keep_default=False)\r
+\r
+ # Removing unique constraint on 'Award', fields ['action']\r
+ db.delete_unique('forum_award', ['action_id'])\r
+\r
+ # Adding field 'Badge.multiple'\r
+ db.add_column('forum_badge', 'multiple', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default=False)\r
+\r
+ # Adding field 'Badge.name'\r
+ db.add_column('forum_badge', 'name', self.gf('django.db.models.fields.CharField')(default=1, max_length=50), keep_default=False)\r
+\r
+ # Adding field 'Badge.slug'\r
+ 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)\r
+\r
+ # Adding field 'Badge.description'\r
+ db.add_column('forum_badge', 'description', self.gf('django.db.models.fields.CharField')(default=1, max_length=300), keep_default=False)\r
+ \r
+ \r
+ models = {\r
+ 'auth.group': {\r
+ 'Meta': {'object_name': 'Group'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),\r
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})\r
+ },\r
+ 'auth.permission': {\r
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},\r
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})\r
+ },\r
+ 'auth.user': {\r
+ 'Meta': {'object_name': 'User'},\r
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),\r
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),\r
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),\r
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),\r
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})\r
+ },\r
+ 'contenttypes.contenttype': {\r
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},\r
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})\r
+ },\r
+ 'forum.action': {\r
+ 'Meta': {'object_name': 'Action'},\r
+ 'action_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'action_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'canceled_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),\r
+ 'canceled_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'canceled_actions'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'canceled_ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'extra': ('forum.models.utils.PickledObjectField', [], {'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.actionrepute': {\r
+ 'Meta': {'object_name': 'ActionRepute'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.Action']"}),\r
+ 'by_canceled': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputes'", 'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.authkeyuserassociation': {\r
+ 'Meta': {'object_name': 'AuthKeyUserAssociation'},\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '64'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_keys'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.award': {\r
+ 'Meta': {'unique_together': "(('user', 'badge', 'node'),)", 'object_name': 'Award'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Badge']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'trigger': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'awards'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.badge': {\r
+ 'Meta': {'object_name': 'Badge'},\r
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'through': "'Award'", 'to': "orm['forum.User']"}),\r
+ 'cls': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'type': ('django.db.models.fields.SmallIntegerField', [], {})\r
+ },\r
+ 'forum.flag': {\r
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Flag'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'flag'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'flagged_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ },\r
+ 'forum.keyvalue': {\r
+ 'Meta': {'object_name': 'KeyValue'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'value': ('forum.models.utils.PickledObjectField', [], {'null': 'True'})\r
+ },\r
+ 'forum.markedtag': {\r
+ 'Meta': {'object_name': 'MarkedTag'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),\r
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['forum.Tag']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.node': {\r
+ 'Meta': {'object_name': 'Node'},\r
+ 'abs_parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'active_revision': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'active'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.NodeRevision']"}),\r
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nodes'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'deleted': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'deleted_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extra_node'", 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'extra_ref': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']", 'null': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'in_moderation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'moderated_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']", 'null': 'True'}),\r
+ 'last_edited': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edited_node'", 'unique': 'True', 'null': 'True', 'to': "orm['forum.Action']"}),\r
+ 'marked': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'node_type': ('django.db.models.fields.CharField', [], {'default': "'node'", 'max_length': '16'}),\r
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'children'", 'null': 'True', 'to': "orm['forum.Node']"}),\r
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'nodes'", 'to': "orm['forum.Tag']"}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'})\r
+ },\r
+ 'forum.noderevision': {\r
+ 'Meta': {'unique_together': "(('node', 'revision'),)", 'object_name': 'NodeRevision'},\r
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'noderevisions'", 'to': "orm['forum.User']"}),\r
+ 'body': ('django.db.models.fields.TextField', [], {}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['forum.Node']"}),\r
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),\r
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300'}),\r
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),\r
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})\r
+ },\r
+ 'forum.openidassociation': {\r
+ 'Meta': {'object_name': 'OpenIdAssociation'},\r
+ 'assoc_type': ('django.db.models.fields.TextField', [], {'max_length': '64'}),\r
+ 'handle': ('django.db.models.fields.CharField', [], {'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'issued': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'lifetime': ('django.db.models.fields.IntegerField', [], {}),\r
+ 'secret': ('django.db.models.fields.TextField', [], {'max_length': '255'}),\r
+ 'server_url': ('django.db.models.fields.TextField', [], {'max_length': '2047'})\r
+ },\r
+ 'forum.openidnonce': {\r
+ 'Meta': {'object_name': 'OpenIdNonce'},\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'salt': ('django.db.models.fields.CharField', [], {'max_length': '50'}),\r
+ 'server_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),\r
+ 'timestamp': ('django.db.models.fields.IntegerField', [], {})\r
+ },\r
+ 'forum.questionsubscription': {\r
+ 'Meta': {'object_name': 'QuestionSubscription'},\r
+ 'auto_subscription': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'last_view': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 3, 11, 46, 22, 80000)'}),\r
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.subscriptionsettings': {\r
+ 'Meta': {'object_name': 'SubscriptionSettings'},\r
+ 'all_questions': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'all_questions_watched_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'enable_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'member_joins': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),\r
+ 'new_question': ('django.db.models.fields.CharField', [], {'default': "'d'", 'max_length': '1'}),\r
+ 'new_question_watched_tags': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'notify_accepted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_answers': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_comments': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'notify_comments_own_post': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'notify_reply_to_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_answered': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_asked': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),\r
+ 'questions_commented': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'questions_viewed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'subscribed_questions': ('django.db.models.fields.CharField', [], {'default': "'i'", 'max_length': '1'}),\r
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'subscription_settings'", 'unique': 'True', 'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.tag': {\r
+ 'Meta': {'object_name': 'Tag'},\r
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['forum.User']"}),\r
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['forum.User']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'marked_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'marked_tags'", 'through': "'MarkedTag'", 'to': "orm['forum.User']"}),\r
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})\r
+ },\r
+ 'forum.user': {\r
+ 'Meta': {'object_name': 'User', '_ormbases': ['auth.User']},\r
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),\r
+ 'bronze': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),\r
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'gold': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),\r
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),\r
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),\r
+ 'silver': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),\r
+ 'subscriptions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subscribers'", 'through': "'QuestionSubscription'", 'to': "orm['forum.Node']"}),\r
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),\r
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})\r
+ },\r
+ 'forum.validationhash': {\r
+ 'Meta': {'unique_together': "(('user', 'type'),)", 'object_name': 'ValidationHash'},\r
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2010, 5, 4, 11, 46, 28, 428000)'}),\r
+ 'hash_code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'seed': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '12'}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"})\r
+ },\r
+ 'forum.vote': {\r
+ 'Meta': {'unique_together': "(('user', 'node'),)", 'object_name': 'Vote'},\r
+ 'action': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'vote'", 'unique': 'True', 'to': "orm['forum.Action']"}),\r
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),\r
+ 'node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.Node']"}),\r
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['forum.User']"}),\r
+ 'value': ('django.db.models.fields.SmallIntegerField', [], {}),\r
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),\r
+ }\r
+ }\r
+ \r
+ complete_apps = ['forum']\r
-from question import Question ,QuestionRevision, FavoriteQuestion, QuestionSubscription\r
+from question import Question ,QuestionRevision, QuestionSubscription\r
from answer import Answer, AnswerRevision\r
from tag import Tag, MarkedTag\r
-from meta import Vote, FlaggedItem\r
-from user import User, Activity, ValidationHash, AuthKeyUserAssociation, SubscriptionSettings\r
-from repute import Badge, Award, Repute\r
-from node import Node, NodeRevision, NodeMetaClass, AnonymousNode\r
+from user import User, ValidationHash, AuthKeyUserAssociation, SubscriptionSettings\r
+from node import Node, NodeRevision, NodeMetaClass\r
from comment import Comment\r
+from action import Action, ActionRepute\r
+from meta import Vote, Flag, Badge, Award\r
from utils import KeyValue\r
\r
try:\r
\r
from base import *\r
\r
-def is_new(sender, instance, **kwargs):\r
- try:\r
- instance._is_new = not bool(instance.id)\r
- except:\r
- pass\r
-\r
-pre_save.connect(is_new)\r
-\r
__all__ = [\r
- 'Node', 'NodeRevision', 'AnonymousNode', \r
- 'Question', 'FavoriteQuestion', 'QuestionSubscription', 'QuestionRevision',\r
+ 'Node', 'NodeRevision', \r
+ 'Question', 'QuestionSubscription', 'QuestionRevision',\r
'Answer', 'AnswerRevision',\r
- 'Tag', 'Comment', 'Vote', 'FlaggedItem', 'MarkedTag', 'Badge', 'Award', 'Repute',\r
- 'Activity', 'ValidationHash', 'AuthKeyUserAssociation', 'SubscriptionSettings', 'KeyValue', 'User',\r
+ 'Tag', 'Comment', 'MarkedTag', 'Badge', 'Award',\r
+ 'ValidationHash', 'AuthKeyUserAssociation', 'SubscriptionSettings', 'KeyValue', 'User',\r
+ 'Action', 'ActionRepute', 'Vote', 'Flag'\r
]\r
\r
\r
__all__.append(k)\r
exec "%s = v" % k\r
\r
-NodeMetaClass.setup_relations()
\ No newline at end of file
+NodeMetaClass.setup_relations()\r
+BaseMetaClass.setup_denormalizes()
\ No newline at end of file
--- /dev/null
+from django.utils.translation import ugettext as _\r
+from utils import PickledObjectField\r
+from threading import Thread\r
+from base import *\r
+import re\r
+\r
+class ActionManager(models.Manager):\r
+ use_for_related_fields = True\r
+\r
+ def get_query_set(self):\r
+ qs = super(ActionManager, self).get_query_set().filter(canceled=False)\r
+\r
+ if self.model is not Action:\r
+ return qs.filter(action_type=self.model.get_type())\r
+ else:\r
+ return qs\r
+\r
+ def get(self, *args, **kwargs):\r
+ action = super(ActionManager, self).get(*args, **kwargs)\r
+ if self.model == Action:\r
+ return action.leaf()\r
+ return action\r
+\r
+ def get_for_types(self, types, *args, **kwargs):\r
+ kwargs['action_type__in'] = [t.get_type() for t in types]\r
+ return self.get(*args, **kwargs)\r
+\r
+ \r
+\r
+class Action(models.Model):\r
+ user = models.ForeignKey('User', related_name="actions")\r
+ ip = models.CharField(max_length=16)\r
+ node = models.ForeignKey('Node', null=True, related_name="actions")\r
+ action_type = models.CharField(max_length=16)\r
+ action_date = models.DateTimeField(default=datetime.datetime.now)\r
+\r
+ extra = PickledObjectField()\r
+\r
+ canceled = models.BooleanField(default=False)\r
+ canceled_by = models.ForeignKey('User', null=True, related_name="canceled_actions")\r
+ canceled_at = models.DateTimeField(null=True)\r
+ canceled_ip = models.CharField(max_length=16)\r
+\r
+ hooks = {}\r
+\r
+ objects = ActionManager()\r
+\r
+ @property\r
+ def at(self):\r
+ return self.action_date\r
+\r
+ @property\r
+ def by(self):\r
+ return self.user\r
+\r
+ def repute_users(self):\r
+ pass\r
+\r
+ def process_data(self, **data):\r
+ pass\r
+\r
+ def process_action(self):\r
+ pass\r
+\r
+ def cancel_action(self):\r
+ pass\r
+\r
+ def describe(self, viewer=None):\r
+ return ""\r
+\r
+ def repute(self, user, value):\r
+ repute = ActionRepute(action=self, user=user, value=value)\r
+ repute.save()\r
+ return repute\r
+\r
+ def cancel_reputes(self):\r
+ for repute in self.reputes.all():\r
+ cancel = ActionRepute(action=self, user=repute.user, value=(-repute.value), by_canceled=True)\r
+ cancel.save()\r
+\r
+ def leaf(self):\r
+ leaf_cls = ActionProxyMetaClass.types.get(self.action_type, None)\r
+\r
+ if leaf_cls is None:\r
+ return self\r
+\r
+ leaf = leaf_cls()\r
+ leaf.__dict__ = self.__dict__\r
+ return leaf\r
+\r
+ @classmethod\r
+ def get_type(cls):\r
+ return re.sub(r'action$', '', cls.__name__.lower())\r
+\r
+ def save(self, data=None, *args, **kwargs):\r
+ isnew = False\r
+\r
+ if not self.id:\r
+ self.action_type = self.__class__.get_type()\r
+ isnew = True\r
+\r
+ if data:\r
+ self.process_data(**data)\r
+\r
+ super(Action, self).save(*args, **kwargs)\r
+\r
+ if isnew:\r
+ if (self.node is None) or (not self.node.wiki):\r
+ self.repute_users()\r
+ self.process_action()\r
+ self.trigger_hooks(True)\r
+\r
+ return self\r
+\r
+ def delete(self):\r
+ self.cancel_action()\r
+ super(Action, self).delete()\r
+\r
+ def cancel(self, user=None, ip=None):\r
+ if not self.canceled:\r
+ self.canceled = True\r
+ self.canceled_at = datetime.datetime.now()\r
+ self.canceled_by = (user is None) and self.user or user\r
+ if ip:\r
+ self.canceled_ip = ip\r
+ self.save()\r
+ self.cancel_reputes()\r
+ self.cancel_action()\r
+ #self.trigger_hooks(False)\r
+\r
+ @classmethod\r
+ def get_current(cls, **kwargs):\r
+ kwargs['canceled'] = False\r
+\r
+ try:\r
+ return cls.objects.get(**kwargs)\r
+ except cls.MultipleObjectsReturned:\r
+ logging.error("Got multiple values for action %s with args %s", cls.__name__,\r
+ ", ".join(["%s='%s'" % i for i in kwargs.items()]))\r
+ raise\r
+ except cls.DoesNotExist:\r
+ return None\r
+\r
+ @classmethod\r
+ def hook(cls, fn):\r
+ if not Action.hooks.get(cls, None):\r
+ Action.hooks[cls] = []\r
+\r
+ Action.hooks[cls].append(fn)\r
+\r
+ def trigger_hooks(self, new=True):\r
+ thread = Thread(target=trigger_hooks_threaded, args=[self, Action.hooks, new])\r
+ thread.setDaemon(True)\r
+ thread.start()\r
+\r
+ class Meta:\r
+ app_label = 'forum'\r
+\r
+def trigger_hooks_threaded(action, hooks, new):\r
+ for cls, hooklist in hooks.items():\r
+ if isinstance(action, cls):\r
+ for hook in hooklist:\r
+ try:\r
+ hook(action=action, new=new)\r
+ except Exception, e:\r
+ logging.error("Error in %s hook: %s" % (cls.__name__, str(e)))\r
+\r
+class ActionProxyMetaClass(models.Model.__metaclass__):\r
+ types = {}\r
+\r
+ def __new__(cls, *args, **kwargs):\r
+ new_cls = super(ActionProxyMetaClass, cls).__new__(cls, *args, **kwargs)\r
+ cls.types[new_cls.get_type()] = new_cls\r
+\r
+ class Meta:\r
+ proxy = True\r
+\r
+ new_cls.Meta = Meta\r
+ return new_cls\r
+\r
+class ActionProxy(Action):\r
+ __metaclass__ = ActionProxyMetaClass\r
+\r
+ def friendly_username(self, viewer, user):\r
+ return (viewer == user) and _('You') or user.username\r
+\r
+ def friendly_ownername(self, owner, user):\r
+ return (owner == user) and _('your') or user.username\r
+\r
+ def hyperlink(self, url, title, **attrs):\r
+ return '<a href="%s" %s>%s</a>' % (url, " ".join('%s="%s"' % i for i in attrs.items()), title)\r
+\r
+ def describe_node(self, viewer, node):\r
+ node_link = self.hyperlink(node.get_absolute_url(), node.headline)\r
+\r
+ if node.parent:\r
+ node_desc = _("on %(link)s") % {'link': node_link}\r
+ else:\r
+ node_desc = node_link\r
+\r
+ return _("%(user)s %(node_name)s %(node_desc)s") % {\r
+ 'user': self.hyperlink(node.author.get_profile_url(), self.friendly_ownername(viewer, node.author)),\r
+ 'node_name': node.friendly_name, 'node_desc': node_desc,\r
+ }\r
+ \r
+ class Meta:\r
+ proxy = True\r
+\r
+class DummyActionProxy(Action):\r
+ __metaclass__ = ActionProxyMetaClass\r
+\r
+ hooks = []\r
+\r
+ def process_data(self, **data):\r
+ pass\r
+\r
+ def process_action(self):\r
+ pass\r
+\r
+ def save(self, data=None):\r
+ self.process_action()\r
+\r
+ if data:\r
+ self.process_data(**data)\r
+\r
+ for hook in self.__class__.hooks:\r
+ hook(self, True)\r
+\r
+ @classmethod\r
+ def get_type(cls):\r
+ return re.sub(r'action$', '', cls.__name__.lower())\r
+\r
+ @classmethod\r
+ def hook(cls, fn):\r
+ cls.hooks.append(fn)\r
+\r
+\r
+\r
+class ActionRepute(models.Model):\r
+ action = models.ForeignKey(Action, related_name='reputes')\r
+ date = models.DateTimeField(default=datetime.datetime.now)\r
+ user = models.ForeignKey('User', related_name='reputes')\r
+ value = models.IntegerField(default=0)\r
+ by_canceled = models.BooleanField(default=False)\r
+\r
+ @property\r
+ def positive(self):\r
+ if self.value > 0: return self.value\r
+ return 0\r
+\r
+ @property\r
+ def negative(self):\r
+ if self.value < 0: return self.value\r
+ return 0\r
+\r
+ def save(self, *args, **kwargs):\r
+ super(ActionRepute, self).save(*args, **kwargs)\r
+ self.user.reputation = models.F('reputation') + self.value\r
+ self.user.save()\r
+\r
+ def delete(self):\r
+ self.user.reputation = models.F('reputation') - self.value\r
+ self.user.save()\r
+ super(ActionRepute, self).delete()\r
+\r
+ class Meta:\r
+ app_label = 'forum'\r
+\r
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:
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)
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:
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()
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)
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
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()
from base import *\r
+from django.utils.translation import ugettext as _\r
import re\r
\r
class Comment(Node):\r
+ friendly_name = _("comment")\r
+\r
class Meta(Node.Meta):\r
ordering = ('-added_at',)\r
proxy = True\r
\r
@property\r
def comment(self):\r
- return self.body\r
+ if settings.FORM_ALLOW_MARKDOWN_IN_COMMENTS:\r
+ return self.as_markdown('limitedsyntax')\r
+ else:\r
+ return self.body\r
\r
@property\r
def headline(self):\r
def save(self, *args, **kwargs):\r
super(Comment,self).save(*args, **kwargs)\r
\r
- if self._is_new:\r
- self._update_parent_comment_count(1)\r
-\r
- try:\r
- ping_google()\r
- except Exception:\r
- logging.debug('problem pinging google did you register your sitemap with google?')\r
+ if not self.id:\r
+ self.parent.reset_comment_count_cache()\r
\r
def mark_deleted(self, user):\r
if super(Comment, self).mark_deleted(user):\r
- self._update_parent_comment_count(-1)\r
+ self.parent.reset_comment_count_cache()\r
\r
def unmark_deleted(self):\r
if super(Comment, self).unmark_deleted():\r
- self._update_parent_comment_count(1)\r
+ self.parent.reset_comment_count_cache()\r
\r
def is_reply_to(self, user):\r
inreply = re.search('@\w+', self.body)\r
-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 _\r
+from base import *\r
+\r
+class Vote(models.Model):\r
+ user = models.ForeignKey(User, related_name="votes")\r
+ node = models.ForeignKey(Node, related_name="votes")\r
+ value = models.SmallIntegerField()\r
+ action = models.ForeignKey(Action, unique=True, related_name="vote")\r
+ voted_at = models.DateTimeField(default=datetime.datetime.now)\r
+\r
+ class Meta:\r
+ app_label = 'forum'\r
+ unique_together = ('user', 'node')\r
+\r
+\r
+class Flag(models.Model):\r
+ user = models.ForeignKey(User, related_name="flags")\r
+ node = models.ForeignKey(Node, related_name="flags")\r
+ reason = models.CharField(max_length=300)\r
+ action = models.ForeignKey(Action, unique=True, related_name="flag")\r
+ flagged_at = models.DateTimeField(default=datetime.datetime.now)\r
+\r
+ class Meta:\r
+ app_label = 'forum'\r
+ unique_together = ('user', 'node')\r
+\r
+class BadgeManager(models.Manager):\r
+ use_for_related_fields = True\r
+ \r
+ def get(self, *args, **kwargs):\r
+ try:\r
+ pk = [v for (k,v) in kwargs.items() if k in ('pk', 'pk__exact', 'id', 'id__exact')][0]\r
+ except:\r
+ return super(BadgeManager, self).get(*args, **kwargs)\r
+\r
+ from forum.badges.base import BadgesMeta\r
+ badge = BadgesMeta.by_id.get(pk, None)\r
+ if not badge:\r
+ return super(BadgeManager, self).get(*args, **kwargs)\r
+ return badge.ondb\r
+\r
+class Badge(models.Model):\r
+ GOLD = 1\r
+ SILVER = 2\r
+ BRONZE = 3\r
+\r
+ type = models.SmallIntegerField()\r
+ cls = models.CharField(max_length=50, null=True)\r
+ awarded_count = models.PositiveIntegerField(default=0)\r
+ \r
+ awarded_to = models.ManyToManyField(User, through='Award', related_name='badges')\r
+\r
+ objects = BadgeManager()\r
+\r
+ @property\r
+ def name(self):\r
+ cls = self.__dict__.get('_class', None)\r
+ return cls and cls.name or _("Unknown")\r
+\r
+ @property\r
+ def description(self):\r
+ cls = self.__dict__.get('_class', None)\r
+ return cls and cls.description or _("No description available")\r
+\r
+ @models.permalink\r
+ def get_absolute_url(self):\r
+ return ('badge', [], {'id': self.id, 'slug': slugify(self.name)}) \r
+\r
+ class Meta:\r
+ app_label = 'forum'\r
+\r
+\r
+class Award(models.Model):\r
+ user = models.ForeignKey(User)\r
+ badge = models.ForeignKey('Badge', related_name="awards")\r
+ node = models.ForeignKey(Node, null=True)\r
+\r
+ awarded_at = models.DateTimeField(default=datetime.datetime.now)\r
+\r
+ trigger = models.ForeignKey(Action, related_name="awards", null=True)\r
+ action = models.ForeignKey(Action, related_name="award", unique=True)\r
+\r
+\r
+ class Meta:\r
+ unique_together = ('user', 'badge', 'node')\r
+ app_label = 'forum'
\ No newline at end of file
-from akismet import *\r
+from forum.akismet import *\r
from base import *\r
from tag import Tag\r
\r
import markdown\r
+from django.utils.translation import ugettext as _\r
from django.utils.safestring import mark_safe\r
from django.utils.html import strip_tags\r
from forum.utils.html import sanitize_html\r
\r
@property\r
def html(self):\r
- return mark_safe(sanitize_html(markdown.markdown(self.body)))\r
+ return self.as_markdown()\r
+\r
+ def as_markdown(self, *extensions):\r
+ return mark_safe(sanitize_html(markdown.markdown(self.body, extensions=extensions)))\r
\r
@property\r
def headline(self):\r
abstract = True\r
app_label = 'forum'\r
\r
-class NodeMetaClass(models.Model.__metaclass__):\r
+class NodeMetaClass(BaseMetaClass):\r
types = {}\r
\r
def __new__(cls, *args, **kwargs):\r
new_cls = super(NodeMetaClass, cls).__new__(cls, *args, **kwargs)\r
\r
if not new_cls._meta.abstract and new_cls.__name__ is not 'Node':\r
- NodeMetaClass.types[new_cls.__name__.lower()] = new_cls\r
+ NodeMetaClass.types[new_cls.get_type()] = new_cls\r
\r
return new_cls\r
\r
name = node_cls.__name__.lower()\r
\r
def children(self):\r
- if node_cls._meta.proxy:\r
- return node_cls.objects.filter(node_type=name, parent=self)\r
- else:\r
- return node_cls.objects.filter(parent=self)\r
+ return node_cls.objects.filter(parent=self)\r
\r
def parent(self):\r
p = self.__dict__.get('_%s_cache' % name, None)\r
Node.add_to_class(name, property(parent))\r
\r
\r
-node_create = django.dispatch.Signal(providing_args=['instance'])\r
-node_edit = django.dispatch.Signal(providing_args=['instance'])\r
+class NodeManager(CachedManager):\r
+ use_for_related_fields = True\r
\r
-class Node(BaseModel, NodeContent, DeletableContent):\r
- __metaclass__ = NodeMetaClass\r
+ def get_query_set(self):\r
+ qs = super(NodeManager, self).get_query_set()\r
+\r
+ if self.model is not Node:\r
+ return qs.filter(node_type=self.model.get_type())\r
+ else:\r
+ return qs\r
+\r
+ def get(self, *args, **kwargs):\r
+ node = super(NodeManager, self).get(*args, **kwargs)\r
+ cls = NodeMetaClass.types.get(node.node_type, None)\r
+\r
+ if cls and node.__class__ is not cls:\r
+ return node.leaf\r
+ return node\r
+\r
+ def get_for_types(self, types, *args, **kwargs):\r
+ kwargs['node_type__in'] = [t.get_type() for t in types]\r
+ return self.get(*args, **kwargs)\r
\r
- node_type = models.CharField(max_length=16, default='node')\r
- parent = models.ForeignKey('Node', related_name='children', null=True)\r
- abs_parent = models.ForeignKey('Node', related_name='all_children', null=True)\r
\r
- added_at = models.DateTimeField(default=datetime.datetime.now)\r
+class Node(BaseModel, NodeContent):\r
+ __metaclass__ = NodeMetaClass\r
\r
- tags = models.ManyToManyField('Tag', related_name='%(class)ss')\r
+ node_type = models.CharField(max_length=16, default='node')\r
+ parent = models.ForeignKey('Node', related_name='children', null=True)\r
+ abs_parent = models.ForeignKey('Node', related_name='all_children', null=True)\r
\r
- score = DenormalizedField(default=0)\r
- vote_up_count = DenormalizedField(default=0)\r
- vote_down_count = models.IntegerField(default=0)\r
+ added_at = models.DateTimeField(default=datetime.datetime.now)\r
+ score = models.IntegerField(default=0)\r
\r
- comment_count = DenormalizedField(default=0)\r
- offensive_flag_count = DenormalizedField(default=0)\r
+ deleted = models.ForeignKey('Action', null=True, unique=True, related_name="deleted_node")\r
+ in_moderation = models.ForeignKey('Action', null=True, unique=True, related_name="moderated_node")\r
+ last_edited = models.ForeignKey('Action', null=True, unique=True, related_name="edited_node")\r
\r
- last_edited_at = models.DateTimeField(null=True, blank=True)\r
- last_edited_by = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_%(class)ss')\r
+ last_activity_by = models.ForeignKey(User, null=True)\r
+ last_activity_at = models.DateTimeField(null=True, blank=True)\r
\r
+ tags = models.ManyToManyField('Tag', related_name='%(class)ss')\r
active_revision = models.OneToOneField('NodeRevision', related_name='active', null=True)\r
\r
+ extra_ref = models.ForeignKey('Node', null=True)\r
+ extra_count = models.IntegerField(default=0)\r
+ extra_action = models.ForeignKey('Action', null=True, related_name="extra_node")\r
+ \r
+ marked = models.BooleanField(default=False)\r
+ wiki = models.BooleanField(default=False)\r
+\r
+ comment_count = DenormalizedField("children", node_type="comment", canceled=False)\r
+ flag_count = DenormalizedField("flags")\r
+\r
+ friendly_name = _("post")\r
+\r
+ objects = NodeManager()\r
+\r
+ @classmethod\r
+ def cache_key(cls, pk):\r
+ return '%s.node:%s' % (settings.APP_URL, pk)\r
+\r
+ @classmethod\r
+ def get_type(cls):\r
+ return cls.__name__.lower()\r
+\r
@property\r
def leaf(self):\r
- return NodeMetaClass.types[self.node_type].objects.get(id=self.id)\r
+ leaf_cls = NodeMetaClass.types.get(self.node_type, None)\r
+\r
+ if leaf_cls is None:\r
+ return self\r
+\r
+ leaf = leaf_cls()\r
+ leaf.__dict__ = self.__dict__\r
+ return leaf\r
\r
@property \r
def absolute_parent(self):\r
def summary(self):\r
return strip_tags(self.html)[:300]\r
\r
- def create_revision(self, user, **kwargs):\r
- revision = NodeRevision(author=user, **kwargs)\r
- \r
- if not self.id:\r
- self.author = user\r
- self.save()\r
- revision.revision = 1\r
- else:\r
- revision.revision = self.revisions.aggregate(last=models.Max('revision'))['last'] + 1\r
+ def update_last_activity(self, user):\r
+ self.last_activity_by = user\r
+ self.last_activity_at = datetime.datetime.now()\r
\r
- revision.node_id = self.id\r
+ if self.parent:\r
+ self.parent.update_last_activity(user)\r
+\r
+ def _create_revision(self, user, number, **kwargs):\r
+ revision = NodeRevision(author=user, revision=number, node=self, **kwargs)\r
revision.save()\r
- self.activate_revision(user, revision)\r
+ return revision\r
+\r
+ def create_revision(self, user, action=None, **kwargs):\r
+ number = self.revisions.aggregate(last=models.Max('revision'))['last'] + 1\r
+ revision = self._create_revision(user, number, **kwargs)\r
+ self.activate_revision(user, revision, action)\r
+ return revision\r
\r
- def activate_revision(self, user, revision):\r
+ def activate_revision(self, user, revision, action=None):\r
self.title = revision.title\r
self.tagnames = revision.tagnames\r
self.body = revision.body\r
\r
- old_revision = self.active_revision\r
self.active_revision = revision\r
+ self.update_last_activity(user)\r
\r
- if not old_revision:\r
- signal = node_create\r
- else:\r
- self.last_edited_at = datetime.datetime.now()\r
- self.last_edited_by = user\r
- signal = node_edit\r
+ if action:\r
+ self.last_edited = action\r
\r
self.save()\r
- signal.send(sender=self.__class__, instance=self)\r
\r
def get_tag_list_if_changed(self):\r
dirty = self.get_dirty_fields()\r
+ active_user = self.last_edited and self.last_edited.by or self.author\r
\r
if 'tagnames' in dirty:\r
new_tags = self.tagname_list()\r
try:\r
tag = Tag.objects.get(name=name)\r
except:\r
- tag = Tag.objects.create(name=name, created_by=self.last_edited_by or self.author)\r
+ tag = Tag.objects.create(name=name, created_by=active_user or self.author)\r
\r
tag_list.append(tag)\r
\r
tag = Tag.objects.get(name=name)\r
tag.used_count = tag.used_count - 1\r
if tag.used_count == 0:\r
- tag.mark_deleted(self.last_edited_by or self.author)\r
+ tag.mark_deleted(active_user)\r
tag.save()\r
\r
return tag_list\r
\r
def save(self, *args, **kwargs):\r
if not self.id:\r
- self.node_type = self.__class__.__name__.lower()\r
+ self.node_type = self.get_type()\r
+ super(BaseModel, self).save(*args, **kwargs)\r
+ self.active_revision = self._create_revision(self.author, 1, title=self.title, tagnames=self.tagnames, body=self.body)\r
+ self.update_last_activity(self.author)\r
\r
if self.parent_id and not self.abs_parent_id:\r
self.abs_parent = self.parent.absolute_parent\r
-\r
- self.__dict__['score'] = self.__dict__['vote_up_count'] - self.__dict__['vote_down_count']\r
- \r
+ \r
tags = self.get_tag_list_if_changed()\r
super(Node, self).save(*args, **kwargs)\r
if tags is not None: self.tags = tags\r
@staticmethod\r
def isSpam(comment, data):\r
api = Akismet()\r
- if api.key is None:\r
- print "problem" # raise APIKeyError\r
+\r
+ if not api.key:\r
+ return False\r
else:\r
if api.comment_check(comment, data):\r
return True\r
app_label = 'forum'\r
\r
\r
-from user import ValidationHash\r
-\r
-class AnonymousNode(Node):\r
- validation_hash = models.ForeignKey(Node, related_name='anonymous_content')\r
- convertible_to = models.CharField(max_length=16, default='node')\r
-\r
- class Meta:\r
- app_label = 'forum'
\ No newline at end of file
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:
@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])
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())
+++ /dev/null
-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'
active = ActiveTagManager()
class Meta(DeletableContent.Meta):
- db_table = u'tag'
ordering = ('-used_count', 'name')
def __unicode__(self):
try:\r
from hashlib import md5\r
except:\r
- import md5\r
+ from md5 import new as md5\r
+\r
import string\r
from random import Random\r
\r
\r
class AnonymousUser(DjangoAnonymousUser):\r
def get_visible_answers(self, question):\r
- return question.answers.filter(deleted=False)\r
+ return question.answers.filter(deleted=None)\r
\r
def can_view_deleted_post(self, post):\r
return False\r
def can_upload_files(self):\r
return False\r
\r
+def true_if_is_super_or_staff(fn):\r
+ def decorated(self, *args, **kwargs):\r
+ return self.is_superuser or self.is_staff or fn(self, *args, **kwargs)\r
+ return decorated\r
+\r
class User(BaseModel, DjangoUser):\r
is_approved = models.BooleanField(default=False)\r
email_isvalid = models.BooleanField(default=False)\r
- email_key = models.CharField(max_length=32, null=True)\r
- reputation = DenormalizedField(default=1)\r
\r
- gold = DenormalizedField(default=0)\r
- silver = DenormalizedField(default=0)\r
- bronze = DenormalizedField(default=0)\r
-\r
- questions_per_page = models.SmallIntegerField(choices=QUESTIONS_PER_PAGE_CHOICES, default=10)\r
- hide_ignored_questions = models.BooleanField(default=False)\r
+ reputation = models.PositiveIntegerField(default=0)\r
+ gold = models.PositiveIntegerField(default=0)\r
+ silver = models.PositiveIntegerField(default=0)\r
+ bronze = models.PositiveIntegerField(default=0)\r
\r
last_seen = models.DateTimeField(default=datetime.datetime.now)\r
real_name = models.CharField(max_length=100, blank=True)\r
location = models.CharField(max_length=100, blank=True)\r
date_of_birth = models.DateField(null=True, blank=True)\r
about = models.TextField(blank=True)\r
- \r
+\r
+ subscriptions = models.ManyToManyField('Node', related_name='subscribers', through='QuestionSubscription')\r
+\r
+ vote_up_count = DenormalizedField("actions", canceled=False, action_type="voteup")\r
+ vote_down_count = DenormalizedField("actions", canceled=False, action_type="votedown")\r
+ \r
objects = UserManager()\r
\r
@property\r
\r
def save(self, *args, **kwargs):\r
if self.reputation < 0:\r
- self.reputation = 1\r
+ self.reputation = 0\r
+\r
+ new = not bool(self.id)\r
\r
super(User, self).save(*args, **kwargs)\r
\r
+ if new:\r
+ sub_settings = SubscriptionSettings(user=self)\r
+ sub_settings.save()\r
+\r
def get_absolute_url(self):\r
return self.get_profile_url()\r
\r
profile_link = u'<a href="%s">%s</a>' % (self.get_profile_url(),self.username)\r
return mark_safe(profile_link)\r
\r
+ def get_visible_answers(self, question):\r
+ return question.answers.filter(deleted=None, in_moderation=None)\r
+\r
def get_vote_count_today(self):\r
today = datetime.date.today()\r
- return self.votes.filter(voted_at__range=(today - datetime.timedelta(days=1), today)).count()\r
-\r
- def get_up_vote_count(self):\r
- return self.votes.filter(vote=1).count()\r
-\r
- def get_down_vote_count(self):\r
- return self.votes.filter(vote=-1).count()\r
+ return self.actions.filter(canceled=False, action_type__in=("voteup", "votedown"),\r
+ action_date__range=(today - datetime.timedelta(days=1), today)).count()\r
\r
def get_reputation_by_upvoted_today(self):\r
today = datetime.datetime.now()\r
\r
def get_flagged_items_count_today(self):\r
today = datetime.date.today()\r
- return self.flaggeditems.filter(flagged_at__range=(today - datetime.timedelta(days=1), today)).count()\r
-\r
- def get_visible_answers(self, question):\r
- if self.is_superuser:\r
- return question.answers\r
- else:\r
- return question.answers.filter(models.Q(deleted=False) | models.Q(deleted_by=self))\r
+ return self.actions.filter(canceled=False, action_type="flag",\r
+ action_date__range=(today - datetime.timedelta(days=1), today)).count()\r
\r
+ @true_if_is_super_or_staff\r
def can_view_deleted_post(self, post):\r
- return self.is_superuser or post.author == self\r
+ return post.author == self\r
\r
+ @true_if_is_super_or_staff\r
def can_vote_up(self):\r
- return self.reputation >= int(settings.REP_TO_VOTE_UP) or self.is_superuser\r
+ return self.reputation >= int(settings.REP_TO_VOTE_UP)\r
\r
+ @true_if_is_super_or_staff\r
def can_vote_down(self):\r
- return self.reputation >= int(settings.REP_TO_VOTE_DOWN) or self.is_superuser\r
+ return self.reputation >= int(settings.REP_TO_VOTE_DOWN)\r
\r
def can_flag_offensive(self, post=None):\r
if post is not None and post.author == self:\r
return False\r
- return self.is_superuser or self.reputation >= int(settings.REP_TO_FLAG)\r
+ return self.is_superuser or self.is_staff or self.reputation >= int(settings.REP_TO_FLAG)\r
\r
+ @true_if_is_super_or_staff\r
def can_view_offensive_flags(self, post=None):\r
if post is not None and post.author == self:\r
return True\r
- return self.is_superuser or self.reputation >= int(settings.REP_TO_VIEW_FLAGS)\r
+ return self.reputation >= int(settings.REP_TO_VIEW_FLAGS)\r
\r
+ @true_if_is_super_or_staff\r
def can_comment(self, post):\r
return self == post.author or self.reputation >= int(settings.REP_TO_COMMENT\r
- ) or self.is_superuser or (post.__class__.__name__ == "Answer" and self == post.question.author)\r
+ ) or (post.__class__.__name__ == "Answer" and self == post.question.author)\r
\r
+ @true_if_is_super_or_staff\r
def can_like_comment(self, comment):\r
- return self != comment.user and (self.reputation >= int(settings.REP_TO_LIKE_COMMENT) or self.is_superuser)\r
+ return self != comment.author and (self.reputation >= int(settings.REP_TO_LIKE_COMMENT))\r
\r
+ @true_if_is_super_or_staff\r
def can_edit_comment(self, comment):\r
- return (comment.user == self and comment.added_at >= datetime.datetime.now() - datetime.timedelta(minutes=60)\r
+ return (comment.author == self and comment.added_at >= datetime.datetime.now() - datetime.timedelta(minutes=60)\r
) or self.is_superuser\r
\r
+ @true_if_is_super_or_staff\r
def can_delete_comment(self, comment):\r
- return self == comment.user or self.reputation >= int(settings.REP_TO_DELETE_COMMENTS) or self.is_superuser\r
+ return self == comment.author or self.reputation >= int(settings.REP_TO_DELETE_COMMENTS)\r
\r
+ @true_if_is_super_or_staff\r
def can_accept_answer(self, answer):\r
- return self.is_superuser or self == answer.question.author\r
+ return self == answer.question.author\r
\r
+ @true_if_is_super_or_staff\r
def can_edit_post(self, post):\r
- return self.is_superuser or self == post.author or self.reputation >= int(settings.REP_TO_EDIT_OTHERS\r
+ return self == post.author or self.reputation >= int(settings.REP_TO_EDIT_OTHERS\r
) or (post.wiki and self.reputation >= int(settings.REP_TO_EDIT_WIKI))\r
\r
+ @true_if_is_super_or_staff\r
def can_retag_questions(self):\r
return self.reputation >= int(settings.REP_TO_RETAG)\r
\r
+ @true_if_is_super_or_staff\r
def can_close_question(self, question):\r
- return self.is_superuser or (self == question.author and self.reputation >= int(settings.REP_TO_CLOSE_OWN)\r
+ return (self == question.author and self.reputation >= int(settings.REP_TO_CLOSE_OWN)\r
) or self.reputation >= int(settings.REP_TO_CLOSE_OTHERS)\r
\r
+ @true_if_is_super_or_staff\r
def can_reopen_question(self, question):\r
- return self.is_superuser or (self == question.author and self.reputation >= settings.REP_TO_REOPEN_OWN)\r
+ return self == question.author and self.reputation >= settings.REP_TO_REOPEN_OWN\r
\r
+ @true_if_is_super_or_staff\r
def can_delete_post(self, post):\r
- return self.is_superuser or (self == post.author and (post.__class__.__name__ == "Answer" or\r
- not post.answers.filter(~Q(author=self)).count()))\r
+ if post.node_type == "comment":\r
+ return self.can_delete_comment(post)\r
+ \r
+ return (self == post.author and (post.__class__.__name__ == "Answer" or\r
+ not post.answers.exclude(author=self).count()))\r
\r
+ @true_if_is_super_or_staff\r
def can_upload_files(self):\r
- return self.is_superuser or self.reputation >= int(settings.REP_TO_UPLOAD)\r
+ return self.reputation >= int(settings.REP_TO_UPLOAD)\r
\r
class Meta:\r
app_label = 'forum'\r
\r
-class Activity(GenericContent):\r
- """\r
- We keep some history data for user activities\r
- """\r
- user = models.ForeignKey(User)\r
- activity_type = models.SmallIntegerField(choices=TYPE_ACTIVITY)\r
- active_at = models.DateTimeField(default=datetime.datetime.now)\r
- is_auditted = models.BooleanField(default=False)\r
-\r
- class Meta:\r
- app_label = 'forum'\r
- db_table = u'activity'\r
-\r
- def __unicode__(self):\r
- return u'[%s] was active at %s' % (self.user.username, self.active_at)\r
-\r
- def save(self, *args, **kwargs):\r
- super(Activity, self).save(*args, **kwargs)\r
- if self._is_new:\r
- activity_record.send(sender=self.activity_type, instance=self)\r
-\r
- @property\r
- def node(self):\r
- if self.activity_type in (const.TYPE_ACTIVITY_ANSWER, const.TYPE_ACTIVITY_ASK_QUESTION,\r
- const.TYPE_ACTIVITY_MARK_ANSWER, const.TYPE_ACTIVITY_COMMENT_QUESTION, const.TYPE_ACTIVITY_COMMENT_ANSWER):\r
- return self.content_object.leaf\r
-\r
- if self.activity_type in (const.TYPE_ACTIVITY_UPDATE_ANSWER, const.TYPE_ACTIVITY_UPDATE_QUESTION):\r
- return self.content_object.node.leaf \r
- \r
- raise NotImplementedError()\r
-\r
- @property\r
- def type_as_string(self):\r
- if self.activity_type == const.TYPE_ACTIVITY_ASK_QUESTION:\r
- return _("asked")\r
- elif self.activity_type == const.TYPE_ACTIVITY_ANSWER:\r
- return _("answered")\r
- elif self.activity_type == const.TYPE_ACTIVITY_MARK_ANSWER:\r
- return _("marked an answer")\r
- elif self.activity_type == const.TYPE_ACTIVITY_UPDATE_QUESTION:\r
- return _("edited a question")\r
- elif self.activity_type == const.TYPE_ACTIVITY_COMMENT_QUESTION:\r
- return _("commented a question")\r
- elif self.activity_type == const.TYPE_ACTIVITY_COMMENT_ANSWER:\r
- return _("commented an answer")\r
- elif self.activity_type == const.TYPE_ACTIVITY_UPDATE_ANSWER:\r
- return _("edited an answer")\r
- elif self.activity_type == const.TYPE_ACTIVITY_PRIZE:\r
- return _("received badge")\r
- else:\r
- raise NotImplementedError()\r
-\r
-\r
-activity_record = django.dispatch.Signal(providing_args=['instance'])\r
-\r
class SubscriptionSettings(models.Model):\r
user = models.OneToOneField(User, related_name='subscription_settings')\r
\r
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)
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', [])
--- /dev/null
+import inspect\r
+\r
+class DecoratableObject(object):\r
+ def __init__(self, fn):\r
+ self._callable = fn\r
+\r
+ def decorate(self, fn, needs_origin):\r
+ origin = self._callable\r
+\r
+ if needs_origin:\r
+ self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs)\r
+ else:\r
+ self._callable = lambda *args, **kwargs: fn(*args, **kwargs)\r
+\r
+ def __call__(self, *args, **kwargs):\r
+ return self._callable(*args, **kwargs)\r
+\r
+\r
+def decoratable(fn):\r
+ return DecoratableObject(fn)\r
+\r
+def decoratable_method(fn):\r
+ obj = DecoratableObject(fn)\r
+ def decorated(self, *args, **kwargs):\r
+ return obj(self, *args, **kwargs)\r
+\r
+ decorated.__obj = obj\r
+ return decorated\r
+\r
+decoratable.method = decoratable_method\r
+\r
+def decorate(origin, needs_origin=True):\r
+ if not isinstance(origin, DecoratableObject):\r
+ if hasattr(origin, '__obj'):\r
+ def decorator(fn):\r
+ origin.__obj.decorate(fn, needs_origin)\r
+ return origin\r
+ return decorator\r
+\r
+ raise Exception('Not an decoratable function: %s' % origin.name)\r
+\r
+ def decorator(fn):\r
+ origin.decorate(fn, needs_origin)\r
+ return origin\r
+\r
+ return decorator\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+++ /dev/null
-from django.db.models.signals import post_save\r
-from forum.models.base import mark_canceled\r
-from forum.models.answer import answer_accepted, answer_accepted_canceled\r
-\r
-from forum.models import *\r
-from forum.const import *\r
-import settings\r
-\r
-def on_flagged_item(instance, created, **kwargs):\r
- if not created:\r
- return\r
-\r
- post = instance.content_object.leaf\r
- question = (post.__class__ == Question) and post or post.question\r
-\r
- post.author.reputes.create(value=-int(settings.REP_LOST_BY_FLAGGED), question=question,\r
- reputation_type=TYPE_REPUTATION_LOST_BY_FLAGGED)\r
-\r
-\r
- if post.offensive_flag_count == settings.FLAG_COUNT_TO_HIDE_POST:\r
- post.author.reputes.create(value=-int(settings.REP_LOST_BY_FLAGGED_3_TIMES),\r
- question=question, reputation_type=TYPE_REPUTATION_LOST_BY_FLAGGED_3_TIMES)\r
-\r
- if post.offensive_flag_count == settings.FLAG_COUNT_TO_DELETE_POST:\r
- post.author.reputes.create(value=-int(settings.REP_LOST_BY_FLAGGED_5_TIMES),\r
- question=question, reputation_type=TYPE_REPUTATION_LOST_BY_FLAGGED_5_TIMES)\r
-\r
- post.mark_deleted(User.objects.get_site_owner())\r
-\r
-post_save.connect(on_flagged_item, sender=FlaggedItem)\r
-\r
-def on_answer_accepted(answer, user, **kwargs):\r
- if user == answer.question.author and not user == answer.author:\r
- user.reputes.create(\r
- value=int(settings.REP_GAIN_BY_ACCEPTING), question=answer.question,\r
- reputation_type=TYPE_REPUTATION_GAIN_BY_ACCEPTING_ANSWER)\r
-\r
- if not user == answer.author:\r
- answer.author.reputes.create(\r
- value=int(settings.REP_GAIN_BY_ACCEPTED), question=answer.question,\r
- reputation_type=TYPE_REPUTATION_GAIN_BY_ANSWER_ACCEPTED)\r
-\r
-answer_accepted.connect(on_answer_accepted)\r
-\r
-\r
-def on_answer_accepted_canceled(answer, user, **kwargs):\r
- if user == answer.accepted_by:\r
- user.reputes.create(\r
- value=-int(settings.REP_LOST_BY_CANCELING_ACCEPTED), question=answer.question,\r
- reputation_type=TYPE_REPUTATION_LOST_BY_CANCELLING_ACCEPTED_ANSWER)\r
-\r
- if not user == answer.author:\r
- answer.author.reputes.create(\r
- value=-int(settings.REP_LOST_BY_ACCEPTED_CANCELED), question=answer.question,\r
- reputation_type=TYPE_REPUTATION_LOST_BY_ACCEPTED_ANSWER_CANCELED)\r
-\r
-answer_accepted_canceled.connect(on_answer_accepted)\r
-\r
-\r
-def on_vote(instance, created, **kwargs):\r
- if created and (instance.content_object.node_type in ("question", "answer") and not instance.content_object.wiki):\r
- post = instance.content_object.leaf\r
- question = (post.__class__ == Question) and post or post.question\r
-\r
- if instance.vote == -1:\r
- instance.user.reputes.create(value=-int(settings.REP_LOST_BY_DOWNVOTING),\r
- question=question, reputation_type=TYPE_REPUTATION_LOST_BY_DOWNVOTING)\r
-\r
- if instance.vote == 1 and post.author.get_reputation_by_upvoted_today() >= int(settings.MAX_REP_BY_UPVOTE_DAY):\r
- return\r
-\r
- repute_type, repute_value = (instance.vote == 1) and (\r
- TYPE_REPUTATION_GAIN_BY_UPVOTED, int(settings.REP_GAIN_BY_UPVOTED)) or (\r
- TYPE_REPUTATION_LOST_BY_DOWNVOTED, -int(settings.REP_LOST_BY_DOWNVOTED))\r
-\r
- post.author.reputes.create(value=repute_value, question=question, reputation_type=repute_type)\r
-\r
-post_save.connect(on_vote, sender=Vote)\r
-\r
-\r
-def on_vote_canceled(instance, **kwargs):\r
- if instance.content_object.node_type in ("question", "answer") and not instance.content_object.wiki:\r
- post = instance.content_object.leaf\r
- question = (post.__class__ == Question) and post or post.question\r
-\r
- if instance.vote == -1:\r
- instance.user.reputes.create(value=int(settings.REP_GAIN_BY_CANCELING_DOWNVOTE),\r
- question=question, reputation_type=TYPE_REPUTATION_GAIN_BY_CANCELING_DOWNVOTE)\r
-\r
- repute_type, repute_value = (instance.vote == 1) and (\r
- TYPE_REPUTATION_LOST_BY_UPVOTE_CANCELED, -int(settings.REP_LOST_BY_UPVOTE_CANCELED)) or (\r
- TYPE_REPUTATION_GAIN_BY_DOWNVOTE_CANCELED, int(settings.REP_GAIN_BY_DOWNVOTE_CANCELED))\r
-\r
- post.author.reputes.create(value=repute_value, question=question, reputation_type=repute_type)\r
-\r
-mark_canceled.connect(on_vote_canceled, sender=Vote)\r
-\r
-\r
- \r
-\r
-\r
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)
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):
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'])
from django.utils.translation import ugettext_lazy as _\r
from django.forms.widgets import Textarea\r
\r
-BASIC_SET = SettingSet('basic', _('Basic Settings'), _("The basic settings for your application"), 1)\r
+BASIC_SET = SettingSet('basic', _('Basic settings'), _("The basic settings for your application"), 1)\r
\r
APP_LOGO = Setting('APP_LOGO', '/m/default/media/images/logo.png', BASIC_SET, dict(\r
label = _("Application logo"),\r
from django.utils.translation import ugettext_lazy as _\r
from django.forms.widgets import PasswordInput\r
\r
-EMAIL_SET = SettingSet('email', _('Email Settings'), _("Email server and other email related settings."), 50)\r
+EMAIL_SET = SettingSet('email', _('Email settings'), _("Email server and other email related settings."), 50)\r
\r
EMAIL_HOST = Setting('EMAIL_HOST', '', EMAIL_SET, dict(\r
label = _("Email Server"),\r
help_text = _("This is the code you get when you register your site at <a href='https://www.google.com/webmasters/tools/'>Google webmaster central</a>."),\r
required=False))\r
\r
-GOOGLE_ANALYTICS_KEY = Setting('GOOGLE_ANALYTICS_KEY', '', EXT_KEYS_SET, dict( \r
+GOOGLE_ANALYTICS_KEY = Setting('GOOGLE_ANALYTICS_KEY', '', EXT_KEYS_SET, dict(\r
label = _("Google analytics key"),\r
help_text = _("Your Google analytics key. You can get one at the <a href='http://www.google.com/analytics/'>Google analytics official website</a>"),\r
required=False))\r
-\r
WORDPRESS_API_KEY = Setting('WORDPRESS_API_KEY', '', EXT_KEYS_SET, dict(\r
label = _("Wordpress API key"),\r
help_text = _("Your Wordpress API key. You can get one at <a href='http://wordpress.com/'>http://wordpress.com/</a>"),\r
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
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:
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
elif name in data:
return data[name]
+class StringListWidget(forms.Widget):
+ def render(self, name, value, attrs=None):
+ ret = ""
+ for s in value:
+ ret += """
+ <div>
+ <input type="text" name="%(name)s" value="%(value)s" />
+ <button class="string_list_widget_button">-</button>
+ </div>
+ """ % {'name': name, 'value': s}
+
+ return """
+ <div class="string_list_widgets">
+ %(ret)s
+ <div><button name="%(name)s" class="string_list_widget_button add">+</button></div>
+ </div>
+ """ % 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]
+
--- /dev/null
+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))
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',
if (providers_small) {
openid_btns.append('<br/>');
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'));
}
}
--- /dev/null
+$(function() {\r
+ $('.string_list_widget_button').live('click', function() {\r
+ $but = $(this);\r
+\r
+ if ($but.is('.add')) {\r
+ $new = $("<div style=\"display: none\">" +\r
+ "<input type=\"text\" name=\"" + $but.attr('name') + "\" value=\"\" />" +\r
+ "<button class=\"string_list_widget_button\">-</button>" +\r
+ "</div>");\r
+\r
+ $but.before($new);\r
+ $new.slideDown('fast');\r
+ } else {\r
+ $but.parent().slideUp('fast', function() {\r
+ $but.parent().remove();\r
+ });\r
+ }\r
+\r
+ return false;\r
+ })\r
+});
\ No newline at end of file
var response_commands = {\r
+ refresh_page: function() {\r
+ window.location.reload(true)\r
+ },\r
+ \r
update_post_score: function(id, inc) {\r
var $score_board = $('#post-' + id + '-score');\r
var current = parseInt($score_board.html())\r
});\r
},\r
\r
- insert_comment: function(post_id, comment_id, comment, username, profile_url, delete_url) {\r
+ insert_comment: function(post_id, comment_id, comment, username, profile_url, delete_url, edit_url) {\r
var $container = $('#comments-container-' + post_id);\r
var skeleton = $('#new-comment-skeleton-' + post_id).html().toString();\r
\r
.replace(new RegExp('%COMMENT%', 'g'), comment)\r
.replace(new RegExp('%USERNAME%', 'g'), username)\r
.replace(new RegExp('%PROFILE_URL%', 'g'), profile_url)\r
- .replace(new RegExp('%DELETE_URL%', 'g'), delete_url);\r
+ .replace(new RegExp('%DELETE_URL%', 'g'), delete_url)\r
+ .replace(new RegExp('%EDIT_URL%', 'g'), edit_url);\r
\r
$container.append(skeleton);\r
\r
}\r
},\r
\r
+ unmark_deleted: function(post_type, post_id) {\r
+ if (post_type == 'answer') {\r
+ var $answer = $('#answer-container-' + post_id);\r
+ $answer.removeClass('deleted');\r
+ } else {\r
+ var $container = $('#question-table');\r
+ $container.removeClass('deleted');\r
+ }\r
+ },\r
+\r
set_subscription_button: function(text) {\r
$('.subscription_switch').html(text);\r
},\r
}\r
}\r
\r
-function show_message(object, msg) {\r
+function show_message(object, msg, callback) {\r
var div = $('<div class="vote-notification"><h3>' + msg + '</h3>(' +\r
'click to close' + ')</div>');\r
\r
div.click(function(event) {\r
- $(".vote-notification").fadeOut("fast", function() { $(this).remove(); });\r
+ $(".vote-notification").fadeOut("fast", function() {\r
+ $(this).remove();\r
+ if (callback) {\r
+ callback();\r
+ }\r
+ });\r
});\r
\r
object.parent().append(div);\r
div.fadeIn("fast");\r
}\r
\r
-function process_ajax_response(data, el) {\r
+function load_prompt(object, url) {\r
+ var $box = $('<div class="vote-notification">' +\r
+ '<img src="/m/default/media/images/indicator.gif" />' +\r
+ '</div>');\r
+\r
+\r
+ object.parent().append($box);\r
+ $box.fadeIn("fast");\r
+\r
+ $box.load(url, function() {\r
+ $box.find('.prompt-cancel').click(function() {\r
+ $box.fadeOut('fast', function() {\r
+ $box.remove();\r
+ });\r
+ return false;\r
+ });\r
+\r
+ $box.find('.prompt-submit').click(function() {\r
+ start_command();\r
+ $.post(url, {prompt: $box.find('textarea').val()}, function(data) {\r
+ $box.fadeOut('fast', function() {\r
+ $box.remove();\r
+ });\r
+ process_ajax_response(data, object);\r
+ }, 'json');\r
+ return false;\r
+ });\r
+ });\r
+}\r
+\r
+function show_prompt(object, msg, callback) {\r
+ var div = $('<div class="vote-notification">' + msg + '<br />' +\r
+ '<textarea class="command-prompt"></textarea><br />' +\r
+ '<button class="prompt-cancel">Cancel</button>' +\r
+ '<button class="prompt-ok">OK</button>' +\r
+ '</div>');\r
+\r
+ function fade_out() {\r
+ div.fadeOut("fast", function() { div.remove(); });\r
+ }\r
+\r
+ div.find('.prompt-cancel').click(fade_out);\r
+\r
+ div.find('.prompt-ok').click(function(event) {\r
+ callback(div.find('.command-prompt').val());\r
+ fade_out();\r
+ });\r
+\r
+ object.parent().append(div);\r
+ div.fadeIn("fast"); \r
+}\r
+\r
+function process_ajax_response(data, el, callback) {\r
if (!data.success && data['error_message'] != undefined) {\r
- show_message(el, data.error_message)\r
+ show_message(el, data.error_message, function() {if (callback) callback(true);});\r
+ end_command(false);\r
} else if (typeof data['commands'] != undefined){\r
for (var command in data.commands) {\r
response_commands[command].apply(null, data.commands[command])\r
}\r
\r
if (data['message'] != undefined) {\r
- show_message(el, data.message)\r
+ show_message(el, data.message, function() {if (callback) callback(false);})\r
+ } else {\r
+ if (callback) callback(false);\r
}\r
+ end_command(true);\r
+ }\r
+}\r
+\r
+var running = false;\r
+\r
+function start_command() {\r
+ $('body').append($('<div id="command-loader"></div>'));\r
+ running = true;\r
+}\r
+\r
+function end_command(success) {\r
+ if (success) {\r
+ $('#command-loader').addClass('success');\r
+ $('#command-loader').fadeOut("slow", function() {\r
+ $('#command-loader').remove();\r
+ running = false;\r
+ });\r
+ } else {\r
+ $('#command-loader').remove();\r
+ running = false;\r
}\r
}\r
\r
$(function() {\r
$('a.ajax-command').live('click', function() {\r
+ if (running) return false;\r
+\r
var el = $(this);\r
- $.getJSON(el.attr('href'), function(data) {\r
- process_ajax_response(data, el);\r
- });\r
+\r
+ if (el.is('.withprompt')) {\r
+ load_prompt(el, el.attr('href'));\r
+ } else {\r
+ start_command();\r
+ $.getJSON(el.attr('href'), function(data) {\r
+ process_ajax_response(data, el);\r
+ });\r
+ }\r
\r
return false\r
});\r
var $container = $(this);\r
var $form = $container.find('form');\r
var $textarea = $container.find('textarea');\r
- var $button = $container.find('input[type="submit"]');\r
- var $chars_left_message = $('.comment-chars-left');\r
+ var textarea = $textarea.get(0);\r
+ var $button = $container.find('.comment-submit');\r
+ var $cancel = $container.find('.comment-cancel');\r
+ var $chars_left_message = $container.find('.comments-chars-left-msg');\r
+ var $chars_togo_message = $container.find('.comments-chars-togo-msg');\r
var $chars_counter = $container.find('.comments-char-left-count');\r
\r
var $comment_tools = $container.parent().find('.comment-tools');\r
var $add_comment_link = $comment_tools.find('.add-comment-link');\r
var $comments_container = $container.parent().find('.comments-container');\r
\r
- var max_length = parseInt($chars_counter.html());\r
+ var chars_limits = $chars_counter.html().split('|');\r
+\r
+ var min_length = parseInt(chars_limits[0]);\r
+ var max_length = parseInt(chars_limits[1]);\r
+ \r
+ var warn_length = max_length - 30;\r
+ var current_length = 0;\r
var comment_in_form = false;\r
+ var interval = null;\r
+\r
+ var hcheck = !($.browser.msie || $.browser.opera);\r
+\r
+ $textarea.css("padding-top", 0).css("padding-bottom", 0).css("resize", "none");\r
+ textarea.style.overflow = 'hidden';\r
+ \r
\r
function cleanup_form() {\r
$textarea.val('');\r
+ $textarea.css('height', 80);\r
$chars_counter.html(max_length);\r
$chars_left_message.removeClass('warn');\r
comment_in_form = false;\r
+ current_length = 0;\r
+\r
+ $chars_left_message.hide();\r
+ $chars_togo_message.show();\r
+ \r
+ $chars_counter.removeClass('warn');\r
+ $chars_counter.html(min_length);\r
+ $button.attr("disabled","disabled");\r
+ \r
+ interval = null;\r
}\r
\r
cleanup_form();\r
\r
- function calculate_chars_left() {\r
+ function process_form_changes() {\r
var length = $textarea.val().length;\r
- var allow = true;\r
\r
- if (length < max_length) {\r
- if (length < max_length * 0.75) {\r
- $chars_left_message.removeClass('warn');\r
- } else {\r
- $chars_left_message.addClass('warn');\r
- }\r
+ if (current_length == length)\r
+ return;\r
+\r
+ if (length < warn_length && current_length >= warn_length) {\r
+ $chars_counter.removeClass('warn');\r
+ } else if (current_length < warn_length && length >= warn_length){\r
+ $chars_counter.addClass('warn');\r
+ }\r
+\r
+ if (length < min_length) {\r
+ $chars_left_message.hide();\r
+ $chars_togo_message.show();\r
+ $chars_counter.html(min_length - length);\r
+ } else {\r
+ $chars_togo_message.hide();\r
+ $chars_left_message.show();\r
+ $chars_counter.html(max_length - length);\r
+ }\r
+\r
+ if (length > max_length || length < min_length) {\r
+ $button.attr("disabled","disabled");\r
} else {\r
- allow = false;\r
+ $button.removeAttr("disabled");\r
}\r
\r
- $chars_counter.html(max_length - length);\r
- return allow;\r
+ var current_height = textarea.style.height;\r
+ if (hcheck)\r
+ textarea.style.height = "0px";\r
+\r
+ var h = Math.max(80, textarea.scrollHeight);\r
+ textarea.style.height = current_height;\r
+ $textarea.animate({height: h + 'px'}, 50);\r
+\r
+ current_length = length;\r
}\r
\r
function show_comment_form() {\r
$container.slideDown('slow');\r
$add_comment_link.fadeOut('slow');\r
+ window.setInterval(function() {\r
+ process_form_changes();\r
+ }, 200);\r
}\r
\r
function hide_comment_form() {\r
+ if (interval != null) {\r
+ window.clearInterval(interval);\r
+ interval = null;\r
+ }\r
$container.slideUp('slow');\r
$add_comment_link.fadeIn('slow');\r
}\r
$('#' + $comments_container.attr('id') + ' .comment-edit').live('click', function() {\r
var $link = $(this);\r
var comment_id = /comment-(\d+)-edit/.exec($link.attr('id'))[1];\r
- var $comment = $link.parents('.comment');\r
- var comment_text = $comment.find('.comment-text').text().trim();\r
+ var $comment = $('#comment-' + comment_id);\r
\r
comment_in_form = comment_id;\r
- $textarea.val(comment_text);\r
- calculate_chars_left();\r
+\r
+ $.get($link.attr('href'), function(data) {\r
+ $textarea.val(data);\r
+ });\r
+ \r
$comment.slideUp('slow');\r
show_comment_form();\r
return false;\r
});\r
\r
- $textarea.keyup(calculate_chars_left);\r
-\r
$button.click(function() {\r
- if ($textarea.val().length > max_length) {\r
- show_message($button, "Your comment exceeds the max number of characters allowed.");\r
- } else {\r
- var post_data = {\r
- comment: $textarea.val()\r
- }\r
+ if (running) return false;\r
\r
- if (comment_in_form) {\r
- post_data['id'] = comment_in_form;\r
- }\r
+ var post_data = {\r
+ comment: $textarea.val()\r
+ }\r
\r
- $.post($form.attr('action'), post_data, function(data) {\r
- process_ajax_response(data, $button);\r
- cleanup_form();\r
- }, "json")\r
+ if (comment_in_form) {\r
+ post_data['id'] = comment_in_form;\r
}\r
\r
+ start_command();\r
+ $.post($form.attr('action'), post_data, function(data) {\r
+ process_ajax_response(data, $button, function(error) {\r
+ if (!error) {\r
+ cleanup_form();\r
+ hide_comment_form();\r
+ }\r
+ });\r
+\r
+ }, "json");\r
+ \r
+ return false;\r
+ });\r
+\r
+ $cancel.click(function() {\r
+ if (comment_in_form) {\r
+ $comment = $('#comment-' + comment_in_form).slideDown('slow');\r
+ }\r
hide_comment_form();\r
return false;\r
});\r
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;
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;
}
#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
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 {
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
+}
margin-top: 5px;
}
-div.comments-container { padding: 0; }
-
.answer {
border-bottom: 1px solid #CCCCCE;
padding-top: 10px;
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;
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;
}
.post-controls {
- float: left;
font-size: 11px;
line-height: 12px;
margin-bottom: 5px;
#question-controls .tags { margin: 0 0 3px; }
-.post-update-info-container {
- float: right;
- min-width: 190px;
-}
-
.post-update-info {
display: inline-block;
float: right;
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; }
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;
}
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; }
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;
}
.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 {
}
.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
$('#pre-collapse').text(txt);
});
- // Tags autocomplete action
+ //Tags autocomplete action
$("#id_tags").autocomplete("/matching_tags", {
minChars: 1,
matchContains: true,
<h3 class="or_label">{% trans 'Or...' %}</h3>\r
{% endif %}\r
<div style="width:600px;float:left;margin-bottom:5px;">\r
- {% trans "Click to sign in through any of these services." %}\r
+ {% blocktrans %}\r
+ External login services use <b><a href="http://openid.net/">OpenID</a></b> technology, where your password always stays confidential between\r
+ you and your login provider and you don't have to remember another one.\r
+ {% endblocktrans %}\r
</div>\r
{% if request.user.is_anonymous %}\r
<div style="width:600px;float:left;margin-bottom:5px;">\r
<div id="bigicon_providers">\r
{% for provider in bigicon_providers %}\r
<div class="provider_logo big" name="{{ provider.id }}">\r
- {% ifequal provider.type "DIRECT" %}\r
- <a class="provider_direct" href="{% url auth_provider_signin provider=provider.id %}">\r
- <img src="{% media provider.icon %}" />\r
- </a>\r
- {% endifequal %}\r
- {% ifequal provider.type "CUSTOM" %}\r
- {% include provider.code_template %}\r
- {% endifequal %}\r
- {% ifequal provider.type "SIMPLE_FORM" %}\r
- <img alt="{{ provider.simple_form_context.your_what }}" class="simple_form_provider" src="{% media provider.icon %}" />\r
- {% endifequal %}\r
+ <div class="inner">\r
+ {% ifequal provider.type "DIRECT" %}\r
+ <a class="provider_direct" href="{% url auth_provider_signin provider=provider.id %}">\r
+ <img src="{% media provider.icon %}" />\r
+ </a>\r
+ {% endifequal %}\r
+ {% ifequal provider.type "CUSTOM" %}\r
+ {% include provider.code_template %}\r
+ {% endifequal %}\r
+ {% ifequal provider.type "SIMPLE_FORM" %}\r
+ <img alt="{{ provider.simple_form_context.your_what }}" class="simple_form_provider" src="{% media provider.icon %}" />\r
+ {% endifequal %}\r
+ </div>\r
</div>\r
{% endfor %}\r
</div>\r
<div id="smallicon_providers">\r
{% for provider in smallicon_providers %}\r
<div class="provider_logo small" name="{{ provider.id }}">\r
- {% ifequal provider.type "DIRECT" %}\r
- <a class="provider_direct" href="{% url auth_provider_signin provider=provider.id %}">\r
- <img src="{% media provider.icon %}" />\r
- </a>\r
- {% endifequal %}\r
- {% ifequal provider.type "CUSTOM" %}\r
- {% include provider.code_template %}\r
- {% endifequal %}\r
- {% ifequal provider.type "SIMPLE_FORM" %}\r
- <img alt="{{ provider.simple_form_context.your_what }}" class="simple_form_provider" src="{% media provider.icon %}" />\r
- {% endifequal %}\r
+ <div class="inner">\r
+ {% ifequal provider.type "DIRECT" %}\r
+ <a class="provider_direct" href="{% url auth_provider_signin provider=provider.id %}">\r
+ <img src="{% media provider.icon %}" />\r
+ </a>\r
+ {% endifequal %}\r
+ {% ifequal provider.type "CUSTOM" %}\r
+ {% include provider.code_template %}\r
+ {% endifequal %}\r
+ {% ifequal provider.type "SIMPLE_FORM" %}\r
+ <img alt="{{ provider.simple_form_context.your_what }}" class="simple_form_provider" src="{% media provider.icon %}" />\r
+ {% endifequal %}\r
+ </div>\r
</div>\r
{% endfor %}\r
</div>\r
</form>\r
{% endfor %}\r
<h3 class="or_label">{% trans 'Or...' %}</h3>\r
- <fieldset>\r
- {% trans 'Click' %} <a href="{% url auth_request_tempsignin %}">here</a> {% trans "if you're having troubles signing in." %}\r
- </fieldset>\r
+ <form name="signin_form" id="dummy_form_unused" class="signin_form" method="POST" action="">\r
+ <fieldset>\r
+ {% trans 'Click' %} <a href="{% url auth_request_tempsignin %}">here</a> {% trans "if you're having troubles signing in." %}\r
+ </fieldset>\r
+ </form>\r
<script type="text/html" id="simple_form_template">\r
<fieldset id="slot_form">\r
<p id="provider_name_slot">{% trans 'Enter your ' %}%%YOUR_WHAT%%</p>\r
<a href="http://openid.net/get/" target="_blank">{% trans "Get OpenID" %} </a>\r
</p>\r
</div>\r
-{% endblock%}
\ No newline at end of file
+{% endblock%}\r
<!-- template badge.html -->
{% load i18n %}
{% load extra_tags %}
+{% load user_tags %}
{% load humanize %}
{% block title %}{% spaceless %}{{ badge.name }} - {% trans "Badge" %}{% endspaceless %}{% endblock %}
{% block forejs %}
</div>
<div id="award-list" style="clear:both;margin-left:20px;line-height:25px;">
{% for award in awards %}
- <p style="width:180px;float:left"><a href="{% url users %}{{ award.id }}/{{ award.name }}">{{ award.name }}</a> {% get_score_badge_by_details award.rep award.gold award.silver award.bronze %}</p>
+ <p style="width:220px;float:left">{% user_signature award.user "badges" %}<span class="tag-number"> × {{ award.count|intcomma }}</span></p>
{% endfor %}
</div>
{% block content %}
<div class="headNormal">
{% trans "FAQ" %}
-</div>
+ </div>
<div class="content">
{{ text|markdown }}
</div>
<div class="comments-container" id="comments-container-{{ post.id }}">\r
{% for comment in comments %}\r
<a name="{{ comment.id }}"></a>\r
- <table class="comment{% if not comment.top_scorer %} not_top_scorer{% endif %}" id="comment-{{comment.id}}">\r
- <tr>\r
- <td rowspan="2" class="comment-score" id="post-{{ comment.id }}-score">\r
- {% if comment.score %}{{ comment.score }}{% endif %}\r
- </td>\r
- <td class="comment-text" id="comment-{{comment.id}}-text">\r
- {{ comment.body }}\r
- </td>\r
- </tr>\r
- <tr>\r
- <td class="comment-info" id="comment-{{comment.id}}-info">\r
- <a class="comment-user userinfo" href="{{comment.user.get_profile_url}}">{{comment.user}}</a>\r
- <span class="comment-age">({% diff_date comment.added_at %})</span>\r
- {% if comment.can_like %}\r
- <a id="post-{{ comment.id }}-upvote" href="{% url vote_post id=comment.id,vote_type='up' %}"\r
- title="{% trans "I like this comment (click again to cancel)" %}" class="ajax-command comment-like{% if comment.likes %} on{% endif %}"\r
- rel="nofollow"> </a>\r
- {% endif %}\r
- {% if comment.can_edit %}\r
- <a id="comment-{{ comment.id }}-edit" href="#" title="{% trans "Edit comment" %}"\r
- class="comment-edit" rel="nofollow"> </a>\r
- {% endif %}\r
- {% if comment.can_delete %}\r
- <a id="comment-{{ comment.id }}-delete" href="{% url delete_comment id=comment.id %}" title="{% trans "Delete comment" %}"\r
- class="ajax-command comment-delete" rel="nofollow"> </a>\r
- {% endif %}\r
- </td>\r
- </tr>\r
- </table>\r
+ <div class="comment{% if not comment.top_scorer %} not_top_scorer{% endif %}" id="comment-{{comment.id}}">\r
+ <div id="post-{{ comment.id }}-score" class="comment-score">{% if comment.score %}{{ comment.score }}{% endif %}</div>\r
+ <div class="comment-text">{{ comment.comment }}</div>\r
+ <div class="comment-info" id="comment-{{comment.id}}-info">\r
+ {% if comment.can_like %}\r
+ <a id="post-{{ comment.id }}-upvote" href="{% url like_comment id=comment.id %}"\r
+ title="{% trans "I like this comment (click again to cancel)" %}" class="ajax-command comment-like{% if comment.likes %} on{% endif %}"\r
+ rel="nofollow"> </a>\r
+ {% endif %}\r
+ {% if comment.can_edit %}\r
+ <a id="comment-{{ comment.id }}-edit" href="{% url node_markdown id=comment.id %}" title="{% trans "Edit comment" %}"\r
+ class="comment-edit" rel="nofollow"> </a>\r
+ {% endif %}\r
+ {% if comment.can_delete %}\r
+ <a id="comment-{{ comment.id }}-delete" href="{% url delete_comment id=comment.id %}" title="{% trans "Delete comment" %}"\r
+ class="ajax-command comment-delete" rel="nofollow"> </a>\r
+ {% endif %}\r
+ <span class="comment-age">({% diff_date comment.added_at %})</span>\r
+ <a class="comment-user userinfo" href="{{comment.user.get_profile_url}}">{{comment.user}}</a>\r
+ {% if show_gravatar %}{% gravatar comment.user 18 %}{% endif %}\r
+ </div>\r
+ </div>\r
{% endfor %}\r
</div>\r
<div id="comment-tools-{{ post.id }}" class="comment-tools">\r
- <img src="/m/default/media/images/gray-up-arrow-h18px.png" />\r
{% ifnotequal showing total %}\r
<span class="comments-showing">\r
{% blocktrans %}showing {{ showing }} of {{ total }}{% endblocktrans %}\r
</div>\r
{% if can_comment %}\r
<div id="comment-{{ post.id }}-form-container" class="comment-form-container">\r
- <form id="comment-{{ post.id }}-form" method="post" action="{% url comment id=post.id %}">\r
+ <form id="comment-{{ post.id }}-form" method="post" action="{% url comment id=post.id %}" accept-charset="utf-8">\r
<div class="comment-form-widgets-container">\r
<textarea name="comment"></textarea>\r
- <input type="submit" value="{% trans " add comment" %}" />\r
+ <div class="comment-form-buttons">\r
+ <span id="comment-{{ post.id }}-chars-left" class="comment-chars-left">\r
+ <span class="comments-char-left-count">{{ min_length }}|{{ max_length }}</span>\r
+ <span class="comments-chars-togo-msg">{% trans "characters to go" %}</span>\r
+ <span class="comments-chars-left-msg">{% trans "characters left" %}</span>\r
+ </span>\r
+ <input type="submit" class="comment-submit" value="{% trans " comment" %}" />\r
+ <input type="submit" class="comment-cancel" value="{% trans " cancel" %}" />\r
+ </div>\r
</div>\r
- <span id="comment-{{ post.id }}-chars-left" class="comment-chars-left">\r
- {% blocktrans %}\r
- have <span class="comments-char-left-count">{{ max_length }}</span> characters left\r
- {% endblocktrans %}\r
- </span>\r
<script type="text/html" class="new-comment-skeleton" id="new-comment-skeleton-{{ post.id }}">\r
- <table class="comment" id="comment-%ID%" style="display: none">\r
- <tr>\r
- <td rowspan="2" class="comment-score" id="comment-%ID%-score"></td>\r
- <td class="comment-text" id="comment-%ID%-text">%COMMENT%</td>\r
- </tr>\r
- <tr>\r
- <td class="comment-info" id="comment-%ID%-info">\r
- <a class="comment-user" href="%PROFILE_URL%">%USERNAME%</a>\r
- <span class="comment-age">({% trans "just now" %})</span>\r
- <a id="comment-%ID%-edit" href="#"\r
- class="comment-edit" rel="nofollow"> </a>\r
- <a id="comment-%ID%-delete" href="%DELETE_URL%"\r
- class="ajax-command comment-delete" rel="nofollow"> </a>\r
- </td>\r
- </tr>\r
- </table>\r
+ <div class="comment{% if not comment.top_scorer %} not_top_scorer{% endif %}" id="comment-%ID%">\r
+ <div id="post-%ID%-score" class="comment-score"></div>\r
+ <div class="comment-text">%COMMENT%</div>\r
+ <div class="comment-info" id="comment-{{comment.id}}-info">\r
+ <a id="comment-%ID%-edit" href="%EDIT_URL%"\r
+ class="comment-edit" rel="nofollow"> </a>\r
+ <a id="comment-%ID%-delete" href="%DELETE_URL%"\r
+ class="ajax-command comment-delete" rel="nofollow"> </a>\r
+ <span class="comment-age">({% trans "just now" %})</span>\r
+ <a class="comment-user" href="%PROFILE_URL%">%USERNAME%</a>\r
+ {% if user.is_authenticated %}\r
+ {% if show_gravatar %}{% gravatar user 18 %}{% endif %}\r
+ {% endif %}\r
+ </div>\r
+ </div>\r
</script>\r
</form>\r
</div>\r
{% spaceless %}\r
{% for control in controls %}\r
<span class="action-link">\r
- <a title="{{ control.title }}" {% if control.command %}class="ajax-command"{% endif %}\r
+ <a title="{{ control.title }}" class="{% if control.command %}ajax-command{% endif %}{% if control.withprompt %} withprompt{% endif %}"\r
href="{{ control.url }}">{{ control.text }}</a>\r
</span>\r
{% ifnotequal controls|last control %}\r
--- /dev/null
+{% load i18n %}\r
+\r
+<div class="user-prompt">\r
+ {% trans "Please select a reason bellow or use the text box to input your own reason." %}\r
+ <select class="prompt-examples">\r
+ {% for type in types %}\r
+ <option value="{{ type }}">{{ type }}</option>\r
+ {% endfor %}\r
+ </select>\r
+ <textarea>{{ types|first }}</textarea>\r
+ <div class="prompt-buttons">\r
+ <button class="prompt-cancel">{% trans "Cancel" %}</button><button class="prompt-submit">{% trans "Send" %}</button>\r
+ </div>\r
+</div>\r
+<script>\r
+$('.user-prompt .prompt-examples').change(function() {\r
+ $('.user-prompt textarea').val($(this).val()) \r
+})\r
+</script>
\ No newline at end of file
\r
{% block forejs %}\r
<link rel="stylesheet" type="text/css" media="screen" href="{% media "/media/style/admin.css" %}"/>\r
+ <script type="text/javascript" src="{% media "/media/js/osqa.admin.js" %}"></script>\r
{% block adminjs %}{% endblock %}\r
{% endblock %}\r
\r
\r
{% block sidebar %}\r
<div class="boxC">\r
- <h3 class="subtitle">{% trans "Administration menu" %}</h3>\r
- <ul>\r
- {% for set in sets %}\r
- <li><a href="{% url admin_set set.name %}">{{ set.title }}</a></li>\r
- {% endfor %}\r
- </ul>\r
+ <h3 class="subtitle">{% trans "Administration menu" %}</h3>\r
+ <ul>\r
+ {% for set in sets %}\r
+ <li><a href="{% url admin_set set.name %}">{{ set.title }}</a></li>\r
+ {% endfor %}\r
+ </ul>\r
</div>\r
{% if markdown %}\r
\r
{% endif %}\r
{% endblock %}\r
\r
-\r
-\r
+ \r
<h3>{% trans "Recent activity" %}</h3>\r
<table width="100%">\r
{% for activity in recent_activity %}\r
- {% activity_item activity %}\r
+ {% activity_item activity request.user %}\r
{% endfor %}\r
</table>\r
</td>\r
{% get_score_badge post.author %}</p>
{% endif %}
{% else %}
- {% if post.last_edited_at %}
+ {% if post.last_edited %}
<p style="line-height:12px;">
{% ifequal post_type 'question' %}
<a href="{% url question_revisions post.id %}">
{% else %}
<a href="{% url answer_revisions post.id %}">
{% endifequal %}
- {% trans "updated" %} <strong>{% diff_date post.last_edited_at %}</strong>
+ {% trans "updated" %} <strong>{% diff_date post.last_edited.at %}</strong>
</a>
</p>
- {% if post.author != post.last_edited_by or wiki %}
- {% gravatar post.last_edited_by 32 %}
- <p style="float:left">{{post.last_edited_by.get_profile_link}}<br/>
- {% get_score_badge post.last_edited_by %}</p>
+ {% if post.author != post.last_edited.by or wiki %}
+ {% gravatar post.last_edited.by 32 %}
+ <p style="float:left">{{post.last_edited.by.get_profile_link}}<br/>
+ {% get_score_badge post.last_edited.by %}</p>
{% endif %}
{% endif %}
{% endifequal %}
{% load humanize %}\r
{% load i18n %}\r
{% load cache %}\r
-{% block title %}{% spaceless %}{{ question.get_question_title }}{% endspaceless %}{% endblock %}\r
+{% block title %}{% spaceless %}{{ question.headline }}{% endspaceless %}{% endblock %}\r
{% block forejs %}\r
<meta name="description" content="{{question.summary}}" />\r
<meta name="keywords" content="{{question.tagname_meta_generator}}" />\r
{% endif %}\r
\r
<script type="text/javascript">\r
- // define reputation needs for comments\r
- var repNeededForComments = 50;\r
$().ready(function(){\r
$("#nav_questions").attr('className',"on");\r
var answer_sort_tab = "{{ tab_id }}";\r
\r
{% block content %}\r
<div class="headNormal">\r
- <a href="{{ question.get_absolute_url }}">{{ question.get_question_title }}</a>\r
+ <a href="{{ question.get_absolute_url }}">{{ question.headline }}</a>\r
</div>\r
<div id="main-body" class="">\r
<div id="askform">\r
</td>\r
</tr>\r
</table>\r
- {% if question.closed %}\r
+ {% if question.marked %}\r
<div class="question-status" style="margin-bottom:15px">\r
- <h3>{% blocktrans with question.get_close_reason_display as close_reason %}The question has been closed for the following reason "{{ close_reason }}" by{% endblocktrans %} \r
- <a href="{{ question.closed_by.get_profile_url }}">{{ question.closed_by.username }}</a> \r
- {% blocktrans with question.closed_at as closed_at %}close date {{closed_at}}{% endblocktrans %}</h3>\r
+ <h3>\r
+ {% blocktrans with question.closed.extra as close_reason %}\r
+ The question has been closed for the following reason "{{ close_reason }}" by\r
+ {% endblocktrans %}\r
+ <a href="{{ question.closed.by.get_profile_url }}">{{ question.closed.by.username }}</a>\r
+ {% diff_date question.closed.at %}\r
+ </h3>\r
</div>\r
{% endif %}\r
{% if answers %}\r
\r
{% for question in similar_questions %}\r
<p>\r
- <a href="{{ question.get_absolute_url }}">{{ question.get_question_title }}</a>\r
+ <a href="{{ question.get_absolute_url }}">{{ question.headline }}</a>\r
</p>\r
{% endfor %}\r
\r
</div>
<input id="ignoredTagInput" autocomplete="off" type="text"/>
<input id="ignoredTagAdd" type="submit" value="{% trans "Add" %}"/>
+ {% comment %}
<p id="hideIgnoredTagsControl">
<input id="hideIgnoredTagsCb" type="checkbox" {% if request.user.hide_ignored_questions %}checked="checked"{% endif %} />
<label id="hideIgnoredTagsLabel" for="hideIgnoredTagsCb">{% trans "keep ignored questions hidden" %}</label>
<p>
+ {% endcomment %}
</div>
{% endif %}
<div id="askform">
<form id="fmretag" action="{% url edit_question question.id %}" method="post" >
<h3>
- {{ question.get_question_title }}
+ {{ question.headline }}
</h3>
<div id="description" class="edit-content-html">
{{ question.html|safe }}
<div class="qstA">
<h2>
- <a href="{{ question.get_absolute_url }}">{{ question.get_question_title }}</a>
+ <a href="{{ question.get_absolute_url }}">{{ question.headline }}</a>
</h2>
<div class="stat">
<table>
{% trans "Reopen question" %}
</div>
<div id="main-body" style="width:100%">
- <p>{% trans "Open the previously closed question" %}: <a href="{{ question.get_absolute_url }}"><span class="big">{{ question.get_question_title }}</span></a>
+ <p>{% trans "Open the previously closed question" %}: <a href="{{ question.get_absolute_url }}"><span class="big">{{ question.headline }}</span></a>
</p>
<p><strong>{% trans "The question was closed for the following reason " %}"{{ question.get_close_reason_display }}"{% trans "reason - leave blank in english" %} <a href="{{ question.closed_by.get_profile_url }}">{{ question.closed_by.username }}</a> {% trans "on "%} {% diff_date question.closed_at %}<font class="darkred">{% trans "date closed" %}</font>
<ul class="badge-list">\r
{% for award in awards %}\r
<li>\r
- <a href="{% url badges %}{{award.badge_id}}/{{award.badge_name}}" title="{{ award.badge_description }}" class="medal">\r
- <span class="badge{{ award.badge_type }}">●</span> {{ award.badge_name }}</a>\r
- <a href="/users/{{ award.user_id }}/{{ award.user_name|slugify }}/">{{ award.user_name }}</a>\r
+ <a href="{% url badges %}{{award.badge.id}}/{{award.badge.name|slugify}}" title="{{ award.badge.description }}" class="medal">\r
+ <span class="badge{{ award.badge.type }}">●</span> {{ award.badge.name }}</a>\r
+ <a href="/users/{{ award.user_id }}/{{ award.user_name|slugify }}/">{{ award.user.username }}</a>\r
</li>\r
{% endfor %}\r
</ul>\r
{% load extra_tags %}\r
{% load humanize %}\r
+{% load extra_tags %}\r
\r
-<div style="clear:both;line-height:20px" >\r
- <div style="width:180px;float:left">{% diff_date active_at 3 %}</div>\r
- <div style="width:150px;float:left">\r
- <span class="user-action-{{ type }}">{{ description }}</span>\r
+<div class="action_container">\r
+ <div class="action_body">\r
+ {{ describe }}\r
</div>\r
- <div style="float:left;overflow:hidden;">\r
- {% if badge %}\r
- <a href="{{ url }}" title="{{ title }}" class="medal"><span class="badge{{ badge_type }}">●</span> {{ title }}</a>\r
- {% else %}\r
- <span class="post-type-{{ type }}"><a href="{{ url }}">{{ title }}</a></span>\r
- {% if revision %}<span class="revision-summary">{{ summary }}</span>{% endif %}\r
- {% endif %}\r
- <div style="height:5px"></div>\r
+ <div class="action_date" style="text-align: right;">\r
+ {% diff_date action.action_date %}\r
</div>\r
</div>
\ No newline at end of file
{% load i18n %}\r
{% block title %}{% spaceless %}{% trans "Edit user profile" %}{% endspaceless %}{% endblock %}\r
{% block forejs %}\r
- <script type="text/javascript">google.load("jquery", "1.4.2");google.load("jqueryui", "1.8.1");</script>\r
+ <script type="text/javascript">google.load("jquery", "1.4.2");</script>\r
\r
<link rel="stylesheet" href="http://jquery-ui.googlecode.com/svn/tags/latest/themes/base/jquery-ui.css" type="text/css" media="all" />\r
<link rel="stylesheet" href="http://static.jquery.com/ui/css/demo-docs-theme/ui.theme.css" type="text/css" media="all" />\r
\r
+ <script src="{% media "/media/js/effects.core.min.js" %}" type="text/javascript"></script>\r
+ <script src="{% media "/media/js/ui.core.js" %}" type="text/javascript"></script>\r
+ <script src="{% media "/media/js/ui.datepicker.js" %}" type="text/javascript"></script>\r
+\r
<script type="text/javascript">\r
$().ready(function(){\r
$("#id_birthday").datepicker({\r
title="gravatar {% trans "image associated with your email address" %}">{% blocktrans %}avatar, see {{gravatar_faq_url}}{% endblocktrans %}</a>\r
</div>\r
</div>\r
-\r
+ \r
<div id="askform" style="float:right;width:750px;text-align:left;">\r
<h2>{% trans "Registered user" %}</h2>\r
<table class="user-details">\r
{% load humanize %}
{% load smart_if %}
{% load i18n %}
+{% load user_tags %}
<div id="subheader" class="headUser">
{{view_user.username}}
</div>
<table class="user-details">
{% if view_user != request.user and request.user.is_superuser %}
<tr>
- <td class="admin" align="left" colspan="2">
- <h3>{% trans "Moderate this user" %}</h3>
- <form id="moderate_user_form" method="post">
- {{moderate_user_form.as_p}}
- </form>
- <p id="action_status"></p>
+ <td class="moderation" align="left" colspan="2">
+ {% comment %}{% user_moderation request.user view_user %}{% endcomment %}
</td>
</tr>
{% endif %}
<tr>
<!--todo - redo this with blocktrans -->
{% if view_user.date_of_birth.year != 1900%}
- <td>{% trans "age" %}</td>
- <td>{% get_age view_user.date_of_birth %} {% trans "age unit" %}</td>
+ <td>{% trans "age" %}</td>
+ <td>{% get_age view_user.date_of_birth %} {% trans "age unit" %}</td>
{% endif %}
</tr>
{% endif %}
--- /dev/null
+{% load i18n %}\r
+\r
+<h3>{% trans "Moderation tools" %}</h3>\r
+<p><a href="#" class="ajax-command">{% trans "Reputation bonus" %}</a></p>\r
{% load question_list_tags %}
{% block usercontent %}
<div class="user-stats-table">
- {% for question in questions %}
- {% question_list_item question favorite_count=yes signature_type=badges %}
+ {% for favorite in favorites %}
+ {% question_list_item favorite.node favorite_count=yes signature_type=badges %}
{% endfor %}
</div>
{% endblock %}
{% block usercontent %}
<div style="padding-top:5px;font-size:13px;">
{% for act in activities %}
- {% activity_item act %}
+ {% activity_item act request.user %}
{% endfor %}
</div>
{% endblock %}
<div style="float:left;width:20px;color:red">{{ rep.negative }}</div>
</div>
- <a href="{{ rep.question.get_absolute_url }}">{{ rep.question.title }}</a> <span class="small">({{ rep.reputed_at }})</span>
+ <a href="{{ rep.action.node.get_absolute_url }}">{{ rep.action.node.headline }}</a> <span class="small">({{ rep.date }})</span>
</p>
{% endfor %}
</div>
<table>
<tr>
<td width="180" style="line-height:35px">
- {% for award in awards %}
- <a href="{% url badges %}{{award.id}}/{{award.name}}" title="{{ award.description }}" class="medal"><span class="badge{{ award.type }}">●</span> {{ award.name }}</a><span class="tag-number"> × {{ award.count|intcomma }}</span><br/>
+ {% for award, count in awards %}
+ <a href="{% url badges %}{{award.id}}/{{award.name}}" title="{{ award.description }}" class="medal"><span class="badge{{ award.type }}">●</span> {{ award.name }}</a><span class="tag-number"> × {{ count|intcomma }}</span><br/>
{% if forloop.counter|divisibleby:"6" %}
</td>
<td width="180" style="line-height:35px">
<div style="clear:both;line-height:20px" >
<div style="width:150px;float:left">{% diff_date vote.voted_at 3 %}</div>
<div style="width:30px;float:left">
- {% ifequal vote.vote 1 %}
+ {% ifequal vote.value 1 %}
<img src="{% media "/media/images/vote-arrow-up-on.png" %}" title="{% trans "upvote" %}">
{% else %}
<img src="{% media "/media/images/vote-arrow-down-on.png" %}" title="{% trans "downvote" %}">
-import forum.activity
-import forum.reputation
import forum.badges
import forum.subscriptions
import re\r
import datetime\r
from forum.models import User, Question, Comment, QuestionSubscription, SubscriptionSettings, Answer\r
-from forum.models.user import activity_record\r
-from forum.models.node import node_create\r
from forum.utils.mail import send_email\r
-from forum.views.readers import question_view\r
from django.utils.translation import ugettext as _\r
+from forum.actions import AskAction, AnswerAction, CommentAction, AcceptAnswerAction, UserJoinsAction, QuestionViewAction\r
from django.conf import settings\r
from django.db.models import Q, F\r
-from django.db.models.signals import post_save\r
-from django.contrib.contenttypes.models import ContentType\r
-import const\r
\r
def create_subscription_if_not_exists(question, user):\r
try:\r
def create_recipients_dict(usr_list):\r
return [(s['username'], s['email'], {'username': s['username']}) for s in usr_list]\r
\r
-def question_posted(instance, **kwargs):\r
- question = instance\r
+def question_posted(action, new):\r
+ question = action.node\r
\r
subscribers = User.objects.values('email', 'username').filter(\r
Q(subscription_settings__enable_notifications=True, subscription_settings__new_question='i') |\r
for user in new_subscribers:\r
create_subscription_if_not_exists(question, user)\r
\r
-node_create.connect(question_posted, sender=Question)\r
+AskAction.hook(question_posted)\r
\r
\r
-def answer_posted(instance, **kwargs):\r
- answer = instance\r
+def answer_posted(action, new):\r
+ answer = action.node\r
question = answer.question\r
\r
subscribers = question.subscribers.values('email', 'username').filter(\r
recipients, "notifications/newanswer.html", {\r
'question': question,\r
'answer': answer\r
- })\r
+ }, threaded=False)\r
\r
if answer.author.subscription_settings.questions_answered:\r
create_subscription_if_not_exists(question, answer.author)\r
\r
-node_create.connect(answer_posted, sender=Answer)\r
+AnswerAction.hook(answer_posted)\r
\r
\r
-def comment_posted(instance, **kwargs):\r
- comment = instance\r
+def comment_posted(action, new):\r
+ comment = action.node\r
post = comment.content_object\r
\r
if post.__class__ == Question:\r
\r
q_filter = Q(subscription_settings__notify_comments=True) | Q(subscription_settings__notify_comments_own_post=True, id=post.author.id)\r
\r
- inreply = re.search('@\w+', comment.comment)\r
- if inreply is not None:\r
- q_filter = q_filter | Q(subscription_settings__notify_reply_to_comments=True,\r
- username__istartswith=inreply.group(0)[1:],\r
- comments__object_id=post.id,\r
- comments__content_type=ContentType.objects.get_for_model(post.__class__)\r
- )\r
+ #inreply = re.search('@\w+', comment.comment)\r
+ #if inreply is not None:\r
+ # q_filter = q_filter | Q(subscription_settings__notify_reply_to_comments=True,\r
+ # username__istartswith=inreply.group(0)[1:],\r
+ ## comments__object_id=post.id,\r
+ # comments__content_type=ContentType.objects.get_for_model(post.__class__)\r
+ # )\r
\r
subscribers = subscribers.filter(\r
q_filter, subscription_settings__subscribed_questions='i', subscription_settings__enable_notifications=True\r
'comment': comment,\r
'post': post,\r
'question': question,\r
- })\r
+ }, threaded=False)\r
\r
if comment.user.subscription_settings.questions_commented:\r
create_subscription_if_not_exists(question, comment.user)\r
\r
-node_create.connect(comment_posted, sender=Comment)\r
+CommentAction.hook(comment_posted)\r
\r
\r
-def answer_accepted(instance, created, **kwargs):\r
- if not created and 'accepted' in instance.get_dirty_fields() and instance.accepted:\r
- question = instance.question\r
+def answer_accepted(action, new):\r
+ question = action.node.question\r
\r
- subscribers = question.subscribers.values('email', 'username').filter(\r
- subscription_settings__enable_notifications=True,\r
- subscription_settings__notify_accepted=True,\r
- subscription_settings__subscribed_questions='i'\r
- ).exclude(id=instance.accepted_by.id).distinct()\r
- recipients = create_recipients_dict(subscribers)\r
+ subscribers = question.subscribers.values('email', 'username').filter(\r
+ subscription_settings__enable_notifications=True,\r
+ subscription_settings__notify_accepted=True,\r
+ subscription_settings__subscribed_questions='i'\r
+ ).exclude(id=instance.accepted_by.id).distinct()\r
+ recipients = create_recipients_dict(subscribers)\r
\r
- send_email(settings.EMAIL_SUBJECT_PREFIX + _("An answer to '%(question_title)s' was accepted") % dict(question_title=question.title),\r
- recipients, "notifications/answeraccepted.html", {\r
- 'question': question,\r
- 'answer': instance\r
- })\r
+ send_email(settings.EMAIL_SUBJECT_PREFIX + _("An answer to '%(question_title)s' was accepted") % dict(question_title=question.title),\r
+ recipients, "notifications/answeraccepted.html", {\r
+ 'question': question,\r
+ 'answer': action.node\r
+ }, threaded=False)\r
\r
-post_save.connect(answer_accepted, sender=Answer)\r
+AcceptAnswerAction.hook(answer_accepted)\r
\r
\r
-def member_joined(sender, instance, created, **kwargs):\r
- if not created:\r
- return\r
- \r
+def member_joined(action, new):\r
subscribers = User.objects.values('email', 'username').filter(\r
subscription_settings__enable_notifications=True,\r
subscription_settings__member_joins='i'\r
- ).exclude(id=instance.id).distinct()\r
+ ).exclude(id=action.user.id).distinct()\r
\r
recipients = create_recipients_dict(subscribers)\r
\r
send_email(settings.EMAIL_SUBJECT_PREFIX + _("%(username)s is a new member on %(app_name)s") % dict(username=instance.username, app_name=settings.APP_SHORT_NAME),\r
recipients, "notifications/newmember.html", {\r
- 'newmember': instance,\r
- })\r
-\r
- sub_settings = SubscriptionSettings(user=instance)\r
- sub_settings.save()\r
+ 'newmember': action.user,\r
+ }, threaded=False)\r
\r
-post_save.connect(member_joined, sender=User, weak=False)\r
+UserJoinsAction.hook(member_joined)\r
\r
-def question_viewed(instance, user, **kwargs):\r
- if not user.is_authenticated():\r
+def question_viewed(action, new):\r
+ if not action.viewuser.is_authenticated():\r
return\r
- \r
+\r
try:\r
- subscription = QuestionSubscription.objects.get(question=instance, user=user)\r
+ subscription = QuestionSubscription.objects.get(question=action.question, user=action.viewuser)\r
subscription.last_view = datetime.datetime.now()\r
subscription.save()\r
except:\r
- if user.subscription_settings.questions_viewed:\r
- subscription = QuestionSubscription(question=instance, user=user)\r
+ if action.viewuser.subscription_settings.questions_viewed:\r
+ subscription = QuestionSubscription(question=action.question, user=action.viewuser)\r
subscription.save()\r
\r
-question_view.connect(question_viewed)\r
-\r
-#todo: this stuff goes temporarily here\r
-from forum.models import Award, Answer\r
-\r
-def notify_award_message(instance, created, **kwargs):\r
- if created:\r
- user = instance.user\r
-\r
- msg = (u"Congratulations, you have received a badge '%s'. " \\r
- + u"Check out <a href=\"%s\">your profile</a>.") \\r
- % (instance.badge.name, user.get_profile_url())\r
-\r
- user.message_set.create(message=msg)\r
+QuestionViewAction.hook(question_viewed)\r
\r
-post_save.connect(notify_award_message, sender=Award)\r
\r
#todo: translate this\r
-record_answer_event_re = re.compile("You have received (a|\d+) .*new response.*")\r
-def record_answer_event(instance, created, **kwargs):\r
- if created:\r
- q_author = instance.question.author\r
- found_match = False\r
- #print 'going through %d messages' % q_author.message_set.all().count()\r
- for m in q_author.message_set.all():\r
- #print m.message\r
- match = record_answer_event_re.search(m.message)\r
- if match:\r
- found_match = True\r
- try:\r
- cnt = int(match.group(1))\r
- except:\r
- cnt = 1\r
- m.message = u"You have received %d <a href=\"%s?sort=responses\">new responses</a>."\\r
- % (cnt+1, q_author.get_profile_url())\r
-\r
- m.save()\r
- break\r
- if not found_match:\r
- msg = u"You have received a <a href=\"%s?sort=responses\">new response</a>."\\r
- % q_author.get_profile_url()\r
-\r
- q_author.message_set.create(message=msg)\r
-\r
-post_save.connect(record_answer_event, sender=Answer)
\ No newline at end of file
+#record_answer_event_re = re.compile("You have received (a|\d+) .*new response.*")\r
+#def record_answer_event(instance, created, **kwargs):\r
+# if created:\r
+# q_author = instance.question.author\r
+# found_match = False\r
+# #print 'going through %d messages' % q_author.message_set.all().count()\r
+# for m in q_author.message_set.all():\r
+## #print m.message\r
+# # match = record_answer_event_re.search(m.message)\r
+# if match:\r
+# found_match = True\r
+# try:\r
+# cnt = int(match.group(1))\r
+# except:\r
+# cnt = 1\r
+## m.message = u"You have received %d <a href=\"%s?sort=responses\">new responses</a>."\\r
+# # % (cnt+1, q_author.get_profile_url())\r
+#\r
+# m.save()\r
+# break\r
+# if not found_match:\r
+# msg = u"You have received a <a href=\"%s?sort=responses\">new response</a>."\\r
+# % q_author.get_profile_url()\r
+#\r
+# q_author.message_set.create(message=msg)\r
+#\r
+#post_save.connect(record_answer_event, sender=Answer)
\ No newline at end of file
@register.simple_tag
def diff_date(date, limen=2):
+ if not date:
+ return _('unknown')
+
now = datetime.datetime.now()#datetime(*time.localtime()[0:6])#???
diff = now - date
days = diff.days
\r
@register.inclusion_tag('sidebar/recent_awards.html')\r
def recent_awards():\r
- return {'awards': Award.objects.get_recent_awards()[:RECENT_AWARD_SIZE]}
\ No newline at end of file
+ return {'awards': Award.objects.order_by('-awarded_at')[:RECENT_AWARD_SIZE]}
\ No newline at end of file
from datetime import datetime, timedelta\r
\r
-from forum.models import Question, FavoriteQuestion\r
+from forum.models import Question, Action\r
from django.utils.translation import ugettext as _\r
from django.core.urlresolvers import reverse\r
from django import template\r
-from django.conf import settings\r
+from forum.actions import *\r
+from forum import settings\r
\r
register = template.Library()\r
\r
@register.inclusion_tag('node/vote_buttons.html')\r
def vote_buttons(post, user):\r
- context = {\r
- 'post': post,\r
- 'user_vote': 'none'\r
- }\r
+ context = dict(post=post, user_vote='none')\r
\r
if user.is_authenticated():\r
- try:\r
- vote = post.votes.get(user=user)\r
- context['user_vote'] = vote.is_upvote() and 'up' or 'down'\r
- except:\r
- pass\r
+ context['user_vote'] = {1: 'up', -1: 'down', None: 'none'}[VoteAction.get_for(user, post)]\r
\r
return context\r
\r
@register.inclusion_tag('node/favorite_mark.html')\r
def favorite_mark(question, user):\r
try:\r
- FavoriteQuestion.objects.get(question=question, user=user)\r
+ FavoriteAction.objects.get(node=question, user=user)\r
favorited = True\r
except:\r
favorited = False\r
\r
- favorite_count = question.favorited_by.count()\r
-\r
- return {'favorited': favorited, 'favorite_count': favorite_count, 'question': question}\r
+ return {'favorited': favorited, 'favorite_count': question.favorite_count, 'question': question}\r
\r
-def post_control(text, url, command=False, title=""):\r
- return {'text': text, 'url': url, 'command': command, 'title': title}\r
+def post_control(text, url, command=False, withprompt=False, title=""):\r
+ return {'text': text, 'url': url, 'command': command, 'withprompt': withprompt ,'title': title}\r
\r
@register.inclusion_tag('node/post_controls.html')\r
def post_controls(post, user):\r
\r
if post_type == 'question':\r
if post.closed and user.can_reopen_question(post):\r
- controls.append(post_control(_('reopen'), reverse('reopen', kwargs={'id': post.id})))\r
+ controls.append(post_control(_('reopen'), reverse('reopen', kwargs={'id': post.id}), command=True))\r
elif not post.closed and user.can_close_question(post):\r
- controls.append(post_control(_('close'), reverse('close', kwargs={'id': post.id})))\r
+ controls.append(post_control(_('close'), reverse('close', kwargs={'id': post.id}), command=True, withprompt=True))\r
\r
if user.can_flag_offensive(post):\r
- label = _('flag')\r
+ label = _('report')\r
\r
if user.can_view_offensive_flags(post):\r
- label = "%s (%d)" % (label, post.flaggeditems.count())\r
+ label = "%s (%d)" % (label, post.flag_count)\r
\r
controls.append(post_control(label, reverse('flag_post', kwargs={'id': post.id}),\r
- command=True, title=_("report as offensive (i.e containing spam, advertising, malicious text, etc.)")))\r
+ command=True, withprompt=True, title=_("report as offensive (i.e containing spam, advertising, malicious text, etc.)")))\r
\r
if user.can_delete_post(post):\r
- controls.append(post_control(_('delete'), reverse('delete_post', kwargs={'id': post.id}),\r
- command=True))\r
+ if post.deleted:\r
+ controls.append(post_control(_('undelete'), reverse('delete_post', kwargs={'id': post.id}),\r
+ command=True))\r
+ else:\r
+ controls.append(post_control(_('delete'), reverse('delete_post', kwargs={'id': post.id}),\r
+ command=True))\r
\r
return {'controls': controls}\r
\r
@register.inclusion_tag('node/comments.html')\r
def comments(post, user):\r
- all_comments = post.comments.filter(deleted=False).order_by('added_at')\r
+ all_comments = post.comments.filter(deleted=None).order_by('added_at')\r
\r
if len(all_comments) <= 5:\r
top_scorers = all_comments\r
showing += 1\r
\r
if context['can_like']:\r
- try:\r
- c.votes.get(user=user)\r
- context['likes'] = True\r
- except:\r
- context['likes'] = False\r
+ context['likes'] = VoteAction.get_for(user, c) == 1\r
\r
context['user'] = c.user\r
+ context['comment'] = c.comment\r
context.update(dict(c.__dict__))\r
comments.append(context)\r
\r
'post': post,\r
'can_comment': user.can_comment(post),\r
'max_length': settings.FORM_MAX_COMMENT_BODY,\r
+ 'min_length': settings.FORM_MIN_COMMENT_BODY,\r
+ 'show_gravatar': settings.FORM_GRAVATAR_IN_COMMENTS,\r
'showing': showing,\r
'total': len(all_comments),\r
+ 'user': user,\r
}\r
from django import template\r
from django.utils.translation import ugettext as _\r
+from django.utils.safestring import mark_safe\r
from forum import const\r
\r
register = template.Library()\r
class ActivityNode(template.Node):\r
template = template.loader.get_template('users/activity.html')\r
\r
- def __init__(self, activity):\r
+ def __init__(self, activity, viewer):\r
self.activity = template.Variable(activity)\r
+ self.viewer = template.Variable(viewer)\r
\r
def render(self, context):\r
try:\r
- activity = self.activity.resolve(context)\r
-\r
- context = {\r
- 'active_at': activity.active_at,\r
- 'description': activity.type_as_string,\r
- 'type': activity.activity_type,\r
- }\r
-\r
- if activity.activity_type == const.TYPE_ACTIVITY_PRIZE:\r
- context['badge'] = True\r
- context['title'] = activity.content_object.badge.name\r
- context['url'] = activity.content_object.badge.get_absolute_url()\r
- context['badge_type'] = activity.content_object.badge.type\r
- else:\r
- context['title'] = activity.node.headline\r
- context['url'] = activity.node.get_absolute_url()\r
-\r
- if activity.activity_type in (const.TYPE_ACTIVITY_UPDATE_ANSWER, const.TYPE_ACTIVITY_UPDATE_QUESTION):\r
- context['revision'] = True\r
- context['summary'] = activity.content_object.summary or \\r
- _('Revision n. %(rev_number)d') % {'rev_number': activity.content_object.revision}\r
-\r
- return self.template.render(template.Context(context))\r
+ action = self.activity.resolve(context).leaf()\r
+ viewer = self.viewer.resolve(context)\r
+ describe = mark_safe(action.describe(viewer))\r
+ return self.template.render(template.Context(dict(action=action, describe=describe)))\r
except Exception, e:\r
- return ''\r
+ #import sys, traceback\r
+ #traceback.print_exc(file=sys.stdout)\r
+ pass\r
\r
@register.tag\r
def activity_item(parser, token):\r
try:\r
- tag_name, activity = token.split_contents()\r
+ tag_name, activity, viewer = token.split_contents()\r
except ValueError:\r
- raise template.TemplateSyntaxError, "%r tag requires exactly one arguments" % token.contents.split()[0]\r
+ raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]\r
+\r
+ return ActivityNode(activity, viewer)\r
+\r
\r
- return ActivityNode(activity)\r
+@register.inclusion_tag('users/moderation.html')\r
+def user_moderation(moderator, user):\r
+ \r
+ return dict(user=user)\r
url(r'^%s%s$' % (_('questions/'), _('ask/')), app.writers.ask, name='ask'),
url(r'^%s%s$' % (_('questions/'), _('unanswered/')), app.readers.unanswered, name='unanswered'),
url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('edit/')), app.writers.edit_question, name='edit_question'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('close/')), app.commands.close, name='close'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')), app.commands.reopen, name='reopen'),
+ url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('close/')), app.commands.close, kwargs=dict(close=True), name='close'),
+ url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')), app.commands.close, kwargs=dict(close=False), name='reopen'),
url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('answer/')), app.writers.answer, name='answer'),
url(r'^%s(?P<id>\d+)/(?P<vote_type>[a-z]+)/' % _('vote/'), app.commands.vote_post, name='vote_post'),
url(r'^%s(?P<id>\d+)/' % _('delete/'), app.commands.delete_post, name='delete_post'),
url(r'^%s(?P<id>\d+)/$' % _('subscribe/'), app.commands.subscribe, name="subscribe"),
url(r'^%s' % _('matching_tags/'), app.commands.matching_tags, name='matching_tags'),
-
+ url(r'^%s(?P<id>\d+)/' % _('node_markdown/'), app.commands.node_markdown, name='node_markdown'),
+
url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')), app.readers.revisions, name='question_revisions'),
- url(r'^%s$' % _('command/'), app.commands.ajax_command, name='call_ajax'),
#place general question item in the end of other operations
url(r'^%s(?P<id>\d+)/(?P<slug>[\w-]*)$' % _('question/'), app.readers.question, name='question'),
url(r'^%s$' % _('users/'),app.users.users, name='users'),
- url(r'^%s(?P<id>\d+)/$' % _('moderate-user/'), app.users.moderate_user, name='moderate_user'),
url(r'^%s(?P<id>\d+)/%s$' % (_('users/'), _('edit/')), app.users.edit_user, name='edit_user'),
url(r'^%s(?P<id>\d+)/(?P<slug>.+)/%s$' % (_('users/'), _('subscriptions/')), app.users.user_subscriptions, name='user_subscriptions'),
url(r'^%s(?P<id>\d+)/(?P<slug>.+)/$' % _('users/'), app.users.user_stats, name='user_profile'),
url(r'^%s$' % _('badges/'),app.meta.badges, name='badges'),
- url(r'^%s(?P<id>\d+)//*' % _('badges/'), app.meta.badge, name='badge'),
- url(r'^%s%s$' % (_('messages/'), _('markread/')),app.commands.read_message, name='read_message'),
+ url(r'^%s(?P<id>\d+)/(?P<slug>.+)/$' % _('badges/'), app.meta.badge, name='badge'),
# (r'^admin/doc/' % _('admin/doc'), include('django.contrib.admindocs.urls')),
url(r'^%s(.*)' % _('nimda/'), admin.site.root, name='osqa_admin'),
url(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}, name='feeds'),
from forum.settings.base import Setting
from forum.settings.forms import SettingsSetForm
-from forum.models import Activity, Question, Answer, User, Node
+from forum.models import Question, Answer, User, Node, Action
from forum import const
from forum import settings
return sorted(Setting.sets.values(), lambda s1, s2: s1.weight - s2.weight)
def get_recent_activity():
- return Activity.objects.filter(activity_type__in=(
- const.TYPE_ACTIVITY_ASK_QUESTION, const.TYPE_ACTIVITY_ANSWER,
- const.TYPE_ACTIVITY_COMMENT_QUESTION, const.TYPE_ACTIVITY_COMMENT_ANSWER,
- const.TYPE_ACTIVITY_MARK_ANSWER)).order_by('-active_at')[0:10]
+ return Action.objects.order_by('-action_date')[0:30]
def get_statistics():
return {
'total_users': User.objects.all().count(),
'users_last_24': User.objects.filter(date_joined__gt=(datetime.now() - timedelta(days=1))).count(),
- 'total_questions': Question.objects.filter(deleted=False).count(),
- 'questions_last_24': Question.objects.filter(deleted=False, added_at__gt=(datetime.now() - timedelta(days=1))).count(),
- 'total_answers': Answer.objects.filter(deleted=False).count(),
- 'answers_last_24': Answer.objects.filter(deleted=False, added_at__gt=(datetime.now() - timedelta(days=1))).count(),
+ 'total_questions': Question.objects.filter(deleted=None).count(),
+ 'questions_last_24': Question.objects.filter(deleted=None, added_at__gt=(datetime.now() - timedelta(days=1))).count(),
+ 'total_answers': Answer.objects.filter(deleted=None).count(),
+ 'answers_last_24': Answer.objects.filter(deleted=None, added_at__gt=(datetime.now() - timedelta(days=1))).count(),
}
@super_user_required
from forum.utils.mail import send_email
from forum.authentication.base import InvalidAuthentication
-from forum.authentication import AUTH_PROVIDERS, user_logged_in
+from forum.authentication import AUTH_PROVIDERS
from forum.models import AuthKeyUserAssociation, ValidationHash, Question, Answer
+from forum.actions import UserJoinsAction
def signin_page(request, action=None):
if action is None:
user_.is_superuser = True
user_.save()
+ UserJoinsAction(user=user_, ip=request.META['REMOTE_ADDR']).save()
if not user_.email_isvalid:
send_validation_email(user_)
request.session['auth_error'] = _("Oops, something went wrong in the middle of this process. Please try again.")
return HttpResponseRedirect(request.session.get('on_signin_url', reverse('auth_signin')))
- uassoc = AuthKeyUserAssociation(user=user_, key=request.session['assoc_key'], provider=request.session['auth_provider'])
+ uassoc = AuthKeyUserAssociation(user=user_, key=assoc_key, provider=auth_provider)
uassoc.save()
if email_feeds_form.cleaned_data['subscribe'] == 'n':
user.backend = "django.contrib.auth.backends.ModelBackend"
login(request, user)
- user_logged_in.send(user=user,old_session=old_session,sender=None)
+ #user_logged_in.send(user=user,old_session=old_session,sender=None)
if not forward:
signin_action = request.session.get('on_signin_action', None)
from django.template import RequestContext
from forum.models import *
from forum.forms import CloseForm
+from forum.actions import *
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from forum.utils.decorators import ajax_method, ajax_login_required
-from decorators import command
+from decorators import command, CommandException
+from forum import settings
import logging
-class NotEnoughRepPointsException(Exception):
+class NotEnoughRepPointsException(CommandException):
def __init__(self, action):
super(NotEnoughRepPointsException, self).__init__(
_("""
""" % {'action': action, 'faq_url': reverse('faq')})
)
-class CannotDoOnOwnException(Exception):
+class CannotDoOnOwnException(CommandException):
def __init__(self, action):
super(CannotDoOnOwnException, self).__init__(
_("""
""" % {'action': action, 'faq_url': reverse('faq')})
)
-class AnonymousNotAllowedException(Exception):
+class AnonymousNotAllowedException(CommandException):
def __init__(self, action):
super(AnonymousNotAllowedException, self).__init__(
_("""
""" % {'action': action, 'signin_url': reverse('auth_signin')})
)
-class SpamNotAllowedException(Exception):
+class SpamNotAllowedException(CommandException):
def __init__(self, action = "comment"):
super(SpamNotAllowedException, self).__init__(
_("""Your %s has been marked as spam.""" % action)
)
-class NotEnoughLeftException(Exception):
+class NotEnoughLeftException(CommandException):
def __init__(self, action, limit):
super(NotEnoughLeftException, self).__init__(
_("""
""" % {'action': action, 'limit': limit, 'faq_url': reverse('faq')})
)
-class CannotDoubleActionException(Exception):
+class CannotDoubleActionException(CommandException):
def __init__(self, action):
super(CannotDoubleActionException, self).__init__(
_("""
@command
def vote_post(request, id, vote_type):
post = get_object_or_404(Node, id=id).leaf
- vote_score = vote_type == 'up' and 1 or -1
user = request.user
if not user.is_authenticated():
if user_vote_count_today >= int(settings.MAX_VOTES_PER_DAY):
raise NotEnoughLeftException(_('votes'), str(settings.MAX_VOTES_PER_DAY))
+ new_vote_cls = (vote_type == 'up') and VoteUpAction or VoteDownAction
+ score_inc = 0
+
try:
- vote = post.votes.get(canceled=False, user=user)
+ old_vote = Action.objects.get_for_types((VoteUpAction, VoteDownAction), node=post, user=user)
- if vote.voted_at < datetime.datetime.now() - datetime.timedelta(days=int(settings.DENY_UNVOTE_DAYS)):
- raise Exception(
+ if old_vote.action_date < datetime.datetime.now() - datetime.timedelta(days=int(settings.DENY_UNVOTE_DAYS)):
+ raise CommandException(
_("Sorry but you cannot cancel a vote after %(ndays)d %(tdays)s from the original vote") %
{'ndays': int(settings.DENY_UNVOTE_DAYS), 'tdays': ungettext('day', 'days', int(settings.DENY_UNVOTE_DAYS))}
)
- vote.cancel()
- vote_type = 'none'
+ old_vote.cancel(ip=request.META['REMOTE_ADDR'])
+ score_inc += (old_vote.__class__ == VoteDownAction) and 1 or -1
except ObjectDoesNotExist:
- #there is no vote yet
- vote = Vote(user=user, node=post, vote=vote_score)
- vote.save()
+ old_vote = None
+
+ if old_vote.__class__ != new_vote_cls:
+ new_vote_cls(user=user, node=post, ip=request.META['REMOTE_ADDR']).save()
+ score_inc += (new_vote_cls == VoteUpAction) and 1 or -1
+ else:
+ vote_type = "none"
response = {
'commands': {
- 'update_post_score': [id, vote.vote * (vote_type == 'none' and -1 or 1)],
+ 'update_post_score': [id, score_inc],
'update_user_post_vote': [id, vote_type]
}
}
- votes_left = int(settings.MAX_VOTES_PER_DAY) - user_vote_count_today + (vote_type == 'none' and -1 or 1)
+ votes_left = (int(settings.MAX_VOTES_PER_DAY) - user_vote_count_today) + (vote_type == 'none' and -1 or 1)
if int(settings.START_WARN_VOTES_LEFT) >= votes_left:
response['message'] = _("You have %(nvotes)s %(tvotes)s left today.") % \
@command
def flag_post(request, id):
+ if not request.POST:
+ return render_to_response('node/report.html', {'types': settings.FLAG_TYPES})
+
post = get_object_or_404(Node, id=id)
user = request.user
raise NotEnoughLeftException(_('flags'), str(settings.MAX_FLAGS_PER_DAY))
try:
- post.flaggeditems.get(user=user)
- raise CannotDoubleActionException(_('flag'))
+ current = FlagAction.objects.get(user=user, node=post)
+ raise CommandException(_("You already flagged this post with the following reason: %(reason)s") % {'reason': current.extra})
except ObjectDoesNotExist:
- flag = FlaggedItem(user=user, content_object=post)
- flag.save()
+ reason = request.POST.get('prompt', '').strip()
- return {}
+ if not len(reason):
+ raise CommandException(_("Reason is empty"))
+
+ FlagAction(user=user, node=post, extra=reason, ip=request.META['REMOTE_ADDR']).save()
+
+ return {'message': _("Thank you for your report. A moderator will review your submission shortly.")}
@command
def like_comment(request, id):
raise NotEnoughRepPointsException( _('like comments'))
try:
- like = LikedComment.active.get(comment=comment, user=user)
- like.cancel()
+ like = VoteUpCommentAction.objects.get(node=comment, user=user)
+ like.cancel(ip=request.META['REMOTE_ADDR'])
likes = False
except ObjectDoesNotExist:
- like = LikedComment(comment=comment, user=user)
- like.save()
+ VoteUpCommentAction(node=comment, user=user, ip=request.META['REMOTE_ADDR']).save()
likes = True
return {
'commands': {
- 'update_comment_score': [comment.id, likes and 1 or -1],
- 'update_likes_comment_mark': [comment.id, likes and 'on' or 'off']
+ 'update_post_score': [comment.id, likes and 1 or -1],
+ 'update_user_post_vote': [comment.id, likes and 'up' or 'none']
}
}
if not user.can_delete_comment(comment):
raise NotEnoughRepPointsException( _('delete comments'))
- comment.mark_deleted(user)
+ if not comment.deleted:
+ DeleteAction(node=comment, user=user, ip=request.META['REMOTE_ADDR']).save()
return {
'commands': {
raise AnonymousNotAllowedException(_('mark a question as favorite'))
try:
- favorite = FavoriteQuestion.objects.get(question=question, user=request.user)
- favorite.delete()
+ favorite = FavoriteAction.objects.get(node=question, user=request.user)
+ favorite.cancel(ip=request.META['REMOTE_ADDR'])
added = False
except ObjectDoesNotExist:
- favorite = FavoriteQuestion(question=question, user=request.user)
- favorite.save()
+ FavoriteAction(node=question, user=request.user, ip=request.META['REMOTE_ADDR']).save()
added = True
return {
raise AnonymousNotAllowedException(_('comment'))
if not request.method == 'POST':
- raise Exception(_("Invalid request"))
-
- if 'id' in request.POST:
- comment = get_object_or_404(Comment, id=request.POST['id'])
-
- if not user.can_edit_comment(comment):
- raise NotEnoughRepPointsException( _('edit comments'))
- else:
- if not user.can_comment(post):
- raise NotEnoughRepPointsException( _('comment'))
-
- comment = Comment(parent=post)
+ raise CommandException(_("Invalid request"))
comment_text = request.POST.get('comment', '').strip()
if not len(comment_text):
- raise Exception(_("Comment is empty"))
+ raise CommandException(_("Comment is empty"))
- if not len(comment_text) > settings.FORM_MIN_COMMENT_BODY:
- raise Exception(_("Comment must be at least %s characters" % settings.FORM_MIN_COMMENT_BODY))
+ if len(comment_text) < settings.FORM_MIN_COMMENT_BODY:
+ raise CommandException(_("At least %d characters required on comment body.") % settings.FORM_MIN_COMMENT_BODY)
- comment.create_revision(user, body=comment_text)
+ if len(comment_text) > settings.FORM_MAX_COMMENT_BODY:
+ raise CommandException(_("No more than %d characters on comment body.") % settings.FORM_MAX_COMMENT_BODY)
data = {
"user_ip":request.META["REMOTE_ADDR"],
"user_agent":request.environ['HTTP_USER_AGENT'],
- "comment_author":request.user.real_name,
+ "comment_author":request.user.username,
"comment_author_email":request.user.email,
"comment_author_url":request.user.website,
"comment":comment_text
if Node.isSpam(comment_text, data):
raise SpamNotAllowedException()
+ if 'id' in request.POST:
+ comment = get_object_or_404(Comment, id=request.POST['id'])
+
+ if not user.can_edit_comment(comment):
+ raise NotEnoughRepPointsException( _('edit comments'))
+
+ comment = ReviseAction(user=user, node=comment, ip=request.META['REMOTE_ADDR']).save(data=dict(text=comment_text)).node
+ else:
+ if not user.can_comment(post):
+ raise NotEnoughRepPointsException( _('comment'))
+
+ comment = CommentAction(user=user, ip=request.META['REMOTE_ADDR']).save(data=dict(text=comment_text, parent=post)).node
+
if comment.active_revision.revision == 1:
return {
'commands': {
'insert_comment': [
- id, comment.id, comment_text, user.username, user.get_profile_url(), reverse('delete_comment', kwargs={'id': comment.id})
+ id, comment.id, comment.comment, user.username, user.get_profile_url(),
+ reverse('delete_comment', kwargs={'id': comment.id}), reverse('node_markdown', kwargs={'id': comment.id})
]
}
}
}
}
+@command
+def node_markdown(request, id):
+ user = request.user
+
+ if not user.is_authenticated():
+ raise AnonymousNotAllowedException(_('accept answers'))
+
+ node = get_object_or_404(Node, id=id)
+ return HttpResponse(node.body, mimetype="text/plain")
+
@command
def accept_answer(request, id):
question = answer.question
if not user.can_accept_answer(answer):
- raise Exception(_("Sorry but only the question author can accept an answer"))
+ raise CommandException(_("Sorry but only the question author can accept an answer"))
commands = {}
if answer.accepted:
- answer.unmark_accepted(user)
+ answer.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
commands['unmark_accepted'] = [answer.id]
else:
- if question.accepted_answer is not None:
+ if question.answer_accepted:
accepted = question.accepted_answer
- accepted.unmark_accepted(user)
+ accepted.accepted.cancel(user, ip=request.META['REMOTE_ADDR'])
commands['unmark_accepted'] = [accepted.id]
- answer.mark_accepted(user)
+ AcceptAnswerAction(node=answer, user=user, ip=request.META['REMOTE_ADDR']).save()
commands['mark_accepted'] = [answer.id]
return {'commands': commands}
if not (user.can_delete_post(post)):
raise NotEnoughRepPointsException(_('delete posts'))
- post.mark_deleted(user)
+ ret = {'commands': {}}
+
+ if post.deleted:
+ post.deleted.cancel(user, ip=request.META['REMOTE_ADDR'])
+ ret['commands']['unmark_deleted'] = [post.node_type, id]
+ else:
+ DeleteAction(node=post, user=user, ip=request.META['REMOTE_ADDR']).save()
+
+ ret['commands']['mark_deleted'] = [post.node_type, id]
+
+ return ret
+
+@command
+def close(request, id, close):
+ if close and not request.POST:
+ return render_to_response('node/report.html', {'types': settings.CLOSE_TYPES})
+
+ question = get_object_or_404(Question, id=id)
+ user = request.user
+
+ if not user.is_authenticated():
+ raise AnonymousNotAllowedException(_('close questions'))
+
+ if question.extra_action:
+ if not user.can_reopen_question(question):
+ raise NotEnoughRepPointsException(_('reopen questions'))
+
+ question.extra_action.cancel(user, ip=request.META['REMOTE_ADDR'])
+ else:
+ if not request.user.can_close_question(question):
+ raise NotEnoughRepPointsException(_('close questions'))
+
+ reason = request.POST.get('prompt', '').strip()
+
+ if not len(reason):
+ raise CommandException(_("Reason is empty"))
+
+ CloseAction(node=question, user=user, extra=reason, ip=request.META['REMOTE_ADDR']).save()
return {
'commands': {
- 'mark_deleted': [post.node_type, id]
- }
+ 'refresh_page': []
+ }
}
@command
def matching_tags(request):
if len(request.GET['q']) == 0:
- raise Exception(_("Invalid request"))
+ raise CommandException(_("Invalid request"))
possible_tags = Tag.objects.filter(name__istartswith = request.GET['q'])
tag_output = ''
return HttpResponse(tag_output, mimetype="text/plain")
-@ajax_login_required
-def ajax_toggle_ignored_questions(request):#ajax tagging and tag-filtering system
- if request.user.hide_ignored_questions:
- new_hide_setting = False
- else:
- new_hide_setting = True
- request.user.hide_ignored_questions = new_hide_setting
- request.user.save()
-
-@ajax_method
-def ajax_command(request):#refactor? view processing ajax commands - note "vote" and view others do it too
- if 'command' not in request.POST:
- return HttpResponseForbidden(mimetype="application/json")
- if request.POST['command'] == 'toggle-ignored-questions':
- return ajax_toggle_ignored_questions(request)
-
-@login_required
-def close(request, id):#close question
- """view to initiate and process
- question close
- """
- question = get_object_or_404(Question, id=id)
- if not request.user.can_close_question(question):
- return HttpResponseForbidden()
- if request.method == 'POST':
- form = CloseForm(request.POST)
- if form.is_valid():
- reason = form.cleaned_data['reason']
- question.closed = True
- question.closed_by = request.user
- question.closed_at = datetime.datetime.now()
- question.close_reason = reason
- question.save()
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- form = CloseForm()
- return render_to_response('close.html', {
- 'form' : form,
- 'question' : question,
- }, context_instance=RequestContext(request))
-
-@login_required
-def reopen(request, id):#re-open question
- """view to initiate and process
- question close
- """
- question = get_object_or_404(Question, id=id)
- # open question
- if not request.user.can_reopen_question(question):
- return HttpResponseForbidden()
- if request.method == 'POST' :
- Question.objects.filter(id=question.id).update(closed=False,
- closed_by=None, closed_at=None, close_reason=None)
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- return render_to_response('reopen.html', {
- 'question' : question,
- }, context_instance=RequestContext(request))
-
-#osqa-user communication system
-def read_message(request):#marks message a read
- if request.method == "POST":
- if request.POST['formdata'] == 'required':
- request.session['message_silent'] = 1
- if request.user.is_authenticated():
- request.user.delete_messages()
- return HttpResponse('')
+
+
+
+
from django.core.paginator import Paginator\r
from django.shortcuts import render_to_response\r
from django.template import RequestContext\r
+from django.utils.translation import ungettext, ugettext as _\r
+import logging\r
\r
def render(template=None, tab=None):\r
def decorator(func):\r
paginator = Paginator(big_list, pagesize)\r
\r
page_obj = paginator.page(page)\r
- context[paginate] = page_obj.object_list\r
+ context[paginate] = page_obj.object_list.lazy()\r
\r
base_path = context.get('base_path', None) or request.path\r
sort = request.utils.sort_method('')\r
return decorator\r
\r
\r
+class CommandException(Exception):\r
+ pass\r
+\r
+\r
def command(func):\r
def decorated(request, *args, **kwargs):\r
try:\r
response = func(request, *args, **kwargs)\r
+\r
+ if isinstance(response, HttpResponse):\r
+ return response\r
+\r
response['success'] = True\r
except Exception, e:\r
- #import sys, traceback\r
- #traceback.print_exc(file=sys.stdout)\r
-\r
- response = {\r
- 'success': False,\r
- 'error_message': str(e)\r
- }\r
+ import sys, traceback\r
+ traceback.print_exc(file=sys.stdout)\r
+\r
+ if isinstance(e, CommandException):\r
+ response = {\r
+ 'success': False,\r
+ 'error_message': str(e)\r
+ }\r
+ else:\r
+ logging.error("%s: %s" % (func.__name__, str(e)))\r
+ response = {\r
+ 'success': False,\r
+ 'error_message': _("We're sorry, but an unknown error ocurred.<br />Please try again in a while.")\r
+ }\r
\r
if request.is_ajax():\r
return HttpResponse(simplejson.dumps(response), mimetype="application/json")\r
from django.conf import settings
from forum.forms import FeedbackForm
from django.core.urlresolvers import reverse
-from django.core.mail import mail_admins
from django.utils.translation import ugettext as _
+from django.db.models import Count
from forum.utils.forms import get_next_url
from forum.models import Badge, Award, User
-from forum.badges import ALL_BADGES
+from forum.badges.base import BadgesMeta
from forum import settings
from forum.utils.mail import send_email
-from forum.settings.settingsmarkdown import *
-
+from forum.settings.settingsmarkdown import SettingsExtension, markdown
import re
def favicon(request):
if not request.user.is_authenticated:
context['email'] = form.cleaned_data.get('email',None)
-
context['message'] = form.cleaned_data['message']
context['name'] = form.cleaned_data.get('name',None)
'next' : get_next_url(request),
}, context_instance=RequestContext(request))
-def badges(request):#user status/reputation system
- badges = Badge.objects.all().order_by('name')
-
- badges_dict = dict([(badge.badge, badge.description) for badge in ALL_BADGES])
-
- for badge in badges:
- if badge.description != badges_dict.get(badge.slug, badge.description):
- badge.description = badges_dict[badge.slug]
- badge.save()
+def badges(request):
+ badges = [b.ondb for b in sorted(BadgesMeta.by_id.values(), lambda b1, b2: cmp(b1.name, b2.name))]
- my_badges = []
if request.user.is_authenticated():
- my_badges = Award.objects.filter(user=request.user).values('badge_id')
- #my_badges.query.group_by = ['badge_id']
+ my_badges = Award.objects.filter(user=request.user).values('badge_id').distinct()
+ else:
+ my_badges = []
return render_to_response('badges.html', {
'badges' : badges,
'feedback_faq_url' : reverse('feedback'),
}, context_instance=RequestContext(request))
-def badge(request, id):
- badge = get_object_or_404(Badge, id=id)
- awards = Award.objects.extra(
- select={'id': 'auth_user.id',
- 'name': 'auth_user.username',
- 'rep':'forum_user.reputation',
- 'gold': 'forum_user.gold',
- 'silver': 'forum_user.silver',
- 'bronze': 'forum_user.bronze'},
- tables=['award', 'auth_user', 'forum_user'],
- where=['badge_id=%s AND user_id=auth_user.id AND forum_user.user_ptr_id = auth_user.id'],
- params=[id]
- ).distinct('id')
+def badge(request, id, slug):
+ badge = Badge.objects.get(id=id)
+ awards = Award.objects.filter(badge=badge).annotate(count=Count('user')).distinct('user').order_by('-count')
return render_to_response('badge.html', {
'awards' : awards,
from forum.models import *
from forum.const import *
from forum.utils.forms import get_next_url
-from forum.models.question import question_view
+from forum.actions import QuestionViewAction
+from forum.modules.decorators import decoratable
import decorators
# used in index page
# used in answers
ANSWERS_PAGE_SIZE = 10
-#system to display main content
-def _get_tags_cache_json():#service routine used by views requiring tag list in the javascript space
- """returns list of all tags in json format
- no caching yet, actually
- """
- tags = Tag.objects.filter(deleted=False).all()
- tags_list = []
- for tag in tags:
- dic = {'n': tag.name, 'c': tag.used_count}
- tags_list.append(dic)
- tags = simplejson.dumps(tags_list)
- return tags
-
@decorators.render('index.html')
def index(request):
return question_list(request, Question.objects.all(), sort='active', base_path=reverse('questions'))
@decorators.render('questions.html', 'unanswered')
def unanswered(request):
- return question_list(request, Question.objects.filter(accepted_answer=None),
+ return question_list(request, Question.objects.filter(extra_ref=None),
_('Open questions without an accepted answer'))
@decorators.render('questions.html', 'questions')
@decorators.list('questions', QUESTIONS_PAGE_SIZE)
def question_list(request, initial, list_description=_('questions'), sort=None, base_path=None):
- pagesize = request.utils.page_size(QUESTIONS_PAGE_SIZE)
- page = int(request.GET.get('page', 1))
-
- questions = initial.filter(deleted=False)
+ questions = initial.filter(deleted=None, in_moderation=None)
if request.user.is_authenticated():
questions = questions.filter(
else:
request.utils.set_sort_method(sort)
- view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" }
+ view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-extra_count", "mostvoted":"-score" }
questions=questions.order_by(view_dic.get(sort, '-added_at'))
else:
return render_to_response("search.html", context_instance=RequestContext(request))
+@decoratable
+def do_question_search(keywords):
+ return Question.objects.filter(Q(title__icontains=keywords) | Q(body__icontains=keywords))
+
@decorators.render('questions.html')
def question_search(request, keywords):
- def question_search(keywords):
- return Question.objects.filter(Q(title__icontains=keywords) | Q(body__icontains=keywords))
-
- from forum.modules import get_handler
-
- question_search = get_handler('question_search', question_search)
- initial = question_search(keywords)
+ initial = do_question_search(keywords)
return question_list(request, initial, _("questions matching '%(keywords)s'") % {'keywords': keywords},
base_path="%s?t=question&q=%s" % (reverse('search'), django_urlquote(keywords)), sort=False)
last_seen = request.session['last_seen_in_question'].get(question.id,None)
if (not last_seen) or last_seen < question.last_activity_at:
- question_view.send(sender=update_question_view_times, instance=question, user=request.user)
+ QuestionViewAction(question, request.user).save()
request.session['last_seen_in_question'][question.id] = datetime.datetime.now()
request.session['last_seen_in_question'][question.id] = datetime.datetime.now()
answers = request.user.get_visible_answers(question)
if answers is not None:
- answers = [a for a in answers.order_by("-accepted", order_by)
+ answers = [a for a in answers.order_by("-marked", order_by)
if not a.deleted or a.author == request.user]
objects_list = Paginator(answers, ANSWERS_PAGE_SIZE)
"question" : question,
"answer" : answer_form,
"answers" : page_objects.object_list,
- "tags" : question.tags.all(),
"tab_id" : view_id,
"similar_questions" : question.get_related_questions(),
"subscription": subscription,
from django.core.urlresolvers import reverse\r
from forum.forms import *\r
from forum.utils.html import sanitize_html\r
-from forum.authentication import user_updated\r
from datetime import date\r
import decorators\r
+from forum.actions import EditProfileAction, FavoriteAction\r
\r
import time\r
\r
\r
}, context_instance=RequestContext(request))\r
\r
-@login_required\r
-def moderate_user(request, id):\r
- """ajax handler of user moderation\r
- """\r
- if not request.user.is_superuser or request.method != 'POST':\r
- raise Http404\r
- if not request.is_ajax():\r
- return HttpResponseForbidden(mimetype="application/json")\r
-\r
- user = get_object_or_404(User, id=id)\r
- form = ModerateUserForm(request.POST, instance=user)\r
-\r
- if form.is_valid():\r
- form.save()\r
- logging.debug('data saved')\r
- response = HttpResponse(simplejson.dumps(''), mimetype="application/json")\r
- else:\r
- response = HttpResponseForbidden(mimetype="application/json")\r
- return response\r
-\r
def set_new_email(user, new_email, nomessage=False):\r
if new_email != user.email:\r
user.email = new_email\r
user.about = sanitize_html(form.cleaned_data['about'])\r
\r
user.save()\r
- # send user updated signal if full fields have been updated\r
- if user.email and user.real_name and user.website and user.location and \\r
- user.date_of_birth and user.about:\r
- user_updated.send(sender=user.__class__, instance=user, updated_by=user)\r
+ EditProfileAction(user=user, ip=request.META['REMOTE_ADDR']).save()\r
+\r
return HttpResponseRedirect(user.get_profile_url())\r
else:\r
form = EditUserForm(user)\r
\r
@user_view('users/stats.html', 'stats', _('user profile'), _('user profile overview'))\r
def user_stats(request, user):\r
- questions = Question.objects.filter(author=user, deleted=False).order_by('-added_at')\r
- answers = Answer.objects.filter(author=user, deleted=False).order_by('-added_at')\r
+ questions = Question.objects.filter(author=user, deleted=None).order_by('-added_at')\r
+ answers = Answer.objects.filter(author=user, deleted=None).order_by('-added_at')\r
\r
- up_votes = user.get_up_vote_count()\r
- down_votes = user.get_down_vote_count()\r
+ up_votes = user.vote_up_count\r
+ down_votes = user.vote_down_count\r
votes_today = user.get_vote_count_today()\r
votes_total = int(settings.MAX_VOTES_PER_DAY)\r
\r
user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \\r
.annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')\r
\r
- awards = Badge.objects.filter(award_badge__user=user).annotate(count=Count('name')).order_by('-count')\r
-\r
- if request.user.is_superuser:\r
- moderate_user_form = ModerateUserForm(instance=user)\r
- else:\r
- moderate_user_form = None\r
+ awards = [(Badge.objects.get(id=b['id']), b['count']) for b in\r
+ Badge.objects.filter(awards__user=user).values('id').annotate(count=Count('cls')).order_by('-count')]\r
\r
- return {'moderate_user_form': moderate_user_form,\r
+ return {\r
"view_user" : user,\r
"questions" : questions,\r
"answers" : answers,\r
"votes_total_per_day": votes_total,\r
"user_tags" : user_tags[:50],\r
"awards": awards,\r
- "total_awards" : awards.count(),\r
+ "total_awards" : len(awards),\r
}\r
\r
@user_view('users/recent.html', 'recent', _('recent user activity'), _('profile - recent activity'))\r
def user_recent(request, user):\r
- activities = Activity.objects.filter(activity_type__in=(TYPE_ACTIVITY_PRIZE,\r
- TYPE_ACTIVITY_ASK_QUESTION, TYPE_ACTIVITY_ANSWER,\r
- TYPE_ACTIVITY_COMMENT_QUESTION, TYPE_ACTIVITY_COMMENT_ANSWER,\r
- TYPE_ACTIVITY_MARK_ANSWER), user=user).order_by('-active_at')[:USERS_PAGE_SIZE]\r
+ activities = user.actions.exclude(action_type__in=("voteup", "votedown", "voteupcomment", "flag")).order_by('-action_date')[:USERS_PAGE_SIZE]\r
\r
return {"view_user" : user, "activities" : activities}\r
\r
\r
@user_view('users/votes.html', 'votes', _('user vote record'), _('profile - votes'), True)\r
def user_votes(request, user):\r
- votes = user.votes.exclude(node__deleted=True).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
+ votes = user.votes.filter(node__deleted=None).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
\r
return {"view_user" : user, "votes" : votes}\r
\r
\r
@user_view('users/reputation.html', 'reputation', _('user reputation in the community'), _('profile - user reputation'))\r
def user_reputation(request, user):\r
- reputation = user.reputes.order_by('-reputed_at')\r
+ rep = list(user.reputes.order_by('date'))\r
+ values = [r.value for r in rep]\r
+ redux = lambda x, y: x+y \r
\r
graph_data = simplejson.dumps([\r
- (time.mktime(rep.reputed_at.timetuple()) * 1000, rep.reputation)\r
- for rep in reputation\r
+ (time.mktime(rep[i].date.timetuple()) * 1000, reduce(redux, values[:i], 0))\r
+ for i in range(len(values))\r
])\r
\r
- return {"view_user": user, "reputation": reputation, "graph_data": graph_data}\r
+ return {"view_user": user, "reputation": reversed(rep), "graph_data": graph_data}\r
\r
-@user_view('users/questions.html', 'favorites', _('favorite questions'), _('profile - favorite questions'), True)\r
+@user_view('users/questions.html', 'favorites', _('favorite questions'), _('profile - favorite questions'))\r
def user_favorites(request, user):\r
- questions = user.favorite_questions.filter(deleted=False)\r
+ favorites = FavoriteAction.objects.filter(user=user)\r
\r
- return {"questions" : questions, "view_user" : user}\r
+ return {"favorites" : favorites, "view_user" : user}\r
\r
@user_view('users/subscriptions.html', 'subscriptions', _('subscription settings'), _('profile - subscriptions'), True)\r
def user_subscriptions(request, user):\r
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied
+from forum.actions import AskAction, AnswerAction, ReviseAction, RollbackAction, RetagAction
from forum.forms import *
from forum.models import *
from forum.const import *
from forum.utils.forms import get_next_url
-from forum.views.readers import _get_tags_cache_json
from forum.views.commands import SpamNotAllowedException
-# used in index page
-INDEX_PAGE_SIZE = 20
-INDEX_AWARD_SIZE = 15
-INDEX_TAGS_SIZE = 100
-# used in tags list
-DEFAULT_PAGE_SIZE = 60
-# used in questions
-QUESTIONS_PAGE_SIZE = 10
-# used in answers
-ANSWERS_PAGE_SIZE = 10
def upload(request):#ajax upload file to a question or answer
class FileTypeNotAllow(Exception):
return HttpResponse(result, mimetype="application/xml")
-def _create_post(request, post_cls, form, parent=None):
- post = post_cls()
-
- if parent is not None:
- post.parent = parent
-
- revision_data = dict(summary=_('Initial revision'), body=form.cleaned_data['text'])
-
- if form.cleaned_data.get('title', None):
- revision_data['title'] = strip_tags(form.cleaned_data['title'].strip())
-
- if form.cleaned_data.get('tags', None):
- revision_data['tagnames'] = form.cleaned_data['tags'].strip()
-
- post.create_revision(request.user, **revision_data)
-
- if form.cleaned_data['wiki']:
- post.wikify()
-
- return HttpResponseRedirect(post.get_absolute_url())
-
-
-
def ask(request):
if request.method == "POST" and "text" in request.POST:
form = AskForm(request.POST)
data = {
"user_ip":request.META["REMOTE_ADDR"],
"user_agent":request.environ['HTTP_USER_AGENT'],
- "comment_author":request.user.real_name,
+ "comment_author":request.user.username,
"comment_author_email":request.user.email,
"comment_author_url":request.user.website,
"comment":request.POST['text']
if Node.isSpam(request.POST['text'], data):
raise SpamNotAllowedException("question")
- return _create_post(request, Question, form)
+ question = AskAction(user=request.user).save(data=form.cleaned_data).node
+ return HttpResponseRedirect(question.get_absolute_url())
else:
return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newquestion'}))
elif request.method == "POST" and "go" in request.POST:
form = RetagQuestionForm(question, request.POST)
if form.is_valid():
if form.has_changed():
- active = question.active_revision
-
- question.create_revision(
- request.user,
- summary = _('Retag'),
- title = active.title,
- tagnames = form.cleaned_data['tags'],
- body = active.body,
- )
+ RetagAction(user=request.user, node=question).save(data=dict(tagnames=form.cleaned_data['tags']))
return HttpResponseRedirect(question.get_absolute_url())
else:
if not 'select_revision' in request.POST and form.is_valid():
if form.has_changed():
- question.create_revision(
- request.user,
- summary = form.cleaned_data['summary'],
- title = strip_tags(form.cleaned_data['title'].strip()),
- tagnames = form.cleaned_data['tags'].strip(),
- body = form.cleaned_data['text'],
- )
-
- if form.cleaned_data.get('wiki', False):
- question.wikify()
-
+ ReviseAction(user=request.user, node=question).save(data=form.cleaned_data)
else:
if not revision == question.active_revision:
- question.activate_revision(request.user, revision)
+ RollbackAction(user=request.user, node=question).save(data=dict(activate=revision))
return HttpResponseRedirect(question.get_absolute_url())
else:
if not 'select_revision' in request.POST and form.is_valid():
if form.has_changed():
- answer.create_revision(
- request.user,
- summary = form.cleaned_data['summary'],
- body = form.cleaned_data['text'],
- )
-
- if form.cleaned_data.get('wiki', False):
- answer.wikify()
-
+ ReviseAction(user=request.user, node=answer).save(data=form.cleaned_data)
else:
if not revision == answer.active_revision:
- answer.activate_revision(request.user, revision)
+ RollbackAction(user=request.user, node=answer).save(data=dict(activate=revision))
return HttpResponseRedirect(answer.get_absolute_url())
data = {
"user_ip":request.META["REMOTE_ADDR"],
"user_agent":request.environ['HTTP_USER_AGENT'],
- "comment_author":request.user.real_name,
+ "comment_author":request.user.username,
"comment_author_email":request.user.email,
"comment_author_url":request.user.website,
"comment":request.POST['text']
if Node.isSpam(request.POST['text'], data):
raise SpamNotAllowedException("answer")
- return _create_post(request, Answer, form, question)
+ answer = AnswerAction(user=request.user).save(dict(question=question, **form.cleaned_data)).node
+ return HttpResponseRedirect(answer.get_absolute_url())
else:
return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newquestion'}))
-from datetime import timedelta
-
-from django.db.models.signals import post_save
+from datetime import datetime, timedelta
from django.utils.translation import ugettext as _
-
-from forum.badges.base import PostCountableAbstractBadge, ActivityAbstractBadge, FirstActivityAbstractBadge, \
- ActivityCountAbstractBadge, CountableAbstractBadge, AbstractBadge, NodeCountableAbstractBadge
-from forum.models import Node, Question, Answer, Activity, Tag
-from forum.models.user import activity_record
-from forum.models.base import denorm_update
-from forum import const
+from forum.badges.base import AbstractBadge
+from forum.models import Badge
+from forum.actions import *
+from forum.models import Vote, Flag
import settings
-class PopularQuestionBadge(PostCountableAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('Asked a question with %s views') % str(settings.POPULAR_QUESTION_VIEWS)
+class QuestionViewBadge(AbstractBadge):
+ abstract = True
+ listen_to = (QuestionViewAction,)
- def __init__(self):
- super(PopularQuestionBadge, self).__init__(Question, 'view_count', settings.POPULAR_QUESTION_VIEWS)
+ @property
+ def description(self):
+ return _('Asked a question with %s views') % str(self.nviews)
-class NotableQuestionBadge(PostCountableAbstractBadge):
- type = const.SILVER_BADGE
- description = _('Asked a question with %s views') % str(settings.NOTABLE_QUESTION_VIEWS)
+ def award_to(self, action):
+ if action.question.extra_count == int(self.nviews):
+ return action.question.author
- def __init__(self):
- super(NotableQuestionBadge, self).__init__(Question, 'view_count', settings.NOTABLE_QUESTION_VIEWS)
-class FamousQuestionBadge(PostCountableAbstractBadge):
- type = const.GOLD_BADGE
- description = _('Asked a question with %s views') % str(settings.FAMOUS_QUESTION_VIEWS)
+class PopularQuestion(QuestionViewBadge):
+ name = _('Popular Question')
+ nviews = settings.POPULAR_QUESTION_VIEWS
- def __init__(self):
- super(FamousQuestionBadge, self).__init__(Question, 'view_count', settings.FAMOUS_QUESTION_VIEWS)
+class NotableQuestion(QuestionViewBadge):
+ type = Badge.SILVER
+ name = _('Notable Question')
+ nviews = settings.NOTABLE_QUESTION_VIEWS
-class NiceAnswerBadge(NodeCountableAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('Answer voted up %s times') % str(settings.NICE_ANSWER_VOTES_UP)
+class FamousQuestion(QuestionViewBadge):
+ type = Badge.GOLD
+ name = _('Famous Question')
+ nviews = settings.FAMOUS_QUESTION_VIEWS
- def __init__(self):
- super(NiceAnswerBadge, self).__init__("answer", 'vote_up_count', settings.NICE_ANSWER_VOTES_UP)
-class NiceQuestionBadge(NodeCountableAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('Question voted up %s times') % str(settings.NICE_QUESTION_VOTES_UP)
- def __init__(self):
- super(NiceQuestionBadge, self).__init__("question", 'vote_up_count', settings.NICE_QUESTION_VOTES_UP)
-class GoodAnswerBadge(NodeCountableAbstractBadge):
- type = const.SILVER_BADGE
- description = _('Answer voted up %s times') % str(settings.GOOD_ANSWER_VOTES_UP)
+class NodeScoreBadge(AbstractBadge):
+ abstract = True
+ listen_to = (VoteAction,)
- def __init__(self):
- super(GoodAnswerBadge, self).__init__("answer", 'vote_up_count', settings.GOOD_ANSWER_VOTES_UP)
+ @property
+ def description(self):
+ return _('Answer voted up %s times') % str(self.expected_score)
-class GoodQuestionBadge(NodeCountableAbstractBadge):
- type = const.SILVER_BADGE
- description = _('Question voted up %s times') % str(settings.GOOD_QUESTION_VOTES_UP)
+ def award_to(self, action):
+ if (action.node.node_type == self.node_type) and (action.node.score == int(self.expected_score)):
+ return action.node.author
+
- def __init__(self):
- super(GoodQuestionBadge, self).__init__("question", 'vote_up_count', settings.GOOD_QUESTION_VOTES_UP)
+class QuestionScoreBadge(NodeScoreBadge):
+ abstract = True
+ node_type = "question"
-class GreatAnswerBadge(NodeCountableAbstractBadge):
- type = const.GOLD_BADGE
- description = _('Answer voted up %s times') % str(settings.GREAT_ANSWER_VOTES_UP)
+class NiceQuestion(QuestionScoreBadge):
+ expected_score = settings.NICE_QUESTION_VOTES_UP
+ name = _("Nice Question")
- def __init__(self):
- super(GreatAnswerBadge, self).__init__("answer", 'vote_up_count', settings.GREAT_ANSWER_VOTES_UP)
+class GoodQuestion(QuestionScoreBadge):
+ type = Badge.SILVER
+ expected_score = settings.GOOD_QUESTION_VOTES_UP
+ name = _("Good Question")
-class GreatQuestionBadge(NodeCountableAbstractBadge):
- type = const.GOLD_BADGE
- description = _('Question voted up %s times') % str(settings.GREAT_QUESTION_VOTES_UP)
+class GreatQuestion(QuestionScoreBadge):
+ type = Badge.GOLD
+ expected_score = settings.GREAT_QUESTION_VOTES_UP
+ name = _("Great Question")
- def __init__(self):
- super(GreatQuestionBadge, self).__init__("question", 'vote_up_count', settings.GREAT_QUESTION_VOTES_UP)
+class AnswerScoreBadge(NodeScoreBadge):
+ abstract = True
+ node_type = "answer"
-class FavoriteQuestionBadge(PostCountableAbstractBadge):
- type = const.SILVER_BADGE
- description = _('Question favorited by %s users') % str(settings.FAVORITE_QUESTION_FAVS)
+class NiceAnswer(AnswerScoreBadge):
+ expected_score = settings.NICE_ANSWER_VOTES_UP
+ name = _("Nice Answer")
- def __init__(self):
- super(FavoriteQuestionBadge, self).__init__(Question, 'favourite_count', settings.FAVORITE_QUESTION_FAVS)
+class GoodAnswer(AnswerScoreBadge):
+ type = Badge.SILVER
+ expected_score = settings.GOOD_ANSWER_VOTES_UP
+ name = _("Good Answer")
-class StellarQuestionBadge(PostCountableAbstractBadge):
- type = const.GOLD_BADGE
- description = _('Question favorited by %s users') % str(settings.STELLAR_QUESTION_FAVS)
+class GreatAnswer(AnswerScoreBadge):
+ type = Badge.GOLD
+ expected_score = settings.GREAT_ANSWER_VOTES_UP
+ name = _("Great Answer")
- def __init__(self):
- super(StellarQuestionBadge, self).__init__(Question, 'favourite_count', settings.STELLAR_QUESTION_FAVS)
-class DisciplinedBadge(ActivityAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('Deleted own post with score of %s or higher') % str(settings.DISCIPLINED_MIN_SCORE)
+class FavoriteQuestionBadge(AbstractBadge):
+ abstract = True
+ listen_to = (FavoriteAction,)
- def __init__(self):
- def handler(instance):
- if instance.user.id == instance.content_object.author.id and instance.content_object.score >= settings.DISCIPLINED_MIN_SCORE:
- self.award_badge(instance.user, instance)
+ @property
+ def description(self):
+ return _('Question favorited by %s users') % str(self.expected_count)
- super(DisciplinedBadge, self).__init__(const.TYPE_ACTIVITY_DELETE_QUESTION, handler)
+ def award_to(self, action):
+ if (action.node.node_type == "question") and (action.node.favorite_count == int(self.expected_count)):
+ return action.node.author
-class PeerPressureBadge(ActivityAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('Deleted own post with score of %s or lower') % str(settings.PEER_PRESSURE_MAX_SCORE)
+class FavoriteQuestion(FavoriteQuestionBadge):
+ type = Badge.SILVER
+ name = _("Favorite Question")
+ expected_count = settings.FAVORITE_QUESTION_FAVS
- def __init__(self):
- def handler(instance):
- if instance.user.id == instance.content_object.author.id and instance.content_object.score <= settings.PEER_PRESSURE_MAX_SCORE:
- self.award_badge(instance.user, instance)
+class StellarQuestion(FavoriteQuestionBadge):
+ name = _("Stellar Question")
+ expected_count = settings.STELLAR_QUESTION_FAVS
- super(PeerPressureBadge, self).__init__(const.TYPE_ACTIVITY_DELETE_QUESTION, handler)
-class CitizenPatrolBadge(FirstActivityAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('First flagged post')
+class Disciplined(AbstractBadge):
+ listen_to = (DeleteAction,)
+ name = _("Disciplined")
+ description = _('Deleted own post with score of %s or higher') % settings.DISCIPLINED_MIN_SCORE
- def __init__(self):
- super(CitizenPatrolBadge, self).__init__(const.TYPE_ACTIVITY_MARK_OFFENSIVE)
+ def award_to(self, action):
+ if (action.node.author == action.user) and (action.node.score >= int(settings.DISCIPLINED_MIN_SCORE)):
+ return action.user
-class CriticBadge(FirstActivityAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('First down vote')
+class PeerPressure(AbstractBadge):
+ listen_to = (DeleteAction,)
+ name = _("Peer Pressure")
+ description = _('Deleted own post with score of %s or lower') % settings.PEER_PRESSURE_MAX_SCORE
- def __init__(self):
- super(CriticBadge, self).__init__(const.TYPE_ACTIVITY_VOTE_DOWN)
+ def award_to(self, action):
+ if (action.node.author == action.user) and (action.node.score <= int(settings.PEER_PRESSURE_MAX_SCORE)):
+ return action.user
-class OrganizerBadge(FirstActivityAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('First retag')
- def __init__(self):
- super(OrganizerBadge, self).__init__(const.TYPE_ACTIVITY_UPDATE_TAGS)
+class Critic(AbstractBadge):
+ award_once = True
+ listen_to = (VoteDownAction,)
+ name = _("Critic")
+ description = _('First down vote')
+
+ def award_to(self, action):
+ if (action.user.vote_down_count == 1):
+ return action.user
+
-class SupporterBadge(FirstActivityAbstractBadge):
- type = const.BRONZE_BADGE
+class Supporter(AbstractBadge):
+ award_once = True
+ listen_to = (VoteUpAction,)
+ name = _("Supporter")
description = _('First up vote')
- def __init__(self):
- super(SupporterBadge, self).__init__(const.TYPE_ACTIVITY_VOTE_UP)
+ def award_to(self, action):
+ if (action.user.vote_up_count == 1):
+ return action.user
-class EditorBadge(FirstActivityAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('First edit')
- def __init__(self):
- super(EditorBadge, self).__init__((const.TYPE_ACTIVITY_UPDATE_ANSWER, const.TYPE_ACTIVITY_UPDATE_QUESTION))
+class FirstActionBadge(AbstractBadge):
+ award_once = True
+ abstract = True
+
+ def award_to(self, action):
+ if (self.listen_to[0].objects.filter(user=action.user).count() == 1):
+ return action.user
-class ScholarBadge(FirstActivityAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('First accepted answer on your own question')
+class CitizenPatrol(FirstActionBadge):
+ listen_to = (FlagAction,)
+ name = _("Citizen Patrol")
+ description = _('First flagged post')
- def __init__(self):
- super(ScholarBadge, self).__init__(const.TYPE_ACTIVITY_MARK_ANSWER)
+class Organizer(FirstActionBadge):
+ listen_to = (RetagAction,)
+ name = _("Organizer")
+ description = _('First retag')
-class AutobiographerBadge(FirstActivityAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('Completed all user profile fields')
+class Editor(FirstActionBadge):
+ listen_to = (ReviseAction,)
+ name = _("Editor")
+ description = _('First edit')
- def __init__(self):
- super(AutobiographerBadge, self).__init__(const.TYPE_ACTIVITY_USER_FULL_UPDATED)
+class Scholar(FirstActionBadge):
+ listen_to = (AcceptAnswerAction,)
+ name = _("Scholar")
+ description = _('First accepted answer on your own question')
-class CleanupBadge(FirstActivityAbstractBadge):
- type = const.BRONZE_BADGE
+class Cleanup(FirstActionBadge):
+ listen_to = (RollbackAction,)
+ name = _("Cleanup")
description = _('First rollback')
- def __init__(self):
- super(CleanupBadge, self).__init__((const.TYPE_ACTIVITY_CANCEL_VOTE_UP, const.TYPE_ACTIVITY_CANCEL_VOTE_DOWN))
+class Autobiographer(AbstractBadge):
+ award_once = True
+ listen_to = (EditProfileAction,)
+ name = _("Autobiographer")
+ description = _('Completed all user profile fields')
+
+ def award_to(self, action):
+ user = action.user
+ if user.email and user.real_name and user.website and user.location and \
+ user.date_of_birth and user.about:
+ return user
-class CivicDutyBadge(ActivityCountAbstractBadge):
- type = const.SILVER_BADGE
- description = _('Voted %s times') % str(settings.CIVIC_DUTY_VOTES)
- def __init__(self):
- super(CivicDutyBadge, self).__init__((const.TYPE_ACTIVITY_VOTE_DOWN, const.TYPE_ACTIVITY_VOTE_UP), settings.CIVIC_DUTY_VOTES)
-class PunditBadge(ActivityCountAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('Left %s comments') % str(settings.PUNDIT_COMMENT_COUNT)
+class CivicDuty(AbstractBadge):
+ type = Badge.SILVER
+ award_once = True
+ listen_to = (VoteUpAction, VoteDownAction)
+ name = _("Civic Duty")
+ description = _('Voted %s times') % settings.CIVIC_DUTY_VOTES
- def __init__(self):
- super(PunditBadge, self).__init__((const.TYPE_ACTIVITY_COMMENT_ANSWER, const.TYPE_ACTIVITY_COMMENT_QUESTION), settings.PUNDIT_COMMENT_COUNT)
+ def award_to(self, action):
+ if (action.user.vote_up_count + action.user.vote_down_count) == int(settings.CIVIC_DUTY_VOTES):
+ return action.user
-class SelfLearnerBadge(CountableAbstractBadge):
- type = const.BRONZE_BADGE
- description = _('Answered your own question with at least %s up votes') % str(settings.SELF_LEARNER_UP_VOTES)
+class Pundit(AbstractBadge):
+ award_once = True
+ listen_to = (CommentAction,)
+ name = _("Pundit")
+ description = _('Left %s comments') % settings.PUNDIT_COMMENT_COUNT
- def __init__(self):
+ def award_to(self, action):
+ if (action.user.nodes.filter(node_type="comment", deleted=None)) == int(settings.CIVIC_DUTY_VOTES):
+ return action.user
- def handler(instance):
- if instance.node_type == "answer" and instance.author_id == instance.question.author_id:
- self.award_badge(instance.author, instance)
- super(SelfLearnerBadge, self).__init__(Node, 'vote_up_count', settings.SELF_LEARNER_UP_VOTES, handler)
+class SelfLearner(AbstractBadge):
+ listen_to = (VoteUpAction, )
+ name = _("Self Learner")
+ description = _('Answered your own question with at least %s up votes') % settings.SELF_LEARNER_UP_VOTES
+ def award_to(self, action):
+ if (action.node.node_type == "answer") and (action.node.author == action.node.parent.author) and (
+ action.node.score == int(settings.SELF_LEARNER_UP_VOTES)):
+ return action.node.author
-class StrunkAndWhiteBadge(ActivityCountAbstractBadge):
- type = const.SILVER_BADGE
- name = _('Strunk & White')
- description = _('Edited %s entries') % str(settings.STRUNK_AND_WHITE_EDITS)
- def __init__(self):
- super(StrunkAndWhiteBadge, self).__init__((const.TYPE_ACTIVITY_UPDATE_ANSWER, const.TYPE_ACTIVITY_UPDATE_QUESTION), settings.STRUNK_AND_WHITE_EDITS)
+class StrunkAndWhite(AbstractBadge):
+ award_once = True
+ listen_to = (ReviseAction,)
+ name = _("Strunk & White")
+ description = _('Edited %s entries') % settings.STRUNK_AND_WHITE_EDITS
+ def award_to(self, action):
+ if (ReviseAction.objects.filter(user=action.user).count() == int(settings.STRUNK_AND_WHITE_EDITS)):
+ return action.user
-def is_user_first(post):
- return post.__class__.objects.filter(author=post.author).order_by('added_at')[0].id == post.id
-class StudentBadge(CountableAbstractBadge):
- type = const.BRONZE_BADGE
+class Student(AbstractBadge):
+ award_once = True
+ listen_to = (VoteUpAction,)
+ name = _("Student")
description = _('Asked first question with at least one up vote')
- def __init__(self):
- def handler(instance):
- if instance.node_type == "question" and is_user_first(instance):
- self.award_badge(instance.author, instance)
+ def award_to(self, action):
+ if (action.node.node_type == "question") and (action.node.author.nodes.filter(node_type="question", deleted=None, score=1).count() == 1):
+ return action.node.author
- super(StudentBadge, self).__init__(Node, 'vote_up_count', 1, handler)
-class TeacherBadge(CountableAbstractBadge):
- type = const.BRONZE_BADGE
+class Teacher(AbstractBadge):
+ award_once = True
+ listen_to = (VoteUpAction,)
+ name = _("Teacher")
description = _('Answered first question with at least one up vote')
- def __init__(self):
- def handler(instance):
- if instance.node_type == "answer" and is_user_first(instance):
- self.award_badge(instance.author, instance)
+ def award_to(self, action):
+ if (action.node.node_type == "answer") and (action.node.author.nodes.filter(node_type="answer", deleted=None, score=1).count() == 1):
+ return action.node.author
- super(TeacherBadge, self).__init__(Node, 'vote_up_count', 1, handler)
+class Enlightened(AbstractBadge):
+ type = Badge.SILVER
+ award_once = True
+ listen_to = (VoteUpAction, AcceptAnswerAction)
+ name = _("Enlightened")
+ description = _('First answer was accepted with at least %s up votes') % settings.ENLIGHTENED_UP_VOTES
-class AcceptedAndVotedAnswerAbstractBadge(AbstractBadge):
- def __init__(self, up_votes, handler):
- def wrapper(sender, instance, **kwargs):
- if sender is Answer:
- if (not kwargs['field'] == "score") or (kwargs['new'] < kwargs['old']):
- return
+ def award_to(self, action):
+ if (action.node.node_type == "answer") and (action.node.accepted) and (
+ action.node.score >= int(settings.ENLIGHTENED_UP_VOTES)):
+ return action.node.author
- answer = instance.leaf
- vote_count = kwargs['new']
- else:
- answer = instance.content_object
- vote_count = answer.vote_up_count
- if answer.accepted and vote_count == up_votes:
- handler(answer)
+class Guru(AbstractBadge):
+ type = Badge.SILVER
+ listen_to = (VoteUpAction, AcceptAnswerAction)
+ name = _("Guru")
+ description = _('Accepted answer and voted up %s times') % settings.GURU_UP_VOTES
- activity_record.connect(wrapper, sender=const.TYPE_ACTIVITY_MARK_ANSWER, weak=False)
- denorm_update.connect(wrapper, sender=Node, weak=False)
+ def award_to(self, action):
+ if (action.node.node_type == "answer") and (action.node.accepted) and (
+ action.node.score >= int(settings.ENLIGHTENED_UP_VOTES)):
+ return action.node.author
-class EnlightenedBadge(AcceptedAndVotedAnswerAbstractBadge):
- type = const.SILVER_BADGE
- description = _('First answer was accepted with at least %s up votes') % str(settings.ENLIGHTENED_UP_VOTES)
-
- def __init__(self):
- def handler(answer):
- self.award_badge(answer.author, answer, True)
-
- super(EnlightenedBadge, self).__init__(settings.ENLIGHTENED_UP_VOTES, handler)
-
-
-class GuruBadge(AcceptedAndVotedAnswerAbstractBadge):
- type = const.SILVER_BADGE
- description = _('Accepted answer and voted up %s times') % str(settings.GURU_UP_VOTES)
-
- def __init__(self):
- def handler(answer):
- self.award_badge(answer.author, answer)
-
- super(GuruBadge, self).__init__(settings.GURU_UP_VOTES, handler)
-
-
-class NecromancerBadge(CountableAbstractBadge):
- type = const.SILVER_BADGE
+class Necromancer(AbstractBadge):
+ type = Badge.SILVER
+ listen_to = (VoteUpAction,)
+ name = _("Necromancer")
description = _('Answered a question more than %(dif_days)s days later with at least %(up_votes)s votes') % \
- {'dif_days': str(settings.NECROMANCER_DIF_DAYS), 'up_votes': str(settings.NECROMANCER_UP_VOTES)}
-
- def __init__(self):
- def handler(instance):
- if instance.node_type == "answer" and instance.added_at >= (instance.question.added_at + timedelta(days=int(settings.NECROMANCER_DIF_DAYS))):
- self.award_badge(instance.author, instance)
+ {'dif_days': settings.NECROMANCER_DIF_DAYS, 'up_votes': settings.NECROMANCER_UP_VOTES}
- super(NecromancerBadge, self).__init__(Node, "vote_up_count", settings.NECROMANCER_UP_VOTES, handler)
+ def award_to(self, action):
+ if (action.node.node_type == "answer") and (
+ action.node.added_at >= (action.node.question.added_at + timedelta(days=int(settings.NECROMANCER_DIF_DAYS)))):
+ return action.node.author
+class Taxonomist(AbstractBadge):
+ type = Badge.SILVER
+ listen_to = tuple()
+ name = _("Taxonomist")
+ description = _('Created a tag used by %s questions') % settings.TAXONOMIST_USE_COUNT
-class TaxonomistBadge(AbstractBadge):
- type = const.SILVER_BADGE
- description = _('Created a tag used by %s questions') % str(settings.TAXONOMIST_USE_COUNT)
+ def award_to(self, action):
+ return None
- def __init__(self):
- def handler(instance, **kwargs):
- if instance.used_count == settings.TAXONOMIST_USE_COUNT:
- self.award_badge(instance.created_by, instance)
-
- post_save.connect(handler, sender=Tag, weak=False)
-
-
-#class GeneralistTag(AbstractBadge):
-# pass
-
-#class ExpertTag(AbstractBadge):
-# pass
-
-#class YearlingTag(AbstractBadge):
-# pass
-
-
-
{% load i18n %}\r
-{% block title %}{% spaceless %}{% trans "Login" %}{% endspaceless %}{% endblock %}\r
\r
<fieldset id='local_login_fs'>\r
<p><span class='big strong'>Enter your local user name and password</span><br/><span class='grey'>(or select your external provider above)</span></p>\r
</td>\r
</tr>\r
</table>\r
-</fieldset>
\ No newline at end of file
+</fieldset>\r
from forms import ClassicRegisterForm
from forum.authentication.forms import SimpleEmailSubscribeForm
from forum.views.auth import login_and_forward, send_validation_email
+from forum.actions import UserJoinsAction
def register(request):
if request.method == 'POST':
user_.is_superuser = True
user_.save()
+ UserJoinsAction(user=user_, ip=request.META['REMOTE_ADDR']).save()
send_validation_email(user_)
if email_feeds_form.cleaned_data['subscribe'] == 'n':
}
weight = 200
human_name = 'MyOpenID'
- icon = '/media/images/openid/myopenid.ico'
+ icon = '/media/images/openid/myopenid.png'
class FlickrAuthConsumer(OpenIdAbstractAuthConsumer):
}
weight = 250
human_name = 'Flickr'
- icon = '/media/images/openid/flickr.ico'
+ icon = '/media/images/openid/flickr.png'
class TechnoratiAuthConsumer(OpenIdAbstractAuthConsumer):
}
weight = 260
human_name = 'Technorati'
- icon = '/media/images/openid/technorati.ico'
+ icon = '/media/images/openid/technorati.png'
class WordpressAuthConsumer(OpenIdAbstractAuthConsumer):
}
weight = 270
human_name = 'Wordpress'
- icon = '/media/images/openid/wordpress.ico'
+ icon = '/media/images/openid/wordpress.png'
class BloggerAuthConsumer(OpenIdAbstractAuthConsumer):
}
weight = 300
human_name = 'Blogger'
- icon = '/media/images/openid/blogger.ico'
+ icon = '/media/images/openid/blogger.png'
class LiveJournalAuthConsumer(OpenIdAbstractAuthConsumer):
}
weight = 310
human_name = 'LiveJournal'
- icon = '/media/images/openid/livejournal.ico'
+ icon = '/media/images/openid/livejournal.png'
class ClaimIdAuthConsumer(OpenIdAbstractAuthConsumer):
}
weight = 320
human_name = 'ClaimID'
- icon = '/media/images/openid/claimid.ico'
-
-class VidoopAuthConsumer(OpenIdAbstractAuthConsumer):
- def get_user_url(self, request):
- blog_name = request.POST['input_field']
- return "http://%s.myvidoop.com/" % blog_name
-
-class VidoopAuthContext(ConsumerTemplateContext):
- mode = 'SMALLICON'
- type = 'SIMPLE_FORM'
- simple_form_context = {
- 'your_what': 'Vidoop user name'
- }
- weight = 330
- human_name = 'Vidoop'
- icon = '/media/images/openid/vidoop.ico'
+ icon = '/media/images/openid/claimid.png'
class VerisignAuthConsumer(OpenIdAbstractAuthConsumer):
def get_user_url(self, request):
}
weight = 340
human_name = 'Verisign'
- icon = '/media/images/openid/verisign.ico'
+ icon = '/media/images/openid/verisign.png'
class OpenIdUrlAuthConsumer(OpenIdAbstractAuthConsumer):
weight = 300
human_name = 'OpenId url'
stack_item_template = 'modules/openidauth/openidurl.html'
- icon = '/media/images/openid/openid-inputicon.gif'
\ No newline at end of file
+ icon = '/media/images/openid/openid-inputicon.gif'
style="width: 500px; background: url('{% media provider.icon %}') no-repeat left center" />\r
</td>\r
<td>\r
- <input type="submit" name="signin" value="{% trans 'Login' %}" />\r
+ <input type="submit" name="ssignin" value="Login" />\r
</td>\r
</tr>\r
</table>\r
from forum.models import Question
+from forum.modules.decorators import decorate
+from forum.views.readers import do_question_search
+@decorate(do_question_search, needs_origin=False)
def question_search(keywords):
- return Question.objects.extra(
+ return Question.objects.all().extra(
select={
- 'ranking': "node_ranking(id, %s)",
+ 'ranking': 'node_ranking("forum_node"."id", %s)',
},
- where=["node_ranking(id, %s) > 0"],
+ where=['node_ranking("forum_node"."id", %s) > 0'],
params=[keywords],
- select_params=[keywords]
- ).order_by('-ranking')
\ No newline at end of file
+ select_params=[keywords],
+ order_by=['-ranking']
+ )
\ No newline at end of file
SELECT active_revision_id INTO rev_id FROM forum_node WHERE id = node_id;
SELECT tsv INTO v FROM forum_noderevision WHERE id = rev_id;
- SELECT count(*) INTO child_count FROM forum_node WHERE abs_parent_id = node_id AND NOT deleted;
+ SELECT count(*) INTO child_count FROM forum_node WHERE abs_parent_id = node_id AND deleted_id IS NULL;
IF child_count > 0 THEN
- FOR r in SELECT * FROM forum_node WHERE abs_parent_id = node_id AND NOT deleted LOOP
+ FOR r in SELECT * FROM forum_node WHERE abs_parent_id = node_id AND deleted_id IS NULL LOOP
SELECT tsv INTO cv FROM forum_noderevision WHERE id = r.active_revision_id;
v :=(v || cv);
END LOOP;
--- /dev/null
+from forum.settings.base import Setting\r
+\r
+PG_FTSTRIGGERS_VERSION = Setting('PG_FTSTRIGGERS_VERSION', 0)
\ No newline at end of file
import os\r
from forum.models import KeyValue\r
from django.db import connection, transaction\r
+import settings\r
\r
-KEY = 'PG_FTSTRIGGERS_VERSION'\r
-VERSION = 3\r
-install = False\r
+VERSION = 4\r
\r
-try:\r
- version = KeyValue.objects.get(key=KEY).value\r
- if version < VERSION:\r
- install = True\r
-except:\r
- install = True\r
-\r
-\r
-if install:\r
+if int(settings.PG_FTSTRIGGERS_VERSION) < VERSION:\r
f = open(os.path.join(os.path.dirname(__file__), 'pg_fts_install.sql'), 'r')\r
\r
try:\r
cursor.execute(f.read())\r
transaction.commit_unless_managed()\r
\r
- try:\r
- kv = KeyValue.objects.get(key=KEY)\r
- except:\r
- kv = KeyValue(key=KEY)\r
-\r
- kv.value = VERSION\r
- kv.save()\r
+ settings.PG_FTSTRIGGERS_VERSION.set_value(VERSION)\r
\r
except Exception, e:\r
#import sys, traceback\r
cursor.close()\r
\r
f.close()\r
+\r
+import handlers\r
-from forum.badges.base import CountableAbstractBadge
-from forum.models import Question, Tag
-from forum import const
from django.utils.translation import ugettext as _
+from forum.badges.base import AbstractBadge
+from forum.models import Badge, Tag
+from forum.actions import VoteUpAction
import settings
-class BugBusterBadge(CountableAbstractBadge):
- type = const.SILVER_BADGE
- description = _('Got %s upvotes in a question tagged with "bug"') % str(settings.BUG_BUSTER_VOTES_UP)
+class BugBuster(AbstractBadge):
+ type = Badge.SILVER
+ name = _("Bug Buster")
+ description = _('Got %s upvotes in a question tagged with "bug"') % settings.BUG_BUSTER_VOTES_UP
+ listen_to = (VoteUpAction, )
- def __init__(self):
-
- def handler(instance):
+ def award_to(self, action):
+ if action.node.node_type == "question" and action.node.score == settings.BUG_BUSTER_VOTES_UP:
try:
- bug_tag = Tag.objects.get(name='bug')
- if bug_tag in instance.tags.all():
- self.award_badge(instance.author, instance)
+ bug = Tag.objects.get(name="bug")
+ if bug in action.node.tags.all():
+ return action.node.author
except:
pass
-
- super(BugBusterBadge, self).__init__(Question, 'vote_up_count', settings.BUG_BUSTER_VOTES_UP, handler)
\ No newline at end of file
--- /dev/null
+import markdown\r
+from django.utils.safestring import mark_safe\r
+from django.utils.html import strip_tags\r
+from forum.utils.html import sanitize_html\r
+\r
+class LimitedSyntaxExtension(markdown.Extension):\r
+ def extendMarkdown(self, md, md_globals):\r
+ del md.inlinePatterns["image_reference"]\r
+\r
+def makeExtension(configs=None) :\r
+ return LimitedSyntaxExtension(configs=configs)\r
'django.template.loaders.app_directories.load_template_source',
'forum.modules.module_templates_loader',
'forum.skins.load_template_source',
-# 'django.template.loaders.eggs.load_template_source',
+# 'django.template.loaders.eggs.load_template_source',
)
MIDDLEWARE_CLASSES = [
import logging
logging.basicConfig(
filename=os.path.join(SITE_SRC_ROOT, 'log', LOG_FILENAME),
- level=logging.DEBUG,
+ level=logging.ERROR,
format='%(pathname)s TIME: %(asctime)s MSG: %(filename)s:%(funcName)s:%(lineno)d %(message)s',
)