1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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))