ezperm


Nameezperm JSON
Version 0.1.2 PyPI version JSON
download
home_pagehttps://github.com/VojtechPetru/ezperm
SummaryPermissions made easy
upload_time2024-08-13 11:05:41
maintainerNone
docs_urlNone
authorvojtech
requires_python<4.0,>=3.8
licenseMIT
keywords permissions django
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Easy permissions
Define user permissions and resource access simply and efficiently.

## Installation
```bash
pip install ezperm
```

## Usage & examples
### General case
Assume 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:
```python
import dataclasses


@dataclasses.dataclass
class Hero:
    name: str
    age: int
    permissions: 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 the `PermissionEnum` class and defining a `_has_perm`
method that will check if the hero has the permission.
#### Permission enums
```python
import ezperm

class Permissions(ezperm.PermissionEnum):
    CAN_COOK = 'CAN_COOK'
    CAN_BAKE = 'CAN_BAKE'
    
    def _has_perm(self, hero: Hero) -> bool:
        return self.value in hero.permissions
```
Now lets use our permissions in the code:
```python
# Define some heroes
ironman = 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 permission
Permissions.CAN_COOK(ironman)  # ➞ True
Permissions.CAN_COOK(deadpool)  # ➞ False
Permissions.CAN_COOK(hulk)  # ➞ False
```
It is possible to use `&` _(logical and)_, `|` _(logical or)_ or `~` _(negation)_ operators to combine permissions:
```python
(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)  # ➞ True
```

#### Dynamic permissions
Using the `@permission` decorator, 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.
```python
class Permissions(ezperm.PermissionEnum):
    CAN_COOK = 'CAN_COOK'
    CAN_BAKE = 'CAN_BAKE'
    
    def _has_perm(self, hero: Hero) -> bool:
        return self.value in hero.permissions
    
    ### ↓ NEW ↓ ###
    @ezperm.permission
    def is_worthy(hero: Hero) -> bool:
        return hero.name == 'Thor'
    
    @ezperm.permission
    def is_old(hero: Hero) -> bool:
        return hero.age > 50

    @ezperm.permission
    def can_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:
```python
Permissions.is_worthy(ironman)  # ➞ False
(Permissions.CAN_COOK | PERMISSIONS.is_worthy)(ironman)  # ➞ True
```


### Django integration
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 our `Permissions` and `Hero` classes in our example:
```python
import ezperm.django

from django.db import models
from django.contrib.postgres.fields import ArrayField


class Permissions(ezperm.PermissionEnum, models.TextChoices):
    ... # same as before


class Hero(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 the `Permissions` from Django's `TextChoices` in order to use it as a `choices` argument for the `permissions` field.
Moreover, we've added the `PermissionsMixin` to our `Hero` model, which overrides the `has_perms` and `has_perm` method.

Now lets define a view which will allow access only to worthy or old heroes:
```python
from django.views.generic import View
from ezperm.django.views import PermissionRequiredMixin


class CookView(PermissionRequiredMixin, View):
    permission_required = Permissions.is_worthy | Permissions.is_old
    
    def get(self, request):
        return HttpResponse('You can cook!')
```


## Contributing
Pull requests for any improvements are welcome.

[Poetry](https://github.com/sdispater/poetry) is used to manage dependencies.
To get started follow these steps:

```shell
git clone https://github.com/VojtechPetru/ezperm.git
cd ezperm
poetry install
poetry run pytest
```

## Links
- Repository: https://github.com/VojtechPetru/ezperm
- Issue tracker: https://github.com/VojtechPetru/ezperm/issues. 
In case of sensitive bugs (e.g. security vulnerabilities) please contact me at _petru.vojtech@gmail.com_ directly.



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/VojtechPetru/ezperm",
    "name": "ezperm",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.8",
    "maintainer_email": null,
    "keywords": "permissions, django",
    "author": "vojtech",
    "author_email": "petru.vojtech@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/ee/48/9b04e5a51fd672cf27f455db1076550bbb3365a78d74bfa0c7b19cb1edb4/ezperm-0.1.2.tar.gz",
    "platform": null,
    "description": "# Easy permissions\nDefine user permissions and resource access simply and efficiently.\n\n## Installation\n```bash\npip install ezperm\n```\n\n## Usage & examples\n### General case\nAssume we are in charge of a superhero team. We have a list of heroes, and we want to define permissions for them.\nOur hero model might look like this:\n```python\nimport dataclasses\n\n\n@dataclasses.dataclass\nclass Hero:\n    name: str\n    age: int\n    permissions: list['Permissions']\n```\nAfter a while of working with our heroes, we realize that some of them are terrible cooks. We want to define a permission\nthat will allow only some of them to cook or bake. \n\nThis can be done by extending the `PermissionEnum` class and defining a `_has_perm`\nmethod that will check if the hero has the permission.\n#### Permission enums\n```python\nimport ezperm\n\nclass Permissions(ezperm.PermissionEnum):\n    CAN_COOK = 'CAN_COOK'\n    CAN_BAKE = 'CAN_BAKE'\n    \n    def _has_perm(self, hero: Hero) -> bool:\n        return self.value in hero.permissions\n```\nNow lets use our permissions in the code:\n```python\n# Define some heroes\nironman = Hero('Ironman', 45, [Permissions.CAN_COOK, Permissions.CAN_BAKE])\ndeadpool = Hero('Deadpool', 30, [Permissions.CAN_BAKE])\nhulk = Hero('Hulk', 55, [])\n\n# Check if the hero has a permission\nPermissions.CAN_COOK(ironman)  # \u279e True\nPermissions.CAN_COOK(deadpool)  # \u279e False\nPermissions.CAN_COOK(hulk)  # \u279e False\n```\nIt is possible to use `&` _(logical and)_, `|` _(logical or)_ or `~` _(negation)_ operators to combine permissions:\n```python\n(Permissions.CAN_COOK & Permissions.CAN_BAKE)(ironman)  # \u279e True\n(Permissions.CAN_COOK & Permissions.CAN_BAKE)(deadpool)  # \u279e False\n(Permissions.CAN_COOK | Permissions.CAN_BAKE)(hulk)  # \u279e False\n~(Permissions.CAN_COOK | Permissions.CAN_BAKE)(hulk)  # \u279e True\n(~Permissions.CAN_COOK & Permissions.CAN_BAKE)(deadpool)  # \u279e True\n```\n\n#### Dynamic permissions\nUsing the `@permission` decorator, 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.\n```python\nclass Permissions(ezperm.PermissionEnum):\n    CAN_COOK = 'CAN_COOK'\n    CAN_BAKE = 'CAN_BAKE'\n    \n    def _has_perm(self, hero: Hero) -> bool:\n        return self.value in hero.permissions\n    \n    ### \u2193 NEW \u2193 ###\n    @ezperm.permission\n    def is_worthy(hero: Hero) -> bool:\n        return hero.name == 'Thor'\n    \n    @ezperm.permission\n    def is_old(hero: Hero) -> bool:\n        return hero.age > 50\n\n    @ezperm.permission\n    def can_use_oven(hero: Hero) -> bool:\n        return (Permissions.CAN_COOK | Permissions.CAN_BAKE)(hero)\n```\nThese permissions can be used in the same way as the static ones:\n```python\nPermissions.is_worthy(ironman)  # \u279e False\n(Permissions.CAN_COOK | PERMISSIONS.is_worthy)(ironman)  # \u279e True\n```\n\n\n### Django integration\nezperm 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.\n\nFirst, lets update our `Permissions` and `Hero` classes in our example:\n```python\nimport ezperm.django\n\nfrom django.db import models\nfrom django.contrib.postgres.fields import ArrayField\n\n\nclass Permissions(ezperm.PermissionEnum, models.TextChoices):\n    ... # same as before\n\n\nclass Hero(ezperm.django.PermissionsMixin, models.Model):\n    name = models.CharField(max_length=100)\n    age = models.IntegerField()\n    permissions = ArrayField(\n        base_field=models.CharField(\n            max_length=255,\n            choices=Permissions.choices,\n        ),\n        default=list,\n    )\n```\nNote, that we've inherited the `Permissions` from Django's `TextChoices` in order to use it as a `choices` argument for the `permissions` field.\nMoreover, we've added the `PermissionsMixin` to our `Hero` model, which overrides the `has_perms` and `has_perm` method.\n\nNow lets define a view which will allow access only to worthy or old heroes:\n```python\nfrom django.views.generic import View\nfrom ezperm.django.views import PermissionRequiredMixin\n\n\nclass CookView(PermissionRequiredMixin, View):\n    permission_required = Permissions.is_worthy | Permissions.is_old\n    \n    def get(self, request):\n        return HttpResponse('You can cook!')\n```\n\n\n## Contributing\nPull requests for any improvements are welcome.\n\n[Poetry](https://github.com/sdispater/poetry) is used to manage dependencies.\nTo get started follow these steps:\n\n```shell\ngit clone https://github.com/VojtechPetru/ezperm.git\ncd ezperm\npoetry install\npoetry run pytest\n```\n\n## Links\n- Repository: https://github.com/VojtechPetru/ezperm\n- Issue tracker: https://github.com/VojtechPetru/ezperm/issues. \nIn case of sensitive bugs (e.g. security vulnerabilities) please contact me at _petru.vojtech@gmail.com_ directly.\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Permissions made easy",
    "version": "0.1.2",
    "project_urls": {
        "Homepage": "https://github.com/VojtechPetru/ezperm",
        "Repository": "https://github.com/VojtechPetru/ezperm"
    },
    "split_keywords": [
        "permissions",
        " django"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "57a4ea7a58a5e5c3e33460ba5eea48225fefa2324eae70dc3da23234d5e7bd5c",
                "md5": "dd09aa07eeaa81449a79afe582e67d2b",
                "sha256": "26581466195891d830519b9c6a719c3d295c53618a3eef68d7277a0a6e50edab"
            },
            "downloads": -1,
            "filename": "ezperm-0.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "dd09aa07eeaa81449a79afe582e67d2b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.8",
            "size": 6855,
            "upload_time": "2024-08-13T11:05:39",
            "upload_time_iso_8601": "2024-08-13T11:05:39.894266Z",
            "url": "https://files.pythonhosted.org/packages/57/a4/ea7a58a5e5c3e33460ba5eea48225fefa2324eae70dc3da23234d5e7bd5c/ezperm-0.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ee489b04e5a51fd672cf27f455db1076550bbb3365a78d74bfa0c7b19cb1edb4",
                "md5": "9eea6d6d5c521cc85ac9561e86c42802",
                "sha256": "e69524b91f11c32a949110b2c9b1abc01ff1f265e91e5aa625c0a62b1b5947bc"
            },
            "downloads": -1,
            "filename": "ezperm-0.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "9eea6d6d5c521cc85ac9561e86c42802",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.8",
            "size": 5066,
            "upload_time": "2024-08-13T11:05:41",
            "upload_time_iso_8601": "2024-08-13T11:05:41.449974Z",
            "url": "https://files.pythonhosted.org/packages/ee/48/9b04e5a51fd672cf27f455db1076550bbb3365a78d74bfa0c7b19cb1edb4/ezperm-0.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-08-13 11:05:41",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "VojtechPetru",
    "github_project": "ezperm",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "ezperm"
}
        
Elapsed time: 0.31242s