{ "info": { "author": "Dave O'Connor", "author_email": "github@dead-pixels.org", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "Graphene Field Permission\n=========================\n\nA package to add field-level permissions for `Graphene\nPython `__.\n\nCurrently only supports Django/\\ `Graphene\nDjango `__ but would\nwelcome pull requests adding support for other ORMs.\n\nUsage\n-----\n\nQueries\n~~~~~~~\n\nOn schema nodes add the decorator ``@has_field_access`` to the resolve\nfor any field that you want checked.\n\nUsage example in schema files:\n\n.. code:: python\n\n from graphene_field_permission.decorators import has_field_access\n\n class GroupNode(DjangoObjectType):\n @has_field_access('permission1')\n def resolve_group_name(self, info):\n return self.name\n\n class Meta:\n model = Group\n ...\n\nExample showing checking for one of multiple (unlimited) permissions:\n\n.. code:: python\n\n from graphene_field_permission.decorators import has_field_access\n\n class GroupNode(DjangoObjectType):\n @has_field_access('permission1', 'permission2')\n def resolve_group_description(self, info):\n return self.description\n\nExample showing checking for one of multiple permissions under a group,\nfor cases where permissions differ by group id:\n\n.. code:: python\n\n from graphene_field_permission.decorators import has_field_access\n\n class GroupNode(DjangoObjectType):\n @has_field_access('permission1', 'permission2', filter_field='group_id')\n def resolve_group_text(self, info):\n return self.text\n\nfilter\\_field\n^^^^^^^^^^^^^\n\nA ``filter_field`` value of 'group\\_id' in the above example will look\nat the GroupNode group\\_id field. Add ``.`` separators for related\nobjects.\n\n``filter_field`` processing will traverse related objects as necessary\nto reduce the number of queries.\n\nIt's recommended to try and reduce these as much as possible. e.g. using\ngroup.division.corporation\\_id instead of group.division.corporation.id\n\n.. code:: python\n\n @has_field_access('permission1', 'permission2', filter_field='group.division.corporation_id')\n\nMutations\n~~~~~~~~~\n\nAdd ``check_field_access()`` call for the permission you want to confirm\n- one check per mutation will work. Raises PermissionError if no match\nfound. Permission arguments are logical OR.\n\n.. code:: python\n\n from graphene_field_permission import check_field_access\n\n class ModifyGroup(graphene.Mutation):\n # Normal mutation setup here...\n\n def mutate(self, info, id, field_1_data, field_2_data):\n d = ORM.objects.find(pk=id)\n d.field_1 = field_1_data\n # checking of permissions:\n try:\n check_field_access('permission1', info_context=info.context)\n d.protected_field = field_2_data\n except PermissionError as exc1:\n raise Exception from exc1 \n d.save()\n\n\nGrouped permissions\n\n.. code:: python\n\n from graphene_field_permission import check_field_access\n\n class ModifyGroup(graphene.Mutation):\n # Normal mutation setup here...\n\n def mutate(self, info, id, field_1_data, field_2_data):\n fd = ModelName.objects.find(pk=id)\n fd.field_1 = field_1_data\n # checking of permissions:\n try:\n # check for user having permission1 OR permission2\n check_field_access(\n 'permission1',\n 'permission2',\n filter_field='group.division.corporation_id',\n filter_data=fd,\n info_context=info.context, \n )\n fd.protected_field = field_2_data\n except PermissionError as exc1:\n raise Exception from exc1 \n fd.save()\n\n\n``filter_field`` along with ``filter_data`` works the same way as\n``filter_field`` does in queries, with ``filter_data`` providing the ORM\nobject to be traversed.\n\nMore than one ``check_field_access()`` call can be made and retrieved\npermissions will be retained between the calls.\n\nSample Result in GraphQL output from query decorator:\n-----------------------------------------------------\n\n.. code:: javascript\n\n {\n \"errors\": [\n {\n \"message\": \"No access for user on field 'group_name'\",\n \"locations\": [\n {\n \"line\": 7,\n \"column\": 9\n }\n ],\n \"path\": [\n \"group\",\n \"edges\",\n 0,\n \"node\",\n \"groupName\"\n ]\n }\n ],\n \"data\": {\n \"group\": {\n \"edges\": [\n {\n \"node\": null\n }\n ]\n }\n }\n }\n\nUsage notes:\n~~~~~~~~~~~~\n\n1. An exception is thrown should a user attempt to access a field for\n which they don't have access. the reason for this is that\n graphene-django doesn't allow returning ``None`` for fields which\n aren't set as nullable so this is the best way of proceeding and\n follows that convention throughout. That makes it necessary to have\n your graphql queries fine grained enough to not call those fields in\n the first place.\n\n 1. Client side checking of permissions is recommended in order to\n limit the field's accessed in the query in the first place.\n\nInstallation\n------------\n\n::\n\n pip install graphene-field-permission\n\nSetup\n-----\n\n1. Set up graphene and graphene django following their own instructions.\n2. Create a module and method that will return permissions allowed for\n the user as shown below. By default lists and dicts containing lists\n are supported.\n3. Update settings.py to match the instructions below.\n\nExample permissions resolution\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nStandard:\n\n.. code:: python\n\n def get_user_permissions(user):\n # query database to determine the passed in user's permissions\n return ['permission1', 'permission2', 'permission3']\n\nOr grouped:\n\n.. code:: python\n\n def get_user_permissions(user):\n # query database to determine the passed in user's permissions\n return {\n 'group-id-123': ['permission1', 'permission2', 'permission3'],\n 'group-id-456': ['permission1', 'permission3', 'permission5'],\n }\n\nUser Permission Call Information\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n1. These get called once per graphql query call.\n2. It's recommended to use the logs to try to minimise the number of\n queries generated by this function. Ideally it would be best to do it\n in a single query.\n3. It's recommended to use Django ORM's ``select_related`` on queries\n where necessary in order to minimise the number of queries.\n\nSettings\n~~~~~~~~\n\nWith the above method at app/helpers/user\\_permissions.py (for example)\nupdate settings.py to add:\n\n.. code:: python\n\n GRAPHENE_FIELD_PERMISSION = {\n 'SRC_MODULE': 'app.helpers.user_permissions',\n 'SRC_METHOD': 'get_user_permissions',\n }\n\nAlso update the main graphene settings to add the middleware.\n\n.. code:: python\n\n GRAPHENE = {\n 'MIDDLEWARE': [\n 'graphene_field_permission.permissions.PermissionsMiddleware'\n ]\n }\n\nFuture updates, design notes\n----------------------------\n\n1. I don't plan to develop this a whole lot further. It has scratched my\n itch for now.\n2. I tried about four different ways to do this so resolve\\_field wasn't\n necessary, but found this to be the best balance of making it\n schema-definable and performant. I'm open to pull requests if someone\n can think of a better way.\n3. This currently only supports Graphene under Django. I'm open to\n others adding support for other graphene-python projects if they want\n to submit pull requests.\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/daveoconnor/graphene-field-permission", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "graphene-field-permission", "package_url": "https://pypi.org/project/graphene-field-permission/", "platform": "", "project_url": "https://pypi.org/project/graphene-field-permission/", "project_urls": { "Homepage": "https://github.com/daveoconnor/graphene-field-permission" }, "release_url": "https://pypi.org/project/graphene-field-permission/0.0.7/", "requires_dist": null, "requires_python": "", "summary": "A package to add field permission support for Graphene", "version": "0.0.7" }, "last_serial": 5339080, "releases": { "0.0.2": [ { "comment_text": "", "digests": { "md5": "ea3a82d0881c687de85845b268e0e85a", "sha256": "c59e49b6f78473500c3b4fc352f1923c989618a1073011fa5ebab09d14a6441d" }, "downloads": -1, "filename": "graphene_field_permission-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "ea3a82d0881c687de85845b268e0e85a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6631, "upload_time": "2019-02-23T03:56:48", "url": "https://files.pythonhosted.org/packages/a9/88/2cd24ab8ea159833739b1e210a68adfe5bdb164e88701a69c83016336b79/graphene_field_permission-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7be1eb51e909d4136d189e1715e7cd57", "sha256": "73a90cbc0b670b1ac69402ad853ba1dc0a5c33b8ec39ffb5585fd6680171d0dd" }, "downloads": -1, "filename": "graphene-field-permission-0.0.2.tar.gz", "has_sig": false, "md5_digest": "7be1eb51e909d4136d189e1715e7cd57", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3547, "upload_time": "2019-02-23T03:56:50", "url": "https://files.pythonhosted.org/packages/ec/29/0eefc1ca021c0291372f8772e0c07ff5d870e9c3c27fa6eed2e4d77f6278/graphene-field-permission-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "d969c82234b9f0137649c23b31593f48", "sha256": "25da9a41d023b5953c238f56fc808bc4bf24d828c7831c5aea52a17d0f62f6a5" }, "downloads": -1, "filename": "graphene_field_permission-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "d969c82234b9f0137649c23b31593f48", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7906, "upload_time": "2019-03-01T21:46:47", "url": "https://files.pythonhosted.org/packages/81/4f/3695bf9b8e70bc706f58c62658954ac025db3fe793c0e91fbdf1ae4559ac/graphene_field_permission-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f262ed70606ae0b82762ba7cdbfaf068", "sha256": "8392d745dff82ed81191382115457e4301c710714efb99f0bcf1e9b55606f9d3" }, "downloads": -1, "filename": "graphene-field-permission-0.0.3.tar.gz", "has_sig": false, "md5_digest": "f262ed70606ae0b82762ba7cdbfaf068", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4468, "upload_time": "2019-03-01T21:46:49", "url": "https://files.pythonhosted.org/packages/3c/89/cf6d328d0c96dcda035dbdbebff6c2b3bd45399f9ff17810d6bbda6cac18/graphene-field-permission-0.0.3.tar.gz" } ], "0.0.5": [ { "comment_text": "", "digests": { "md5": "9f2777da81101fbebd89cd1820664ef7", "sha256": "9698ccccba337948a29a73f43ef028a90e8c3b4d249b4696fcf6ea37124c2157" }, "downloads": -1, "filename": "graphene_field_permission-0.0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "9f2777da81101fbebd89cd1820664ef7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8222, "upload_time": "2019-03-11T19:20:53", "url": "https://files.pythonhosted.org/packages/d5/2e/2b47e0932715310a3b26c72efbbd6ce59c938803ccf34d0d321270f6bb12/graphene_field_permission-0.0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "75bdd674e1bfb1caed5d46d094e9ac11", "sha256": "6fd5ffced2204057ae4c218c5244b3c42af013d7680638c76a0a7e29e888b420" }, "downloads": -1, "filename": "graphene-field-permission-0.0.5.tar.gz", "has_sig": false, "md5_digest": "75bdd674e1bfb1caed5d46d094e9ac11", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4897, "upload_time": "2019-03-11T19:20:56", "url": "https://files.pythonhosted.org/packages/7c/b2/a32f4915bc289bb6d270fb40b347a6538f01f60dda01b9fcb244e2bdb424/graphene-field-permission-0.0.5.tar.gz" } ], "0.0.6": [ { "comment_text": "", "digests": { "md5": "11c22b81dd449bdb77334f834633e6a6", "sha256": "8fe68e2025e4ff931861a8797453a488ef9c255b39571328ed6e420ff9824cb7" }, "downloads": -1, "filename": "graphene_field_permission-0.0.6-py3-none-any.whl", "has_sig": false, "md5_digest": "11c22b81dd449bdb77334f834633e6a6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 10445, "upload_time": "2019-04-12T03:33:00", "url": "https://files.pythonhosted.org/packages/ff/11/1093a2daa9e8170734dc43f732325a3e616bb515244178064727aec7acc3/graphene_field_permission-0.0.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2f1b885137d2bca65230c200a7f182ae", "sha256": "f05c63e68ef04368fb990cdbad0e8365d9cc8281dc85cdaf2a41d3a14230d8bd" }, "downloads": -1, "filename": "graphene-field-permission-0.0.6.tar.gz", "has_sig": false, "md5_digest": "2f1b885137d2bca65230c200a7f182ae", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6236, "upload_time": "2019-04-12T03:33:04", "url": "https://files.pythonhosted.org/packages/6d/a5/d4cdbb4c64e58e23b2f1eb3ade6a72215c21d976856bc6a4f8aae60f6790/graphene-field-permission-0.0.6.tar.gz" } ], "0.0.7": [ { "comment_text": "", "digests": { "md5": "d92ed38aac863f4234abb3e1ed0829a7", "sha256": "af9543263a7adeee6e2a3d69887ceb946220ec4a14aed36715a8b3c458b0efe8" }, "downloads": -1, "filename": "graphene_field_permission-0.0.7-py3-none-any.whl", "has_sig": false, "md5_digest": "d92ed38aac863f4234abb3e1ed0829a7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 10481, "upload_time": "2019-05-30T19:09:12", "url": "https://files.pythonhosted.org/packages/e1/0f/d7eecc2e2248e2934f83f720a3b94655a5e1d2ebb0edf79ad9477ff3fe2d/graphene_field_permission-0.0.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "266a25dfa51401437d91a4307b8f7353", "sha256": "abd30796bbe7ac03814df29d58236a86352d8ae0d37be93c62aa23a689ebe8c6" }, "downloads": -1, "filename": "graphene-field-permission-0.0.7.tar.gz", "has_sig": false, "md5_digest": "266a25dfa51401437d91a4307b8f7353", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6268, "upload_time": "2019-05-30T19:09:14", "url": "https://files.pythonhosted.org/packages/4c/3a/139974110ec88d755c17933fa52aff7d62521687d424d7a5d41c203808dc/graphene-field-permission-0.0.7.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d92ed38aac863f4234abb3e1ed0829a7", "sha256": "af9543263a7adeee6e2a3d69887ceb946220ec4a14aed36715a8b3c458b0efe8" }, "downloads": -1, "filename": "graphene_field_permission-0.0.7-py3-none-any.whl", "has_sig": false, "md5_digest": "d92ed38aac863f4234abb3e1ed0829a7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 10481, "upload_time": "2019-05-30T19:09:12", "url": "https://files.pythonhosted.org/packages/e1/0f/d7eecc2e2248e2934f83f720a3b94655a5e1d2ebb0edf79ad9477ff3fe2d/graphene_field_permission-0.0.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "266a25dfa51401437d91a4307b8f7353", "sha256": "abd30796bbe7ac03814df29d58236a86352d8ae0d37be93c62aa23a689ebe8c6" }, "downloads": -1, "filename": "graphene-field-permission-0.0.7.tar.gz", "has_sig": false, "md5_digest": "266a25dfa51401437d91a4307b8f7353", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6268, "upload_time": "2019-05-30T19:09:14", "url": "https://files.pythonhosted.org/packages/4c/3a/139974110ec88d755c17933fa52aff7d62521687d424d7a5d41c203808dc/graphene-field-permission-0.0.7.tar.gz" } ] }