import graphene from graphene import relay from rest_framework.exceptions import PermissionDenied from api.utils import get_object from portfolio.inputs import AddProjectArgument, UpdateProjectArgument, AddProjectEntryArgument, \ UpdateProjectEntryArgument from portfolio.models import Project, ProjectEntry from portfolio.schema import ProjectNode, ProjectEntryNode from portfolio.serializers import ProjectSerializer, ProjectEntrySerializer def check_owner(user, project): return user.id != project.student.id class MutateProject(relay.ClientIDMutation): errors = graphene.List(graphene.String) project = graphene.Field(ProjectNode) # class Meta: # property = 'project' # serializer_class = ProjectSerializer @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): data = kwargs.get('project') data['student'] = info.context.user.id if data.get('id') is not None: entity = get_object(Project, data['id']) serializer = ProjectSerializer(entity, data=data) else: serializer = ProjectSerializer(data=data) if serializer.is_valid(): serializer.save() props = { 'project': serializer.instance, 'errors': None } return cls(**props) return cls(errors=['{}: {}'.format(key, value) for key, value in serializer.errors.items()]) class AddProject(MutateProject): class Input: project = graphene.Argument( AddProjectArgument) # NB: can't be named AddProjectInput, otherwise graphene complains @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): data = kwargs.get('project') data['student'] = info.context.user.id serializer = ProjectSerializer(data=data) if serializer.is_valid(): serializer.save() return cls(project=serializer.instance) return cls(room=None, errors=['{}: {}'.format(key, value) for key, value in serializer.errors.items()]) class UpdateProject(MutateProject): class Input: project = graphene.Argument(UpdateProjectArgument) class MutateProjectEntry(relay.ClientIDMutation): errors = graphene.List(graphene.String) project_entry = graphene.Field(ProjectEntryNode) @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): data = kwargs.get('project_entry') project = None if data.get('project') is not None: project = get_object(Project, data.get('project')) data['project'] = project.id if check_owner(info.context.user, project): return cls(project_entry=None, errors=['not allowed']) if data.get('id') is not None: entity = get_object(ProjectEntry, data['id']) if check_owner(info.context.user, entity.project): return cls(project_entry=None, errors=['not allowed']) serializer = ProjectEntrySerializer(entity, data=data, partial=True) else: serializer = ProjectEntrySerializer(data=data) if serializer.is_valid(): serializer.save() return cls(project_entry=serializer.instance, errors=None) return cls(project_entry=None, errors=['{}: {}'.format(key, value) for key, value in serializer.errors.items()]) class AddProjectEntry(MutateProjectEntry): class Input: project_entry = graphene.Argument(AddProjectEntryArgument) class UpdateProjectEntry(MutateProjectEntry): class Input: project_entry = graphene.Argument(UpdateProjectEntryArgument) class DeleteProject(relay.ClientIDMutation): class Input: id = graphene.ID(required=True) success = graphene.Boolean() errors = graphene.List(graphene.String) @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): id = kwargs.get('id') project = get_object(Project, id) user = info.context.user if project.student != user: raise PermissionDenied('Permission denied: Incorrect project') project.delete() return cls(success=True) class DeleteProjectEntry(relay.ClientIDMutation): class Input: id = graphene.ID(required=True) success = graphene.Boolean() errors = graphene.List(graphene.String) @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): id = kwargs.get('id') project_entry = get_object(ProjectEntry, id) user = info.context.user if project_entry.project.student != user: raise PermissionDenied('Permission denied: Incorrect project') project_entry.delete() return cls(success=True) class UpdateProjectSharedState(relay.ClientIDMutation): class Input: id = graphene.ID() shared = graphene.Boolean() success = graphene.Boolean() shared = graphene.Boolean() errors = graphene.List(graphene.String) @classmethod def mutate_and_get_payload(cls, root, info, **args): try: id = args.get('id') shared = args.get('shared') user = info.context.user project = get_object(Project, id) if project.student != user: raise PermissionError() project.final = shared project.save() return cls(success=True, shared=shared) except PermissionError: errors = ["You don't have the permission to do that."] except Exception as e: errors = ['Error: {}'.format(e)] return cls(success=False, shared=None, errors=errors) class PortfolioMutations: add_project = AddProject.Field() update_project = UpdateProject.Field() delete_project = DeleteProject.Field() add_project_entry = AddProjectEntry.Field() update_project_entry = UpdateProjectEntry.Field() delete_project_entry = DeleteProjectEntry.Field() update_project_shared_state = UpdateProjectSharedState.Field()