diff --git a/server/portfolio/models.py b/server/portfolio/models.py index 17ad7177..54565588 100644 --- a/server/portfolio/models.py +++ b/server/portfolio/models.py @@ -1,11 +1,11 @@ from django.contrib.auth import get_user_model from django.db import models from django_extensions.db.models import TitleSlugDescriptionModel -from graphql_relay import to_global_id from core.mixins import GraphqlNodeMixin from users.models import User + class Project(TitleSlugDescriptionModel, GraphqlNodeMixin): objectives = models.TextField(blank=True) appearance = models.CharField(blank=True, null=False, max_length=255) @@ -21,6 +21,7 @@ class Project(TitleSlugDescriptionModel, GraphqlNodeMixin): self.final and self.student.get_teacher().id == user.id ) + class ProjectEntry(models.Model): activity = models.TextField(blank=True) reflection = models.TextField(blank=True) diff --git a/server/portfolio/mutations.py b/server/portfolio/mutations.py index 66d29fba..3c46b364 100644 --- a/server/portfolio/mutations.py +++ b/server/portfolio/mutations.py @@ -24,23 +24,11 @@ class MutateProject(relay.ClientIDMutation): @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): - data = kwargs.get('project') - data['student'] = info.context.user.id + raise Exception('Must be subclassed') - 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()]) + @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): @@ -58,13 +46,37 @@ class AddProject(MutateProject): serializer.save() return cls(project=serializer.instance) - return cls(room=None, errors=['{}: {}'.format(key, value) for key, value in serializer.errors.items()]) + 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 + + serializer = ProjectSerializer(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.id: + raise PermissionDenied('not allowed') + class MutateProjectEntry(relay.ClientIDMutation): errors = graphene.List(graphene.String) @@ -73,7 +85,6 @@ class MutateProjectEntry(relay.ClientIDMutation): @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')) diff --git a/server/portfolio/schema.py b/server/portfolio/schema.py index 652f86fe..a578e41f 100644 --- a/server/portfolio/schema.py +++ b/server/portfolio/schema.py @@ -54,8 +54,8 @@ class PortfolioQuery(object): return Project.objects.filter(student=user) def resolve_project(self, info, **kwargs): - user = info.context.user # type: User - project = get_by_id_or_slug(Project, **kwargs) #type: Project + user = info.context.user # type: User + project = get_by_id_or_slug(Project, **kwargs) # type: Project if project.is_viewable_by(user): return project diff --git a/server/portfolio/tests/test_project_mutations.py b/server/portfolio/tests/test_project_mutations.py index ce583191..ce370a60 100644 --- a/server/portfolio/tests/test_project_mutations.py +++ b/server/portfolio/tests/test_project_mutations.py @@ -91,7 +91,8 @@ mutation UpdateProjectMutation($input: UpdateProjectInput!){ 'input': input }) self.assertIsNotNone(result.errors) - self.assertTrue('Permission' in result.errors) + self.assertTrue('message' in result.errors[0]) + self.assertEqual(result.errors[0]['message'], 'not allowed') class ProjectMutationsTestCase(DefaultUserTestCase):