]> git.openstreetmap.org Git - osqa.git/blob - forum/badges/base.py
Reintegrate merge cacheimp -> trunk.
[osqa.git] / forum / badges / base.py
1 import re
2 from string import lower
3
4 from django.core.exceptions import MultipleObjectsReturned
5 from django.db.models.signals import post_save
6
7 from forum.models import Badge, Node, Action
8 from forum.actions import AwardAction
9
10 import logging
11
12 installed = dict([(b.cls, b) for b in Badge.objects.all()])
13
14 class BadgesMeta(type):
15     by_class = {}
16     by_id = {}
17
18     def __new__(mcs, name, bases, dic):
19         badge = type.__new__(mcs, name, bases, dic)
20
21         if not dic.get('abstract', False):
22             if not name in installed:
23                 ondb = Badge(cls=name, type=dic.get('type', Badge.BRONZE))
24                 ondb.save()
25             else:
26                 ondb = installed[name]
27
28             badge.ondb = ondb.id
29
30             inst = badge()
31
32             def hook(action, new):
33                 user = inst.award_to(action)
34
35                 if user:
36                     badge.award(user, action, badge.award_once)
37
38             for action in badge.listen_to:
39                 action.hook(hook)
40
41             BadgesMeta.by_class[name] = inst
42             BadgesMeta.by_id[ondb.id] = inst
43
44         return badge
45
46 class AbstractBadge(object):
47     __metaclass__ = BadgesMeta
48
49     abstract = True
50     award_once = False
51
52     @property
53     def name(self):
54         raise NotImplementedError
55
56     @property
57     def description(self):
58         raise NotImplementedError
59
60     @classmethod
61     def award(cls, user, action, once=False):
62         db_object = Badge.objects.get(id=cls.ondb)
63         try:
64             if once:
65                 node = None
66                 awarded = AwardAction.get_for(user, db_object)
67             else:
68                 node = action.node
69                 awarded = AwardAction.get_for(user, db_object, node)
70
71             trigger = isinstance(action, Action) and action or None
72
73             if not awarded:
74                 AwardAction(user=user, node=node).save(data=dict(badge=db_object, trigger=trigger))
75         except MultipleObjectsReturned:
76             if node:
77                 logging.error('Found multiple %s badges awarded for user %s (%s)' % (self.name, user.username, user.id))
78             else:
79                 logging.error('Found multiple %s badges awarded for user %s (%s) and node %s' % (self.name, user.username, user.id, node.id))