Package: ezperm
Easy permissionsDefine user permissions and resource access simply and efficiently.InstallationpipinstallezpermUsage & examplesGeneral caseAssume we are in charge of a superhero team. We have a list of heroes, and we want to define permissions for them.
Our hero model might look like this:importdataclasses@dataclasses.dataclassclassHero:name:strage:intpermissions:list['Permissions']After a while of working with our heroes, we realize that some of them are terrible cooks. We want to define a permission
that will allow only some of them to cook or bake.This can be done by extending thePermissionEnumclass and defining a_has_permmethod that will check if the hero has the permission.Permission enumsimportezpermclassPermissions(ezperm.PermissionEnum):CAN_COOK='CAN_COOK'CAN_BAKE='CAN_BAKE'def_has_perm(self,hero:Hero)->bool:returnself.valueinhero.permissionsNow lets use our permissions in the code:# Define some heroesironman=Hero('Ironman',45,[Permissions.CAN_COOK,Permissions.CAN_BAKE])deadpool=Hero('Deadpool',30,[Permissions.CAN_BAKE])hulk=Hero('Hulk',55,[])# Check if the hero has a permissionPermissions.CAN_COOK(ironman)# ➞ TruePermissions.CAN_COOK(deadpool)# ➞ FalsePermissions.CAN_COOK(hulk)# ➞ FalseIt is possible to use&(logical and),|(logical or)or~(negation)operators to combine permissions:(Permissions.CAN_COOK&Permissions.CAN_BAKE)(ironman)# ➞ True(Permissions.CAN_COOK&Permissions.CAN_BAKE)(deadpool)# ➞ False(Permissions.CAN_COOK|Permissions.CAN_BAKE)(hulk)# ➞ False~(Permissions.CAN_COOK|Permissions.CAN_BAKE)(hulk)# ➞ True(~Permissions.CAN_COOK&Permissions.CAN_BAKE)(deadpool)# ➞ TrueDynamic permissionsUsing the@permissiondecorator, we can also define dynamic permissions that will check if the hero has a permission based on some other condition, or define a permission as a combination of other permissions.classPermissions(ezperm.PermissionEnum):CAN_COOK='CAN_COOK'CAN_BAKE='CAN_BAKE'def_has_perm(self,hero:Hero)->bool:returnself.valueinhero.permissions### ↓ NEW ↓ ###@ezperm.permissiondefis_worthy(hero:Hero)->bool:returnhero.name=='Thor'@ezperm.permissiondefis_old(hero:Hero)->bool:returnhero.age>50@ezperm.permissiondefcan_use_oven(hero:Hero)->bool:return(Permissions.CAN_COOK|Permissions.CAN_BAKE)(hero)These permissions can be used in the same way as the static ones:Permissions.is_worthy(ironman)# ➞ False(Permissions.CAN_COOK|PERMISSIONS.is_worthy)(ironman)# ➞ TrueDjango integrationInstallationpipinstallezperm[django]ezperm comes with a couple of tools to help with Django integration. Its use is entirely optional, and you can use ezperm and Django without it.First, lets update ourPermissionsandHeroclasses in our example:importezperm.djangofromdjango.dbimportmodelsfromdjango.contrib.postgres.fieldsimportArrayFieldclassPermissions(ezperm.PermissionEnum,models.TextChoices):...# same as beforeclassHero(ezperm.django.PermissionsMixin,models.Model):name=models.CharField(max_length=100)age=models.IntegerField()permissions=ArrayField(base_field=models.CharField(max_length=255,choices=Permissions.choices,),default=list,)Note, that we've inherited thePermissionsfrom Django'sTextChoicesin order to use it as achoicesargument for thepermissionsfield.
Moreover, we've added thePermissionsMixinto ourHeromodel, which overrides thehas_permsandhas_permmethod.Now lets define a view which will allow access only to worthy or old heroes:fromdjango.views.genericimportViewfromezperm.django.viewsimportPermissionRequiredMixinclassCookView(PermissionRequiredMixin,View):permission_required=Permissions.CAN_COOK|Permissions.is_worthydefget(self,request):returnHttpResponse('You can cook!')ContributingPull requests for any improvements are welcome.Poetryis used to manage dependencies.
To get started follow these steps:gitclonehttps://github.com/VojtechPetru/ezperm.gitcdezperm
poetryinstall
poetryrunpytestLinksRepository:https://github.com/VojtechPetru/ezpermIssue tracker:https://github.com/VojtechPetru/ezperm/issues.
In case of sensitive bugs (e.g. security vulnerabilities) please contact me atpetru.vojtech@gmail.comdirectly.