# Provide permissions handling # we don't import models at module level in order to avoid migration problems from django.utils.translation import gettext_lazy as _ from django.contrib.auth.models import Group, Permission from django.contrib.contenttypes.models import ContentType from .models import Program __all__ = ("PagePermissions", "program") class PagePermissions: """Handles obj permissions initialization of page subclass.""" model = None # TODO: move values to subclass groups = ({"label": _("editors"), "field": "editors_group_id", "perms": ["update"]},) """Groups informations initialized.""" groups_name_format = "{obj.title}: {group_label}" """Format used for groups name.""" perms_name_format = "{obj.title}: can {perm}" """Format used for permission name (displayed to humans).""" perms_codename_format = "{obj._meta.label_lower}_{obj.pk}_{perm}" """Format used for permissions codename.""" def __init__(self, model): self.model = model def can(self, user, perm, obj): """Return True wether if user can edit Program or its children.""" from .models.page import ChildPage if isinstance(obj, ChildPage): obj = obj.parent_subclass if not isinstance(obj, self.model): return False if user.is_superuser: return True perm = self.perms_codename_format.format(self=self, perm=perm, obj=obj) return user.has_perm(perm) def init(self, obj, model=None): """Initialize permissions for the provided obj. Return True if group or permission have been created (`obj` has thus been saved). """ updated = False created_groups = [] # init groups for infos in self.groups: group = getattr(obj, infos["field"]) if not group: group, created = self.init_group(obj, infos) setattr(obj, infos["field"], group.pk) updated = True created and created_groups.append((group, infos)) if updated: obj.save() # init perms for group, infos in created_groups: self.init_perms(obj, group, infos) return updated def init_group(self, obj, infos): name = self.groups_name_format.format(obj=obj, group_label=infos["label"]) return Group.objects.get_or_create(name=name) def init_perms(self, obj, group, infos): # TODO: avoid multiple database hits for name in infos["perms"]: perm, _ = Permission.objects.get_or_create( codename=self.perms_codename_format.format(obj=obj, perm=name), content_type=ContentType.objects.get_for_model(obj), defaults={"name": self.perms_name_format.format(obj=obj, perm=name)}, ) if perm not in group.permissions.all(): group.permissions.add(perm) program = PagePermissions(Program)