]> git.openstreetmap.org Git - osqa.git/blob - forum/badges/base.py
initial import
[osqa.git] / forum / badges / base.py
1 import re
2 from string import lower
3
4 from django.contrib.contenttypes.models import ContentType
5 from django.db.models.signals import post_save
6
7 from forum.models.user import activity_record
8 from forum.models import Badge, Award, Activity
9
10 import logging
11
12 class AbstractBadge(object):
13
14     _instance = None
15
16     @property
17     def name(self):
18         return " ".join(re.findall(r'([A-Z][a-z1-9]+)', re.sub('Badge', '', self.__class__.__name__)))
19
20     @property
21     def description(self):
22         raise NotImplementedError
23
24     def __new__(cls, *args, **kwargs):
25         if cls._instance is None:
26             cls.badge = "-".join(map(lower, re.findall(r'([A-Z][a-z1-9]+)', re.sub('Badge', '', cls.__name__)))) 
27             cls._instance = super(AbstractBadge, cls).__new__(cls, *args, **kwargs)
28
29         return cls._instance
30
31     def install(self):
32         try:
33             installed = Badge.objects.get(slug=self.badge)
34         except:
35             badge = Badge(name=self.name, description=self.description, slug=self.badge, type=self.type)
36             badge.save()
37
38     def award_badge(self, user, obj=None, award_once=False):
39         try:
40             badge = Badge.objects.get(slug=self.badge)
41         except:
42             logging.log('Trying to award a badge not installed in the database.')
43             return
44             
45         content_type = ContentType.objects.get_for_model(obj.__class__)
46
47         awarded = user.awards.filter(badge=badge)
48
49         if not award_once:
50             awarded = awarded.filter(content_type=content_type, object_id=obj.id)
51
52         if len(awarded):
53             logging.log(1, 'Trying to award badged already awarded.')
54             return
55             
56         award = Award(user=user, badge=badge, content_type=content_type, object_id=obj.id)
57         award.save()
58
59 class CountableAbstractBadge(AbstractBadge):
60
61     def __init__(self, model, field, expected_value, handler):
62         def wrapper(instance, **kwargs):
63             dirty_fields = instance.get_dirty_fields()
64             if field in dirty_fields and instance.__dict__[field] == expected_value:
65                 handler(instance=instance)
66         
67         post_save.connect(wrapper, sender=model, weak=False)
68
69 class PostCountableAbstractBadge(CountableAbstractBadge):
70     def __init__(self, model, field, expected_value):
71
72         def handler(instance):            
73             self.award_badge(instance.author, instance)
74
75         super(PostCountableAbstractBadge, self).__init__(model, field, expected_value, handler)
76
77
78 class ActivityAbstractBadge(AbstractBadge):
79
80     def __init__(self, activity_type, handler):
81
82         def wrapper(sender, **kwargs):
83             handler(instance=kwargs['instance'])
84
85         activity_record.connect(wrapper, sender=activity_type, weak=False)
86
87
88 class ActivityCountAbstractBadge(AbstractBadge):
89
90     def __init__(self, activity_type, count):
91
92         def handler(sender, **kwargs):
93             instance = kwargs['instance']
94             if Activity.objects.filter(user=instance.user, activity_type__in=activity_type).count() == count:
95                 self.award_badge(instance.user, instance.content_object)
96
97         if not isinstance(activity_type, (tuple, list)):
98             activity_type = (activity_type, )
99
100         for type in activity_type:
101             activity_record.connect(handler, sender=type, weak=False)
102
103 class FirstActivityAbstractBadge(ActivityCountAbstractBadge):
104
105     def __init__(self, activity_type):
106         super(FirstActivityAbstractBadge, self).__init__(activity_type, 1)