]> git.openstreetmap.org Git - osqa.git/blob - forum/badges/base.py
Fixes a problem that might allow some users to get multiple badges in some strange...
[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                 badge.ondb = Badge(cls=name, type=dic.get('type', Badge.BRONZE))
24                 badge.ondb.save()
25             else:
26                 badge.ondb = installed[name]
27
28             inst = badge()
29
30             def hook(action, new):
31                 user = inst.award_to(action)
32
33                 if user:
34                     badge.award(user, action, badge.award_once)
35
36             for action in badge.listen_to:
37                 action.hook(hook)
38
39             BadgesMeta.by_class[name] = badge
40             badge.ondb.__dict__['_class'] = inst
41             BadgesMeta.by_id[badge.ondb.id] = badge
42
43         return badge
44
45 class AbstractBadge(object):
46     __metaclass__ = BadgesMeta
47
48     abstract = True
49     award_once = False
50
51     @property
52     def name(self):
53         raise NotImplementedError
54
55     @property
56     def description(self):
57         raise NotImplementedError
58
59     @classmethod
60     def award(cls, user, action, once=False):
61         try:
62             if once:
63                 node = None
64                 awarded = AwardAction.get_for(user, cls.ondb)
65             else:
66                 node = action.node
67                 awarded = AwardAction.get_for(user, cls.ondb, node)
68
69             trigger = isinstance(action, Action) and action or None
70
71             if not awarded:
72                 AwardAction(user=user, node=node, ip=action.ip).save(data=dict(badge=cls.ondb, trigger=trigger))
73         except MultipleObjectsReturned:
74             if node:
75                 logging.error('Found multiple %s badges awarded for user %s (%s)' % (self.name, user.username, user.id))
76             else:
77                 logging.error('Found multiple %s badges awarded for user %s (%s) and node %s' % (self.name, user.username, user.id, node.id))