import re from itertools import groupby from operator import attrgetter from django import forms from django.utils.translation import ugettext_lazy as _ from .models import Group, Permission DEFAULT_PERMS = ['view', 'add', 'change', 'delete'] DEFAULT_PERMS_LABELS = { 'view': _("Voir"), 'add': _("Ajouter"), 'change': _("Modifier"), 'delete': _("Supprimer"), } class GroupsField(forms.ModelMultipleChoiceField): def __init__(self, **kwargs): kwargs.setdefault('queryset', Group.objects.all()) kwargs.setdefault('widget', forms.CheckboxSelectMultiple) super().__init__(**kwargs) class BasePermissionsField(forms.ModelMultipleChoiceField): def __init__(self, **kwargs): kwargs.setdefault('widget', forms.CheckboxSelectMultiple(attrs={ 'field_class': 'permissions-field', })) super().__init__(**kwargs) # Contain permissions grouped by `ContentType`. Used as choices for # this field. grouped_choices = [] for ct, perms in groupby(self.queryset, attrgetter('content_type')): model_opts = ct.model_class()._meta choices = [] # This helps for the default permissions, if they exists, to appear # at the beginning of the permissions list and use custom labels. reg_defaults_p = re.compile( r'^(?P({defaults}))_{model_name}$' .format( defaults='|'.join(DEFAULT_PERMS), model_name=model_opts.model_name, ) ) next_default_pos = 0 for p in perms: match = reg_defaults_p.match(p.codename) if match: # `p` is a default permission. Use shorter label and insert # after the last default permission seen in `choices`. p_type = match.group('p_type') choices.insert( next_default_pos, (p.id, DEFAULT_PERMS_LABELS[p_type]) ) next_default_pos += 1 else: # Non-default permissions. Use the permission description, # instead of its `__str__`. choices.append((p.id, p.name)) grouped_choices.append((model_opts.verbose_name_plural, choices)) self.choices = grouped_choices class CorePermissionsField(BasePermissionsField): def __init__(self, **kwargs): kwargs.setdefault('queryset', Permission.kfetcore.all()) super().__init__(**kwargs)