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, Node
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)
77 class NodeCountableAbstractBadge(CountableAbstractBadge):
78 def __init__(self, node_type, field, expected_value):
80 def handler(instance):
81 if instance.node_type == node_type:
82 self.award_badge(instance.author, instance)
84 super(NodeCountableAbstractBadge, self).__init__(Node, field, expected_value, handler)
86 class ActivityAbstractBadge(AbstractBadge):
88 def __init__(self, activity_type, handler):
90 def wrapper(sender, **kwargs):
91 handler(instance=kwargs['instance'])
93 activity_record.connect(wrapper, sender=activity_type, weak=False)
96 class ActivityCountAbstractBadge(AbstractBadge):
98 def __init__(self, activity_type, count):
100 def handler(sender, **kwargs):
101 instance = kwargs['instance']
102 if Activity.objects.filter(user=instance.user, activity_type__in=activity_type).count() == count:
103 self.award_badge(instance.user, instance.content_object)
105 if not isinstance(activity_type, (tuple, list)):
106 activity_type = (activity_type, )
108 for type in activity_type:
109 activity_record.connect(handler, sender=type, weak=False)
111 class FirstActivityAbstractBadge(ActivityCountAbstractBadge):
113 def __init__(self, activity_type):
114 super(FirstActivityAbstractBadge, self).__init__(activity_type, 1)