PK![4XX"drf_action_permissions/__init__.pyfrom .permissions import DjangoActionPermissions __all__ = ["DjangoActionPermissions"] PK!4h(%drf_action_permissions/permissions.py""" drf_action_permissions/permissions.py ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tools for managing action permissions in Django REST framework. :copyright: (c) 2019 by Andrey Bogoyavlensky. """ from rest_framework.permissions import DjangoModelPermissions class DjangoActionPermissions(DjangoModelPermissions): """Customize permission logic based on request, action and object. For every viewset with `queryset` you want to override some custom logic for particular action, you should define such attribute for `viewset`. Viewset permission at common action level: ``` perms_map_action = { '': [ | , ... ], ... } ``` Viewset permission at object action level: ``` perms_map_action_obj = { '': [ | , ... ], ... } ``` """ perms_map = { "GET": [], "OPTIONS": [], "HEAD": [], "POST": ["%(app_label)s.add_%(model_name)s"], "PUT": ["%(app_label)s.change_%(model_name)s"], "PATCH": ["%(app_label)s.change_%(model_name)s"], "DELETE": ["%(app_label)s.delete_%(model_name)s"], } perms_map_action = { "retrieve": ["%(app_label)s.view_%(model_name)s"], "list": ["%(app_label)s.view_%(model_name)s_list"], "create": ["%(app_label)s.change_%(model_name)s"], "update": ["%(app_label)s.change_%(model_name)s"], } # pylint: disable=protected-access def get_origin_model(self, model_cls): """Return origin model even if proxy has been received.""" return model_cls._meta.proxy_for_model or model_cls._meta.model def get_required_permissions(self, method, model_cls): """Add ability to define origin model even via proxy.""" model_cls = self.get_origin_model(model_cls) return super().get_required_permissions(method, model_cls) def get_perms_list(self, view, obj=None): """Return permission list for action from backend and view.""" perms_map_name = "perms_map_action_obj" if obj else "perms_map_action" view_perms_map = getattr(view, perms_map_name, {}) view_perms_list = view_perms_map.get(view.action) if view_perms_list is not None: return view_perms_list backend_perms_map = getattr(self, perms_map_name, {}) return backend_perms_map.get(view.action) or [] # pylint: disable=protected-access def get_required_action_permissions(self, view, model_cls, obj=None): """Given a model and an action, return the list of permission codes.""" model_cls = self.get_origin_model(model_cls) kwargs = { "app_label": model_cls._meta.app_label, "model_name": model_cls._meta.model_name, } return [ perm % kwargs if isinstance(perm, str) else perm for perm in self.get_perms_list(view, obj) ] def user_has_action_perm(self, user, view, perm, obj=None): """Check if user has single permission for particular view action.""" assert callable(perm) or isinstance( perm, str ), "Permission must be function or string" if callable(perm): return perm(user, view, obj) return user.has_perm(perm) def has_action_permission(self, request, view, obj=None): """Check action specific permissions ignoring custom method.""" queryset = self._queryset(view) perms = self.get_required_action_permissions(view, queryset.model, obj) return all( self.user_has_action_perm(request.user, view, perm, obj) for perm in perms ) def has_permission(self, request, view): """Apply action permission without object and with ignoring method.""" result = super().has_permission(request, view) return result and self.has_action_permission(request, view) def has_object_permission(self, request, view, obj): """Apply action permission with object and with ignoring method.""" return self.has_action_permission(request, view, obj) PK!HڽTU,drf_action_permissions-0.1.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!H`4b /drf_action_permissions-0.1.0.dist-info/METADATAW[o6~1KJ֡;Ѹ P*%6ITIʎR">Dw> =ㆥ0=WZ"g-yHSXb`+ʅFMvJU3U2"8u:4ю&]JEǟYt>Yҥ?[_2^VumL X b?yb5dwupוH`,̦ p.aj7?kC0Í[ Uf-UHGExMzo6=3+\EdοT\x75[_ ]d - jz1TrS|8%W;Ŋ^A$>Vy7kq,tq'}~柝 > e%e@g*cT9/ c~wRq& gp'l顫9/F1׉]m]B6~oK 9!% ^L RA!k?<|CYc/ׂg p3jWEYKrkq\,=(:x2_q^"~T"SQX~4']#ho~*8B}20554mfa+$JӛR uxy (iXˊnYa|25;YZfLT%. y6Ō% NЇ\},}~S䴻n^ІesB>}3&i)J*ܞDK\*(K?M"")_S'wbZ к#-fo9PoOƓѻf2MjXL'![+ #wQ7e#9|V~KH)  0X>\Ҭa@\9SKTN568a0SxXʑq? DVk 1Ӄ l ?=!dz!:{ ߐ4vX~ϰBKS.Cvhv1Hm07tyagk>+(c1 /9b ȃ2ͽNwyL ;C kƤR ¢2ƒpAbp!R>D ִEYd5e*Y 1ubV\,Q:j]&*ޔfww`ơj4z$l@-~J9^0ycьq"!M;p"ЍUg^ݾ QO/vw-ŶHc.OvTYn/r+n<&5yxInxiցJj3@Z6-W͙9wP8m-3n#\Ѿdr%SPHkxqUAt?Y_;*s?Z\?B6/SPK!HZ-drf_action_permissions-0.1.0.dist-info/RECORD=s0$ 8R. _.9wn>qbrђ*i ڶN10h329!91b{>:7ꏎ@8k=iV Eك_ ;w\!Zq G E;'"/1moei9 -ӴHR;G1L}_19(DOCpP~p̭fh[lQ|_S%/n\ѰȩpsYu6n &?PK![4XX"drf_action_permissions/__init__.pyPK!4h(%drf_action_permissions/permissions.pyPK!HڽTU,drf_action_permissions-0.1.0.dist-info/WHEELPK!H`4b /Vdrf_action_permissions-0.1.0.dist-info/METADATAPK!HZ-drf_action_permissions-0.1.0.dist-info/RECORDPKW