• Giuseppe Terrasi's avatar
    · 795d73a4
    Giuseppe Terrasi authored
    Initial release based on svn rev 1272 with no changes
    795d73a4
base.py 2.22 KB
import re
from string import lower

from django.core.exceptions import MultipleObjectsReturned
from django.db.models.signals import post_save

from forum.models import Badge, Node, Action
from forum.actions import AwardAction

import logging

installed = dict([(b.cls, b) for b in Badge.objects.all()])

class BadgesMeta(type):
    by_class = {}
    by_id = {}

    def __new__(mcs, name, bases, dic):
        badge = type.__new__(mcs, name, bases, dic)

        if not dic.get('abstract', False):
            if not name in installed:
                ondb = Badge(cls=name, type=dic.get('type', Badge.BRONZE))
                ondb.save()
            else:
                ondb = installed[name]

            badge.ondb = ondb.id

            inst = badge()

            def hook(action, new):
                user = inst.award_to(action)

                if user:
                    badge.award(user, action, badge.award_once)

            for action in badge.listen_to:
                action.hook(hook)

            BadgesMeta.by_class[name] = inst
            BadgesMeta.by_id[ondb.id] = inst

        return badge

class AbstractBadge(object):
    __metaclass__ = BadgesMeta

    abstract = True
    award_once = False

    @property
    def name(self):
        raise NotImplementedError

    @property
    def description(self):
        raise NotImplementedError

    @classmethod
    def award(cls, user, action, once=False):
        db_object = Badge.objects.get(id=cls.ondb)
        try:
            if once:
                node = None
                awarded = AwardAction.get_for(user, db_object)
            else:
                node = action.node
                awarded = AwardAction.get_for(user, db_object, node)

            trigger = isinstance(action, Action) and action or None

            if not awarded:
                AwardAction(user=user, node=node).save(data=dict(badge=db_object, trigger=trigger))
        except MultipleObjectsReturned:
            if node:
                logging.error('Found multiple %s badges awarded for user %s (%s)' % (self.name, user.username, user.id))
            else:
                logging.error('Found multiple %s badges awarded for user %s (%s) and node %s' % (self.name, user.username, user.id, node.id))