X-Git-Url: https://git.openstreetmap.org/osqa.git/blobdiff_plain/0cfa31f684a8d64a65b8a16f18bb79be49f13701..410bfa05ee36ed1d99356c443a5f3f6aa3ee9578:/forum/badges/base.py diff --git a/forum/badges/base.py b/forum/badges/base.py index 63b6b0b..fce6b6e 100644 --- a/forum/badges/base.py +++ b/forum/badges/base.py @@ -4,111 +4,66 @@ from string import lower from django.contrib.contenttypes.models import ContentType from django.db.models.signals import post_save -from forum.models.user import activity_record -from forum.models.base import denorm_update -from forum.models import Badge, Award, Activity, Node +from forum.models import Badge, Node +from forum.actions import AwardAction import logging -class AbstractBadge(object): - - _instance = None - - @property - def name(self): - return " ".join(re.findall(r'([A-Z][a-z1-9]+)', re.sub('Badge', '', self.__class__.__name__))) - - @property - def description(self): - raise NotImplementedError - - def __new__(cls, *args, **kwargs): - if cls._instance is None: - cls.badge = "-".join(map(lower, re.findall(r'([A-Z][a-z1-9]+)', re.sub('Badge', '', cls.__name__)))) - cls._instance = super(AbstractBadge, cls).__new__(cls, *args, **kwargs) - - return cls._instance - - def install(self): - try: - installed = Badge.objects.get(slug=self.badge) - except: - badge = Badge(name=self.name, description=self.description, slug=self.badge, type=self.type) - badge.save() - - def award_badge(self, user, obj=None, award_once=False): - try: - badge = Badge.objects.get(slug=self.badge) - except: - logging.log(1, 'Trying to award a badge not installed in the database.') - return - - content_type = ContentType.objects.get_for_model(obj.__class__) - - awarded = user.awards.filter(badge=badge) +installed = dict([(b.cls, b) for b in Badge.objects.all()]) - if not award_once: - awarded = awarded.filter(content_type=content_type, object_id=obj.id) +class BadgesMeta(type): + by_class = {} + by_id = {} - if len(awarded): - logging.log(1, 'Trying to award badged already awarded.') - return - - award = Award(user=user, badge=badge, content_type=content_type, object_id=obj.id) - award.save() + def __new__(mcs, name, bases, dic): + badge = type.__new__(mcs, name, bases, dic) -class CountableAbstractBadge(AbstractBadge): + if not dic.get('abstract', False): + if not name in installed: + badge.ondb = Badge(cls=name, type=dic.get('type', Badge.BRONZE)) + badge.ondb.save() + else: + badge.ondb = installed[name] - def __init__(self, model, field, expected_value, handler): - def wrapper(instance, sfield, old, new, **kwargs): - if sfield == field and (new == expected_value) or (old < expected_value and new > expected_value): - handler(instance=instance) - - denorm_update.connect(wrapper, sender=model, weak=False) + inst = badge() -class PostCountableAbstractBadge(CountableAbstractBadge): - def __init__(self, model, field, expected_value): + def hook(action, new): + user = inst.award_to(action) - def handler(instance): - self.award_badge(instance.author, instance) + if user: + badge.award(user, action, badge.award_once) - super(PostCountableAbstractBadge, self).__init__(model, field, expected_value, handler) + for action in badge.listen_to: + action.hook(hook) -class NodeCountableAbstractBadge(CountableAbstractBadge): - def __init__(self, node_type, field, expected_value): + BadgesMeta.by_class[name] = badge + badge.ondb.__dict__['_class'] = inst + BadgesMeta.by_id[badge.ondb.id] = badge - def handler(instance): - if instance.node_type == node_type: - self.award_badge(instance.author, instance) + return badge - super(NodeCountableAbstractBadge, self).__init__(Node, field, expected_value, handler) - -class ActivityAbstractBadge(AbstractBadge): - - def __init__(self, activity_type, handler): - - def wrapper(sender, **kwargs): - handler(instance=kwargs['instance']) - - activity_record.connect(wrapper, sender=activity_type, weak=False) - - -class ActivityCountAbstractBadge(AbstractBadge): +class AbstractBadge(object): + __metaclass__ = BadgesMeta - def __init__(self, activity_type, count): + abstract = True + award_once = False - def handler(sender, **kwargs): - instance = kwargs['instance'] - if Activity.objects.filter(user=instance.user, activity_type__in=activity_type).count() == count: - self.award_badge(instance.user, instance.content_object) + @property + def name(self): + raise NotImplementedError - if not isinstance(activity_type, (tuple, list)): - activity_type = (activity_type, ) + @property + def description(self): + raise NotImplementedError - for type in activity_type: - activity_record.connect(handler, sender=type, weak=False) + @classmethod + def award(cls, user, action, once=False): + if once: + node = None + else: + node = action.node -class FirstActivityAbstractBadge(ActivityCountAbstractBadge): + awarded = AwardAction.get_for(user, node, cls.ondb) - def __init__(self, activity_type): - super(FirstActivityAbstractBadge, self).__init__(activity_type, 1) + if not awarded: + AwardAction(user=user, node=node, ip=action.ip).save(data=dict(badge=cls.ondb, trigger=action)) \ No newline at end of file