Skip to content

Django permissions required for Nodes, Mutations and Connections #301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from

Conversation

carlosmart626
Copy link

This PR adds support to required Django permissions at Nodes, Mutations and Connections.

Example Node:

    from graphene_django.types import DjangoObjectType
    from graphene_django.auth import node_require_permission
    from .models import Reporter

    class ReporterType(DjangoObjectType):

        class Meta:
            model = Reporter
            interfaces = (Node, )

        @classmethod
        @node_require_permission(permissions=('can_view_report', 'can_edit_foo', ))
        def get_node(cls, info, id):
            return super(ReporterType, cls).get_node(info, id)

Example Mutation:

    from rest_framework import serializers
    from graphene_django.types import DjangoObjectType
    from graphene_django.auth import node_require_permission
    from graphene_django.rest_framework.mutation import SerializerMutation
    from .models import Reporter


    class ReporterSerializer(serializers.ModelSerializer):
        class Meta:
            model = Reporter
            fields = '__all__'


    class MyMutation(SerializerMutation):
        class Meta:
            serializer_class = ReporterSerializer

        @classmethod
        @mutation_require_permission(permissions=('can_view_foo', 'can_edit_foo', ))
        def mutate_and_get_payload(cls, root, info, **input):
            return super(MyMutation, cls).mutate_and_get_payload(root, info, **input)

Example Connection:

    import graphene
    from graphene_django.fields import DjangoConnectionField
    from graphene_django.auth import connection_require_permission, node_require_permission
    from graphene_django.types import DjangoObjectType
    from .models import Reporter

    class ReporterType(DjangoObjectType):

        class Meta:
            model = Reporter
            interfaces = (Node, )

        @classmethod
        @node_require_permission(permissions=('can_view_report', 'can_edit_foo', ))
        def get_node(cls, info, id):
            return super(ReporterType, cls).get_node(info, id)

    class MyAuthDjangoConnectionField(DjangoConnectionField):

        @classmethod
        @connection_require_permission(permissions=('can_view_foo', ))
        def connection_resolver(cls, resolver, connection, default_manager, max_limit,
                                enforce_first_or_last, root, info, **args):
            return super(MyAuthDjangoConnectionField, cls).connection_resolver(
                resolver, connection, default_manager, max_limit,
                enforce_first_or_last, root, info, **args)

    class Query(graphene.ObjectType):
        all_reporters = MyAuthDjangoConnectionField(ReporterType)

@coveralls
Copy link

coveralls commented Oct 26, 2017

Coverage Status

Coverage increased (+0.4%) to 93.36% when pulling 0477c1a on CarlosMart626:master into 2600f0f on graphql-python:master.

@coveralls
Copy link

coveralls commented Oct 26, 2017

Coverage Status

Coverage increased (+0.4%) to 93.36% when pulling 0477c1a on CarlosMart626:master into 2600f0f on graphql-python:master.

@helpse
Copy link

helpse commented Mar 7, 2018

Looks nice!

@helpse
Copy link

helpse commented Mar 11, 2018

Hey @carlosmart626. Will this PR ever be approved?
Looks like a nice approach.
I have also worked on a simplified version, based on Django's method decorator and this PR's implementation. Something like this:

@node_require_permission(permissions=('can_view_report', 'can_edit_foo', ))
class GrupoNode(AuthMixin, DjangoObjectType):
    """
    Grupos
    """
    class Meta:
        model = Grupo
        filter_fields = ['id', 'nombre', 'iglesia', ]
        interfaces = (Node, )

This basically does the same.
node_require_permission is a wrapper for this PR's node_require_permission, but I moved the decorator's usage to the class instead of the classmethod.

Copy link

@un33k un33k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

firaskafri
firaskafri previously approved these changes Jan 14, 2019
Copy link
Collaborator

@zbyte64 zbyte64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I like about this PR is it is not inventing any new opinions. All it does is connect django's existing permission framework to our classes with helper functions. It is hard for me to imagine a permission strategy that is less opinionated or less opt-in. That is why I am approving this PR.

@carlosmart626
Copy link
Author

@firaskafri @zbyte64 I can fix the issues to related to the pipeline to continue with this PR. Is any other issue to address here?

@stale
Copy link

stale bot commented Jul 27, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jul 27, 2019
@stale stale bot closed this Aug 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants