{ "info": { "author": "Zhipeng Liu", "author_email": "hustlzp@qq.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 2.7", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "Permission\n==========\n\n|Latest Version| |The MIT License|\n\nSimple and flexible permission control for Flask app.\n\nFeatures\n--------\n\n- **Simple**: all you need to do is subclassing ``Rule`` and\n ``Permission`` class.\n- **Flexible**: support rule inheritance and bitwise operations(\\ ``&``\n and ``|``) to build your own rules.\n\nInstallation\n------------\n\n::\n\n $ pip install permission\n\nRule\n----\n\n``Rule`` has 3 methods which can be overrided:\n\n- base(): define base rule.\n- check(): determine whether this rule should be passed or not.\n- deny(): will be executed when ``check()`` failed.\n\nYou should always override ``check()`` and ``deny()`` while overriding\n``base()`` as needed.\n\nPermission\n----------\n\n``Permission`` has 1 method which can be overrided:\n\n- rule(): define rule needed by this permission\n\nYou should always override ``rule()``.\n\n``Permission`` has 2 instance methods you can use in codes:\n\n- check(): call this to check rule of this permission\n- deny(): call this to execute codes when ``check()`` failed\n\nUsage\n-----\n\nFirst you need to define your own rules by subclassing ``Rule`` then\noverride ``check()`` and ``deny()``:\n\n.. code:: py\n\n # rules.py\n from flask import session, flash, redirect, url_for\n from permission import Rule\n\n\n class UserRule(Rule):\n def check(self):\n \"\"\"Check if there is a user signed in.\"\"\"\n return 'user_id' in session\n\n def deny(self):\n \"\"\"When no user signed in, redirect to signin page.\"\"\"\n flash('Sign in first.')\n return redirect(url_for('signin'))\n\nThen you define permissions by subclassing ``Permission`` and override\n``rule()``:\n\n.. code:: py\n\n # permissions.py\n from permission import Permission\n from .rules import UserRule\n\n\n class UserPermission(Permission):\n \"\"\"Only signin user has this permission.\"\"\"\n def rule(self):\n return UserRule()\n\nThere are 4 ways to use the ``UserPermission`` defined above:\n\n**1. Use as view decorator**\n\n.. code:: py\n\n from .permissions import UserPermission\n\n\n @app.route('/settings')\n @UserPermission()\n def settings():\n \"\"\"User settings page, only accessable for sign-in user.\"\"\"\n return render_template('settings.html')\n\n**2. Use in view codes**\n\n.. code:: py\n\n from .permissions import UserPermission\n\n\n @app.route('/settions')\n def settings():\n permission = UserPermission()\n if not permission.check()\n return permission.deny()\n return render_template('settings.html')\n\n**3. Use in view codes (using ``with`` statement)**\n\n.. code:: py\n\n from .permissions import UserPermission\n\n\n @app.route('/settions')\n def settings():\n with UserPermission():\n return render_template('settings.html')\n\n**Note**: if you don't raise an exception when the permission check\nfailed (in other words, a rule's ``deny()`` will be called),\n``PermissionDeniedException`` will be raised in order to stop the\nexecution of the with-body codes. By the way, you can import this\nexception as needed:\n\n.. code:: py\n\n from permission import PermissionDeniedException\n\n**4. Use in Jinja2 templates**\n\nFirst you need to inject your defined permissions to template context:\n\n.. code:: py\n\n from . import permissions\n\n\n @app.context_processor\n def inject_vars():\n return dict(\n permissions=permissions\n )\n\nthen in templates:\n\n.. code:: html\n\n {% if permissions.UserPermission().check() %}\n New\n {% endif %}\n\nRule Inheritance\n----------------\n\nNeed to say, inheritance here is not the same thing as Python class\ninheritance, it's just means you can use RuleA as the base rule of\nRuleB.\n\nWe achieve this by overriding ``base()``.\n\nLet's say an administrator user should always be a user:\n\n.. code:: py\n\n # rules.py\n from flask import session, abort, flash, redirect, url_for\n from permission import Rule\n\n\n class UserRule(Rule):\n def check(self):\n return 'user_id' in session\n\n def deny(self):\n flash('Sign in first.')\n return redirect(url_for('signin'))\n\n\n class AdminRule(Rule):\n def base(self):\n return UserRule()\n\n def check(self):\n user_id = int(session['user_id'])\n user = User.query.filter(User.id == user_id).first()\n return user and user.is_admin\n\n def deny(self):\n abort(403)\n\nRule Bitwise Operations\n-----------------------\n\n- ``RuleA & RuleB`` means it will be passed when both RuleA and RuleB\n are passed.\n- ``RuleA | RuleB`` means it will be passed either RuleA or RuleB is\n passed.\n\nLet's say we need to build a forum with Flask. Only the topic creator\nand administrator user can edit a topic:\n\nFirst define rules:\n\n.. code:: py\n\n # rules.py\n from flask import session, abort, flash, redirect, url_for\n from permission import Rule\n from .models import User, Topic\n\n\n class UserRule(Rule):\n def check(self):\n \"\"\"Check if there is a user signed in.\"\"\"\n return 'user_id' in session\n\n def deny(self):\n \"\"\"When no user signed in, redirect to signin page.\"\"\"\n flash('Sign in first.')\n return redirect(url_for('signin'))\n\n\n class AdminRule(Rule):\n def base(self):\n return UserRule()\n\n def check(self):\n user_id = int(session['user_id'])\n user = User.query.filter(User.id == user_id).first()\n return user and user.is_admin\n\n def deny(self):\n abort(403)\n\n\n class TopicCreatorRule(Rule):\n def __init__(self, topic):\n self.topic = topic\n super(TopicCreatorRule, self).__init__()\n\n def base(self):\n return UserRule()\n\n def check(self):\n return topic.user_id == session['user_id']\n\n def deny(self):\n abort(403)\n\nthen define permissions:\n\n.. code:: py\n\n # permissions.py\n from permission import Permission\n\n\n class TopicAdminPermission(Permission):\n def __init__(self, topic):\n self.topic = topic\n super(TopicAdminPermission, self).__init__()\n\n def rule(self):\n return AdminRule() | TopicCreatorRule(self.topic)\n\nso we can use ``TopicAdminPermission`` in ``edit_topic`` view:\n\n.. code:: py\n\n from .permissions import TopicAdminPermission\n\n\n @app.route('topic//edit')\n def edit_topic(topic_id):\n topic = Topic.query.get_or_404(topic_id)\n permission = TopicAdminPermission(topic)\n if not permission.check():\n return permission.deny()\n ...\n\nLicense\n-------\n\nMIT\n\n.. |Latest Version| image:: http://img.shields.io/pypi/v/permission.svg\n :target: https://pypi.python.org/pypi/permission\n.. |The MIT License| image:: http://img.shields.io/badge/license-MIT-blue.svg\n :target: https://github.com/hustlzp/permission/blob/master/LICENSE", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/hustlzp/permission", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "permission", "package_url": "https://pypi.org/project/permission/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/permission/", "project_urls": { "Homepage": "https://github.com/hustlzp/permission" }, "release_url": "https://pypi.org/project/permission/0.4.1/", "requires_dist": null, "requires_python": "", "summary": "Simple and flexible permission control for Flask app.", "version": "0.4.1" }, "last_serial": 1812501, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "4c8683db4234490acbabfd0988a32d9c", "sha256": "065f3d925630d3593f291fcb38c0ab09454d43df709add47f5c8b51ee549ff16" }, "downloads": -1, "filename": "permission-0.1.0.tar.gz", "has_sig": false, "md5_digest": "4c8683db4234490acbabfd0988a32d9c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2705, "upload_time": "2014-09-10T09:42:55", "url": "https://files.pythonhosted.org/packages/84/86/2442e66c770a0daf4860ceb5f0a23689096f41903f57587324e936f7bc22/permission-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "15844b43bce70f92558d59b347449a59", "sha256": "44e7f333b54f82479e3638a5e8d65ba98c5bd4b93a19bef1458b6b52e27fdcd9" }, "downloads": -1, "filename": "permission-0.1.1.tar.gz", "has_sig": false, "md5_digest": "15844b43bce70f92558d59b347449a59", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2811, "upload_time": "2014-09-10T09:54:41", "url": "https://files.pythonhosted.org/packages/95/2b/3c9ed45f0a32e1a5a0168c95765b9b10edc0cf70b82824f17c24a1bd9dd7/permission-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "932e256594e8041b65d2b5142dd37d8b", "sha256": "8f907eb2030233c3481c6149e9ea1a278b0a3ae8bf5c894beb521425ac7ee9e9" }, "downloads": -1, "filename": "permission-0.1.2.tar.gz", "has_sig": false, "md5_digest": "932e256594e8041b65d2b5142dd37d8b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4576, "upload_time": "2014-09-12T09:35:06", "url": "https://files.pythonhosted.org/packages/a6/0e/176d5afe36b53de12069222caad61e08b9800e04cd2e1c2170f76f86e973/permission-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "caee8bfeeac032caacfd17146d99ea67", "sha256": "78e12b2d7f5cf9b53c079d8cd8a918636dbbee8fbd8573f6da0064b67a634ba4" }, "downloads": -1, "filename": "permission-0.1.3.tar.gz", "has_sig": false, "md5_digest": "caee8bfeeac032caacfd17146d99ea67", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4561, "upload_time": "2014-09-12T10:23:43", "url": "https://files.pythonhosted.org/packages/a5/ee/5d230ba0347c895c3a316e6c1d9193810a5b567e76651db021793b827827/permission-0.1.3.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "183000b4f9f1c55f6c1f8ba393616000", "sha256": "c4ccc34c4a5fdac9f1b5c007824d0524ddbb06c56bbf6c5cbc0825820a91a5c3" }, "downloads": -1, "filename": "permission-0.2.0.tar.gz", "has_sig": false, "md5_digest": "183000b4f9f1c55f6c1f8ba393616000", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4457, "upload_time": "2014-11-18T01:30:21", "url": "https://files.pythonhosted.org/packages/dd/0f/44775056ade703f2d15d61550b6cc67d147bb29e1b5cf405985744945db8/permission-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "6d5a94c9e6cedef88002794001b85832", "sha256": "9c4ef7525ad16e9b9b7e6ca1b0aac8120d594577b8594bc8ec5c30065f34b26f" }, "downloads": -1, "filename": "permission-0.2.1.tar.gz", "has_sig": false, "md5_digest": "6d5a94c9e6cedef88002794001b85832", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4558, "upload_time": "2014-11-25T11:25:40", "url": "https://files.pythonhosted.org/packages/ec/92/73b91e72a083ede34f4138706e11cc55a9f427989dd43ec63aa82f94f9f6/permission-0.2.1.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "4a51db14842f7a98a3620d9157ec81cc", "sha256": "5f62f03f0ee685f15a8fb0301a7ecb7e9a7077e47397099b0d6afde149aaf70f" }, "downloads": -1, "filename": "permission-0.3.0.tar.gz", "has_sig": false, "md5_digest": "4a51db14842f7a98a3620d9157ec81cc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4558, "upload_time": "2015-03-14T09:34:32", "url": "https://files.pythonhosted.org/packages/c5/6a/e307967e0e896da9b13a6f08de4fba89264d426b8014901f60520cd34ea5/permission-0.3.0.tar.gz" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "0971700ce0f7ec5f22a5ecdf369b95b8", "sha256": "fce5c3e2946ab8fdcae936a1c1e1d6788a0496e37a069f610c70e27c963852c4" }, "downloads": -1, "filename": "permission-0.4.0.tar.gz", "has_sig": false, "md5_digest": "0971700ce0f7ec5f22a5ecdf369b95b8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4903, "upload_time": "2015-11-11T16:18:18", "url": "https://files.pythonhosted.org/packages/86/2c/9552f25a86ff341896a743b371df48e39897d91dc9b065ccd281def4ffff/permission-0.4.0.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "a8ef00354a25f6b205f30d4f8e817db9", "sha256": "f2cd126123fb9f3f4f80a9640cf3aea688b06701525e02c25aa17221c0d871c8" }, "downloads": -1, "filename": "permission-0.4.1.tar.gz", "has_sig": false, "md5_digest": "a8ef00354a25f6b205f30d4f8e817db9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5056, "upload_time": "2015-11-12T03:06:43", "url": "https://files.pythonhosted.org/packages/87/a1/dbcbaff2fccd3dd905f916a1fee9df8a9d4358ee475bbb0a8cfd53fc36ab/permission-0.4.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a8ef00354a25f6b205f30d4f8e817db9", "sha256": "f2cd126123fb9f3f4f80a9640cf3aea688b06701525e02c25aa17221c0d871c8" }, "downloads": -1, "filename": "permission-0.4.1.tar.gz", "has_sig": false, "md5_digest": "a8ef00354a25f6b205f30d4f8e817db9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5056, "upload_time": "2015-11-12T03:06:43", "url": "https://files.pythonhosted.org/packages/87/a1/dbcbaff2fccd3dd905f916a1fee9df8a9d4358ee475bbb0a8cfd53fc36ab/permission-0.4.1.tar.gz" } ] }