2 from string import lower
4 from django.contrib.contenttypes.models import ContentType
5 from django.db.models.signals import post_save
7 from forum.models.user import activity_record
8 from forum.models import Badge, Award, Activity
12 class AbstractBadge(object):
18 return " ".join(re.findall(r'([A-Z][a-z1-9]+)', re.sub('Badge', '', self.__class__.__name__)))
21 def description(self):
22 raise NotImplementedError
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)
33 installed = Badge.objects.get(slug=self.badge)
35 badge = Badge(name=self.name, description=self.description, slug=self.badge, type=self.type)
38 def award_badge(self, user, obj=None, award_once=False):
40 badge = Badge.objects.get(slug=self.badge)
42 logging.log('Trying to award a badge not installed in the database.')
45 content_type = ContentType.objects.get_for_model(obj.__class__)
47 awarded = user.awards.filter(badge=badge)
50 awarded = awarded.filter(content_type=content_type, object_id=obj.id)
53 logging.log(1, 'Trying to award badged already awarded.')
56 award = Award(user=user, badge=badge, content_type=content_type, object_id=obj.id)
59 class CountableAbstractBadge(AbstractBadge):
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)
67 post_save.connect(wrapper, sender=model, weak=False)
69 class PostCountableAbstractBadge(CountableAbstractBadge):
70 def __init__(self, model, field, expected_value):
72 def handler(instance):
73 self.award_badge(instance.author, instance)
75 super(PostCountableAbstractBadge, self).__init__(model, field, expected_value, handler)
78 class ActivityAbstractBadge(AbstractBadge):
80 def __init__(self, activity_type, handler):
82 def wrapper(sender, **kwargs):
83 handler(instance=kwargs['instance'])
85 activity_record.connect(wrapper, sender=activity_type, weak=False)
88 class ActivityCountAbstractBadge(AbstractBadge):
90 def __init__(self, activity_type, count):
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)
97 if not isinstance(activity_type, (tuple, list)):
98 activity_type = (activity_type, )
100 for type in activity_type:
101 activity_record.connect(handler, sender=type, weak=False)
103 class FirstActivityAbstractBadge(ActivityCountAbstractBadge):
105 def __init__(self, activity_type):
106 super(FirstActivityAbstractBadge, self).__init__(activity_type, 1)