Autres langues

Code source de openPLM.apps.badges.utils

from django.db import models
from django.db.models.signals import post_save
from django.contrib.auth.models import User

from .models import Badge as BadgeModel
from .models import BadgeToUser, LEVEL_CHOICES


class RequiresUserOrProgress(Exception): pass

registered_badges = {}

def register(badge):
    if badge.id not in registered_badges:
        registered_badges[badge.id] = badge()
    return badge

def badge_count(user_or_qs=None):
    """
    Given a user or queryset of users, this returns the badge
    count at each badge level that the user(s) have earned.

    Example:

     >>> badge_count(User.objects.filter(username='admin'))
     [{'count': 0, 'badge__level': '1'}, {'count': 0, 'badge__level': '2'}, {'count': 0, 'badge__level': '3'}, {'count': 0, 'badge__level': '4'}]

    Uses a single database query.
    """

    badge_counts = BadgeToUser.objects.all()
    if isinstance(user_or_qs, User):
        badge_counts = badge_counts.filter(user=user_or_qs)
    elif isinstance(user_or_qs, models.QuerySet):
        badge_counts = badge_counts.filter(user__in=user_or_qs)

    badge_counts = badge_counts.values('badge__level')
    badge_counts = badge_counts.annotate(count=models.Count('badge__level'))

    def get_badge_count(level):
        bc = [bc for bc in badge_counts if bc['badge__level'] == level]
        if bc:
            return bc[0]
        else:
            # if the user has no badges at this level, return the appropriate response
            return {'count': 0, 'badge__level': level}


    return [get_badge_count(level_choice[0]) for level_choice in LEVEL_CHOICES]


class MetaBadgeMeta(type):

    def __new__(cls, name, bases, attrs):
        new_badge = super(MetaBadgeMeta, cls).__new__(cls, name, bases, attrs)
        parents = [b for b in bases if isinstance(b, MetaBadgeMeta)]
        if not parents:
            # If this isn't a subclass of MetaBadge, don't do anything special.
            return new_badge
        return register(new_badge)


[docs]class MetaBadge(object): __metaclass__ = MetaBadgeMeta one_time_only = False model = models.Model link_to_doc = None progress_start = 0 progress_finish = 1 def __init__(self): # whenever the server is reloaded, the badge will be initialized and # added to the database self._keep_badge_updated() post_save.connect(self._signal_callback, sender=self.model) def _signal_callback(self, **kwargs): i = kwargs['instance'] self.award_ceremony(i) def _test_conditions(self, instance): condition_callbacks = [getattr(self, c) for c in dir(self) if c.startswith('check')] # will return False on the first False condition return all( fn(instance) for fn in condition_callbacks )
[docs] def get_user(self, instance): """ This function should be overriden if the user can not be reached using `instance.user` """ return instance.user
def get_progress(self, user): return int(BadgeToUser.objects.filter(user=user, badge=self.badge).exists())
[docs] def get_progress_percentage(self, progress=None, user=None): """ Return the percentage of progress for a user. """ if user is None and progress is None: raise RequiresUserOrProgress("This method requires either a user or progress keyword argument") if not progress: progress = self.get_progress(user) progress = min(progress, self.progress_finish) # multiply by a float to get floating point precision return (100.0 * progress) / (self.progress_finish - self.progress_start)
def _keep_badge_updated(self): if getattr(self, 'badge', False): return False badge, created = BadgeModel.objects.get_or_create(id=self.id) if badge.level != self.level: badge.level = self.level badge.save() self.badge = badge def award_ceremony(self, instance): if self._test_conditions(instance): user = self.get_user(instance) self.badge.award_to(user)
[docs] def check_user(self, instance): """ checks if the user exists or not """ if self.get_user(instance) : return True else : return False
[docs] def check_can_win_badge(self, instance): """ Checks if a user can win a badge. Some badge can only be won by contributor. If a badge can be won by user who are not contributor this function should be overridden """ user = self.get_user(instance) if user : return user.profile.is_contributor else : return False