From b12d1c1a9f48a9a598b30a1f8decfa37e7334025 Mon Sep 17 00:00:00 2001 From: Ramon Wenger Date: Wed, 25 May 2022 21:55:55 +0200 Subject: [PATCH] Add mutation to update a snapshot --- server/books/schema/mutations/__init__.py | 3 +- server/books/schema/mutations/snapshot.py | 36 ++++++++++++++ server/books/schema/nodes/snapshot.py | 2 +- server/schema.graphql | 58 +++++++++++------------ 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/server/books/schema/mutations/__init__.py b/server/books/schema/mutations/__init__.py index fab3c1e9..2e523e34 100644 --- a/server/books/schema/mutations/__init__.py +++ b/server/books/schema/mutations/__init__.py @@ -1,7 +1,7 @@ from books.schema.mutations.chapter import UpdateChapterVisibility from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock from books.schema.mutations.module import UpdateSolutionVisibility, UpdateLastModule, SyncModuleVisibility -from books.schema.mutations.snapshot import CreateSnapshot, ApplySnapshot, ShareSnapshot +from books.schema.mutations.snapshot import CreateSnapshot, ApplySnapshot, ShareSnapshot, UpdateSnapshot from books.schema.mutations.topic import UpdateLastTopic @@ -17,3 +17,4 @@ class BookMutations(object): create_snapshot = CreateSnapshot.Field() apply_snapshot = ApplySnapshot.Field() share_snapshot = ShareSnapshot.Field() + update_snapshot = UpdateSnapshot.Field() diff --git a/server/books/schema/mutations/snapshot.py b/server/books/schema/mutations/snapshot.py index 6380e622..29d76719 100644 --- a/server/books/schema/mutations/snapshot.py +++ b/server/books/schema/mutations/snapshot.py @@ -2,6 +2,7 @@ import graphene from django.db.models import Q from graphene import relay +from api.types import FailureNode from api.utils import get_object from books.models import Module, ContentBlock, Chapter from books.models.snapshot import Snapshot @@ -9,6 +10,19 @@ from books.schema.nodes import SnapshotNode, ModuleNode from users.models import SchoolClass +class NotOwner(graphene.ObjectType): + class Meta: + interfaces = (FailureNode,) + + +NotOwnerFailure = NotOwner(reason="Not the owner") + + +class UpdateSnapshotResult(graphene.Union): + class Meta: + types = (SnapshotNode, NotOwner,) + + class CreateSnapshot(relay.ClientIDMutation): class Input: module = graphene.String(required=True) @@ -30,6 +44,28 @@ class CreateSnapshot(relay.ClientIDMutation): return cls(snapshot=snapshot, success=True) +class UpdateSnapshot(relay.ClientIDMutation): + class Input: + id = graphene.ID(required=True) + title = graphene.String() + + snapshot = graphene.Field(UpdateSnapshotResult) + + @classmethod + def mutate_and_get_payload(cls, root, info, **args): + id = args.get('id') + title = args.get('title') + user = info.context.user + + snapshot = get_object(Snapshot, id) + if snapshot.creator != user: + return cls(snapshot=NotOwnerFailure) + if title is not None: + snapshot.title = title + snapshot.save() + return cls(snapshot=snapshot) + + class ApplySnapshot(relay.ClientIDMutation): class Input: snapshot = graphene.ID(required=True) diff --git a/server/books/schema/nodes/snapshot.py b/server/books/schema/nodes/snapshot.py index 53707b9e..a2cc998f 100644 --- a/server/books/schema/nodes/snapshot.py +++ b/server/books/schema/nodes/snapshot.py @@ -141,7 +141,7 @@ class SnapshotNode(DjangoObjectType): @staticmethod def resolve_title(parent: Snapshot, info, **kwargs): - return f'Snapshot {parent.id}' + return parent.title if parent.title is not None else f'Snapshot {parent.id}' @staticmethod def resolve_meta_title(parent, info, **kwargs): diff --git a/server/schema.graphql b/server/schema.graphql index a42045bb..99c5eed1 100644 --- a/server/schema.graphql +++ b/server/schema.graphql @@ -301,16 +301,6 @@ type ContentBlockNode implements Node & ContentBlockInterface { originalCreator: PublicUserNode } -type ContentBlockNodeConnection { - pageInfo: PageInfo! - edges: [ContentBlockNodeEdge]! -} - -type ContentBlockNodeEdge { - node: ContentBlockNode - cursor: String! -} - input ContentElementInput { id: String type: InputTypes! @@ -469,6 +459,10 @@ type DuplicateName { reason: String } +interface FailureNode { + reason: String +} + type FieldError { code: String } @@ -683,6 +677,7 @@ type Mutation { createSnapshot(input: CreateSnapshotInput!): CreateSnapshotPayload applySnapshot(input: ApplySnapshotInput!): ApplySnapshotPayload shareSnapshot(input: ShareSnapshotInput!): ShareSnapshotPayload + updateSnapshot(input: UpdateSnapshotInput!): UpdateSnapshotPayload _debug: DjangoDebug } @@ -706,6 +701,10 @@ type NotFound { reason: String } +type NotOwner implements FailureNode { + reason: String +} + type NoteNode implements Node { id: ID! text: String! @@ -756,16 +755,6 @@ type ObjectiveNode implements Node { mine: Boolean } -type ObjectiveNodeConnection { - pageInfo: PageInfo! - edges: [ObjectiveNodeEdge]! -} - -type ObjectiveNodeEdge { - node: ObjectiveNode - cursor: String! -} - type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! @@ -965,20 +954,14 @@ type SnapshotContentBlockNode implements Node & ContentBlockInterface { } type SnapshotNode implements Node { - id: ID! - module: ModuleNode! - chapters: [SnapshotChapterNode] - hiddenContentBlocks(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, title: String): ContentBlockNodeConnection! - created: DateTime! - creator: String! - shared: Boolean! - objectiveGroups: [SnapshotObjectiveGroupNode] - hiddenObjectives(offset: Int, before: String, after: String, first: Int, last: Int, text: String): ObjectiveNodeConnection! title: String - metaTitle: String - heroImage: String + id: ID! + chapters: [SnapshotChapterNode] changes: SnapshotChangesNode mine: Boolean + shared: Boolean! + creator: String! + objectiveGroups: [SnapshotObjectiveGroupNode] } type SnapshotNodeConnection { @@ -1431,6 +1414,19 @@ type UpdateSettingPayload { clientMutationId: String } +input UpdateSnapshotInput { + id: ID! + title: String + clientMutationId: String +} + +type UpdateSnapshotPayload { + snapshot: UpdateSnapshotResult + clientMutationId: String +} + +union UpdateSnapshotResult = SnapshotNode | NotOwner + input UpdateSolutionVisibilityInput { slug: String enabled: Boolean