skillbox/server/portfolio/mutations.py

200 lines
6.3 KiB
Python

import graphene
from graphene import relay
from rest_framework.exceptions import PermissionDenied
from api.utils import get_object
from portfolio.inputs import AddProjectArgument, AddProjectEntryArgument, UpdateProjectArgument, \
UpdateProjectEntryArgument
from portfolio.models import Project, ProjectEntry
from portfolio.schema import ProjectEntryNode, ProjectNode
from portfolio.serializers import ProjectEntrySerializer, ProjectSerializer
from users.models import UserSetting
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):
raise Exception('Must be subclassed')
@classmethod
def create_error_response(cls, serializer):
return cls(room=None, 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
data['school_class'] = info.context.user.selected_class.id
serializer = ProjectSerializer(data=data)
if serializer.is_valid():
serializer.save()
return cls(project=serializer.instance)
return cls.create_error_response(serializer)
class UpdateProject(MutateProject):
class Input:
project = graphene.Argument(UpdateProjectArgument)
@classmethod
def mutate_and_get_payload(cls, root, info, **kwargs):
data = kwargs.get('project')
cls.user_is_owner(data, info.context.user)
data['student'] = info.context.user.id
entity = get_object(Project, data['id'])
serializer = ProjectSerializer(entity, data=data)
if serializer.is_valid():
serializer.save()
props = {
'project': serializer.instance,
'errors': None
}
return cls(**props)
return cls.create_error_response(serializer)
@classmethod
def user_is_owner(cls, data, user):
project = get_object(Project, data['id'])
if not project or not project.student == user:
raise PermissionDenied('not allowed')
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')
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()