From 74820f52b6a82d5b2e0bbe7b9cd5f4e1b6a925d1 Mon Sep 17 00:00:00 2001 From: Lorenz Padberg Date: Thu, 25 Apr 2024 11:43:26 +0200 Subject: [PATCH] Rafactoring Module.heroImage --- client/src/components/modules/Module.vue | 6 +- .../src/components/modules/ModuleTeaser.vue | 13 +- client/src/components/ui/WagtailImage.vue | 1 - .../src/graphql/gql/fragments/moduleParts.gql | 11 +- .../gql/fragments/wagtailImageParts.gql | 8 + schema.graphql | 2042 +++++++++++++++++ server/books/schema/interfaces/module.py | 18 +- server/books/schema/nodes/module.py | 5 - 8 files changed, 2065 insertions(+), 39 deletions(-) create mode 100644 client/src/graphql/gql/fragments/wagtailImageParts.gql create mode 100644 schema.graphql diff --git a/client/src/components/modules/Module.vue b/client/src/components/modules/Module.vue index 18042735..e733c178 100644 --- a/client/src/components/modules/Module.vue +++ b/client/src/components/modules/Module.vue @@ -30,9 +30,9 @@
+ :src="module.heroImage.src" + :original-width="module.heroImage.width" + :original-height="module.heroImage.height">

       
- - - - - +
@@ -34,7 +35,7 @@ import Pill from '@/components/ui/Pill.vue'; import { ModuleCategoryNode, ModuleLevelNode } from '@/__generated__/graphql'; import { computed } from '@vue/reactivity'; -import WagtailImage from "@/components/ui/WagtailImage.vue"; +import WagtailImage from '@/components/ui/WagtailImage.vue'; export interface Props { metaTitle: string; diff --git a/client/src/components/ui/WagtailImage.vue b/client/src/components/ui/WagtailImage.vue index 5e67d443..3b7a2981 100644 --- a/client/src/components/ui/WagtailImage.vue +++ b/client/src/components/ui/WagtailImage.vue @@ -66,7 +66,6 @@ const placeholderStyle = computed(() => { }; if (width.value) { const scalingFactor = width.value / props.originalWidth; - console.log(props.originalWidth, width.value); const scaledHeight = Math.round(props.originalHeight * scalingFactor); const scaledWidth = Math.round(props.originalWidth * scalingFactor); diff --git a/client/src/graphql/gql/fragments/moduleParts.gql b/client/src/graphql/gql/fragments/moduleParts.gql index 7e3c1ff8..27d8d3cc 100644 --- a/client/src/graphql/gql/fragments/moduleParts.gql +++ b/client/src/graphql/gql/fragments/moduleParts.gql @@ -1,4 +1,6 @@ #import "./highlightParts.gql" +#import "./wagtailIMageParts.gql" + fragment ModuleLegacyParts on ModuleNode { id title @@ -6,14 +8,9 @@ fragment ModuleLegacyParts on ModuleNode { teaser intro slug - heroImage heroSource - heroImageJson{ - src - alt - width - height - title + heroImage { + ...WagtailImageParts } solutionsEnabled highlights { diff --git a/client/src/graphql/gql/fragments/wagtailImageParts.gql b/client/src/graphql/gql/fragments/wagtailImageParts.gql new file mode 100644 index 00000000..2895fe0e --- /dev/null +++ b/client/src/graphql/gql/fragments/wagtailImageParts.gql @@ -0,0 +1,8 @@ +fragment WagtailImageParts on WagtailImageNode { + id + src + alt + width + height + title + } diff --git a/schema.graphql b/schema.graphql new file mode 100644 index 00000000..dbf8440a --- /dev/null +++ b/schema.graphql @@ -0,0 +1,2042 @@ +type Query { + newsTeasers: [NewsTeaserNode] + survey(id: ID): SurveyNode + surveys(offset: Int, before: String, after: String, first: Int, last: Int): SurveyNodeConnection + project(id: ID, slug: String): ProjectNode + projects: [ProjectNode] + instrument(slug: String, id: ID): InstrumentNode + instruments: [InstrumentNode] + instrumentTypes: [InstrumentTypeNode] + instrumentCategories: [InstrumentCategoryNode] + studentSubmission(id: ID!): StudentSubmissionNode + assignment( + """The ID of the object""" + id: ID! + ): AssignmentNode + assignments: [AssignmentNode] + node( + """The ID of the object""" + id: ID! + ): Node + topic(slug: String): TopicOr404Node + module(slug: String, id: ID): ModuleNode + chapter( + """The ID of the object""" + id: ID! + ): ChapterNode + contentBlock( + """The ID of the object""" + id: ID! + ): ContentBlockNode + snapshot( + """The ID of the object""" + id: ID! + ): SnapshotNode + topics(before: String, after: String, first: Int, last: Int): TopicConnection + modules(before: String, after: String, first: Int, last: Int): ModuleConnection + chapters(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, title: String): ChapterNodeConnection + moduleLevel(id: ID!): ModuleLevelNode + moduleLevels: [ModuleLevelNode] + moduleCategory(id: ID!): ModuleCategoryNode + moduleCategories: [ModuleCategoryNode] + objectiveGroup( + """The ID of the object""" + id: ID! + ): ObjectiveGroupNode + objectiveGroups(offset: Int, before: String, after: String, first: Int, last: Int, title: ObjectivesObjectiveGroupTitleChoices, module_Slug: String): ObjectiveGroupNodeConnection + roomEntry(id: ID, slug: String): RoomEntryNode + room(slug: String, id: ID, appearance: String): RoomNode + rooms: [RoomNode] + allRoomEntries(offset: Int, before: String, after: String, first: Int, last: Int, slug: String): RoomEntryNodeConnection + moduleRoom(slug: String, classId: ID): RoomNode + me: PrivateUserNode + allUsers(offset: Int, before: String, after: String, first: Int, last: Int, username: String, email: String): PrivateUserNodeConnection + myActivity(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): ModuleNodeConnection + myInstrumentActivity(offset: Int, before: String, after: String, first: Int, last: Int, slug: String): InstrumentNodeConnection + myActivities: ActivityNode + _debug: DjangoDebug +} + +type NewsTeaserNode implements Node { + """The ID of the object""" + id: ID! + imageUrl: String + title: String! + description: String + date: Date + orderId: Int! + newsArticleUrl: String + imageSource: String! + displayDate: String +} + +"""An object with an ID""" +interface Node { + """The ID of the object""" + id: ID! +} + +""" +The `Date` scalar type represents a Date +value as specified by +[iso8601](https://en.wikipedia.org/wiki/ISO_8601). +""" +scalar Date + +type SurveyNode implements Node { + """The ID of the object""" + id: ID! + title: String! + module: ModuleNode + data: JSONString! + answers(offset: Int, before: String, after: String, first: Int, last: Int): AnswerNodeConnection! + pk: Int + answer: AnswerNode + path: String! +} + +type ModuleNode implements ModuleInterface { + """Der Seitentitel, der öffentlich angezeigt werden soll""" + title: String! + + """ + Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/ + """ + slug: String! + + """e.g. 'Intro' or 'Modul 1'""" + metaTitle: String! + level: ModuleLevelNode + category: ModuleCategoryNode + heroImage: String! + + """e.g. 'Reuters', 'Wikipedia'""" + heroSource: String! + teaser: String! + intro: String! + assignments: [AssignmentNode] + objectiveGroups: [ObjectiveGroupNode] + + """The ID of the object""" + id: ID! + pk: Int + topic: TopicNode + heroImageJson: WagtailImageNode + chapters: [ChapterNode] + solutionsEnabled: Boolean + bookmark: ModuleBookmarkNode + mySubmissions: [StudentSubmissionNode] + myAnswers: [AnswerNode] + myContentBookmarks(offset: Int, before: String, after: String, first: Int, last: Int): ContentBlockBookmarkNodeConnection + myChapterBookmarks(offset: Int, before: String, after: String, first: Int, last: Int): ChapterBookmarkNodeConnection + snapshots: [SnapshotNode] + language: String + highlights: [HighlightNode] + myHighlights: [HighlightNode!]! + myBookmarks: [BookmarkNode] + path: String +} + +interface ModuleInterface { + """The ID of the object""" + id: ID! + pk: Int + heroImage: String! + topic: TopicNode + heroImageJson: WagtailImageNode +} + +type TopicNode implements Node { + """Der Seitentitel, der öffentlich angezeigt werden soll""" + title: String! + + """ + Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/ + """ + slug: String! + + """Order of the topic""" + order: Int! + teaser: String! + description: String! + vimeoId: String + instructions: String + + """The ID of the object""" + id: ID! + pk: Int + modules: [ModuleNode!] + highlights: [HighlightNode] +} + +type HighlightNode implements Node { + """The ID of the object""" + id: ID! + user: PublicUserNode! + page: HighlightableNode! + contentIndex: Int + contentUuid: UUID + paragraphIndex: Int! + startPosition: Int! + selectionLength: Int! + text: String! + note: NoteNode + color: String! +} + +type PublicUserNode implements Node { + firstName: String! + lastName: String! + avatarUrl: String! + + """The ID of the object""" + id: ID! + fullName: String! + isMe: Boolean + schoolClasses: [SchoolClassNode] +} + +type SchoolClassNode implements Node { + name: String! + code: String + + """The ID of the object""" + id: ID! + pk: Int + members: [ClassMemberNode] + readOnly: Boolean +} + +""" +We need to build this ourselves, because we want the active property on the node, because providing it on the +Connection or Edge for a UserNodeConnection is difficult. +""" +type ClassMemberNode { + user: PublicUserNode + active: Boolean + firstName: String + lastName: String + isTeacher: Boolean + id: ID + isMe: Boolean +} + +union HighlightableNode = ContentBlockNode | InstrumentNode | ModuleNode | ChapterNode + +type ContentBlockNode implements Node & ContentBlockInterface { + title: String + + """ + Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/ + """ + slug: String! + hiddenFor: [SchoolClassNode] + visibleFor: [SchoolClassNode] + userCreated: Boolean! + contents: GenericStreamFieldType + type: String! + + """The ID of the object""" + id: ID! + mine: Boolean + bookmarks: [ContentBlockBookmarkNode] + originalCreator: PublicUserNode + instrumentCategory: InstrumentCategoryNode + path: String + highlights: [HighlightNode] +} + +interface ContentBlockInterface { + title: String + contents: GenericStreamFieldType + type: String! +} + +scalar GenericStreamFieldType + +type ContentBlockBookmarkNode implements Node { + """The ID of the object""" + id: ID! + user: PublicUserNode! + note: NoteNode + uuid: UUID + contentBlock: ContentBlockNode! + path: String + content: String +} + +type NoteNode implements Node { + """The ID of the object""" + id: ID! + text: String! + contentblockbookmark: ContentBlockBookmarkNode + modulebookmark: ModuleBookmarkNode + chapterbookmark: ChapterBookmarkNode + instrumentbookmark: InstrumentBookmarkNode + highlight: HighlightNode + pk: Int +} + +type ModuleBookmarkNode { + id: ID! + user: PublicUserNode! + note: NoteNode + module: ModuleNode! + path: String + content: String +} + +type ChapterBookmarkNode implements Node { + """The ID of the object""" + id: ID! + user: PublicUserNode! + note: NoteNode + chapter: ChapterNode! + path: String + content: String +} + +type ChapterNode implements Node & ChapterInterface { + title: String + + """ + Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/ + """ + slug: String! + description: String + titleHiddenFor: [SchoolClassNode] + descriptionHiddenFor: [SchoolClassNode] + + """The ID of the object""" + id: ID! + bookmark: ChapterBookmarkNode + contentBlocks: [ContentBlockNode] + path: String + highlights: [HighlightNode] +} + +interface ChapterInterface { + description: String + title: String +} + +type InstrumentBookmarkNode implements Node { + """The ID of the object""" + id: ID! + user: PublicUserNode! + note: NoteNode + uuid: UUID + instrument: InstrumentNode! + path: String! + content: String +} + +""" +Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects +in fields, resolvers and input. +""" +scalar UUID + +type InstrumentNode implements Node { + """Der Seitentitel, der öffentlich angezeigt werden soll""" + title: String! + + """ + Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/ + """ + slug: String! + intro: String! + contents: GenericStreamFieldType + + """The ID of the object""" + id: ID! + bookmarks: [InstrumentBookmarkNode] + type: InstrumentTypeNode + language: String + highlights: [HighlightNode!]! + path: String! +} + +type InstrumentTypeNode implements Node { + """The ID of the object""" + id: ID! + name: String! + category: InstrumentCategoryNode + type: String! +} + +type InstrumentCategoryNode implements Node { + """The ID of the object""" + id: ID! + name: String! + background: String! + foreground: String! + types: [InstrumentTypeNode] +} + +type WagtailImageNode implements Node { + title: String! + width: Int! + height: Int! + + """The ID of the object""" + id: ID! + src: String + alt: String +} + +type ModuleLevelNode implements Node { + """The ID of the object""" + id: ID! + name: String! + filterAttributeType: BooksModuleLevelFilterAttributeTypeChoices! + + """Order in the Dropdown List""" + order: Int! + moduleSet(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): ModuleNodeConnection! +} + +"""An enumeration.""" +enum BooksModuleLevelFilterAttributeTypeChoices { + """All""" + ALL + + """Exact""" + EXACT +} + +type ModuleNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ModuleNodeEdge]! +} + +""" +The Relay compliant `PageInfo` type, containing data necessary to paginate this connection. +""" +type PageInfo { + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! + + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! + + """When paginating backwards, the cursor to continue.""" + startCursor: String + + """When paginating forwards, the cursor to continue.""" + endCursor: String +} + +"""A Relay edge containing a `ModuleNode` and its cursor.""" +type ModuleNodeEdge { + """The item at the end of the edge""" + node: ModuleNode + + """A cursor for use in pagination""" + cursor: String! +} + +type ModuleCategoryNode implements Node { + """The ID of the object""" + id: ID! + name: String! + filterAttributeType: BooksModuleCategoryFilterAttributeTypeChoices! + + """Order in the Dropdown List""" + order: Int! + moduleSet(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, slug_Icontains: String, slug_In: [String], title: String, title_Icontains: String, title_In: [String]): ModuleNodeConnection! +} + +"""An enumeration.""" +enum BooksModuleCategoryFilterAttributeTypeChoices { + """All""" + ALL + + """Exact""" + EXACT +} + +type AssignmentNode implements Node { + """The ID of the object""" + id: ID! + created: DateTime! + modified: DateTime! + title: String! + assignment: String! + solution: String + deleted: Boolean! + owner: PublicUserNode + module: ModuleNode! + userCreated: Boolean! + taskbaseId: String + submissions: [StudentSubmissionNode] + submission: StudentSubmissionNode + path: String! +} + +""" +The `DateTime` scalar type represents a DateTime +value as specified by +[iso8601](https://en.wikipedia.org/wiki/ISO_8601). +""" +scalar DateTime + +type StudentSubmissionNode implements Node { + """The ID of the object""" + id: ID! + created: DateTime! + modified: DateTime! + text: String! + document: String! + assignment: AssignmentNode! + student: PublicUserNode! + final: Boolean! + submissionFeedback: SubmissionFeedbackNode +} + +type SubmissionFeedbackNode implements Node { + created: DateTime! + modified: DateTime! + text: String! + teacher: PublicUserNode! + studentSubmission: StudentSubmissionNode! + final: Boolean! + + """The ID of the object""" + id: ID! +} + +type ObjectiveGroupNode implements Node { + """The ID of the object""" + id: ID! + title: ObjectivesObjectiveGroupTitleChoices + module: ModuleNode! + hiddenFor: [SchoolClassNode] + objectives: [ObjectiveNode] + pk: Int + displayTitle: String +} + +"""An enumeration.""" +enum ObjectivesObjectiveGroupTitleChoices { + """Sprache & Kommunikation""" + LANGUAGE_COMMUNICATION + + """Gesellschaft""" + SOCIETY + + """Überfachliche Lernziele""" + INTERDISCIPLINARY +} + +type ObjectiveNode implements Node { + """The ID of the object""" + id: ID! + text: String! + group: ObjectiveGroupNode! + owner: PublicUserNode + hiddenFor: [SchoolClassNode] + visibleFor: [SchoolClassNode] + order: Int + hiddenForSnapshots(offset: Int, before: String, after: String, first: Int, last: Int): SnapshotNodeConnection! + pk: Int + userCreated: Boolean + mine: Boolean +} + +type SnapshotNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [SnapshotNodeEdge]! +} + +"""A Relay edge containing a `SnapshotNode` and its cursor.""" +type SnapshotNodeEdge { + """The item at the end of the edge""" + node: SnapshotNode + + """A cursor for use in pagination""" + cursor: String! +} + +type SnapshotNode implements Node { + """The ID of the object""" + 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 + changes: SnapshotChangesNode + mine: Boolean +} + +type SnapshotChapterNode implements Node & ChapterInterface { + """The ID of the object""" + id: ID! + description: String + title: String + contentBlocks: [SnapshotContentBlockNode] + descriptionHidden: Boolean + titleHidden: Boolean +} + +type SnapshotContentBlockNode implements Node & ContentBlockInterface { + """The ID of the object""" + id: ID! + title: String + contents: GenericStreamFieldType + type: String! + hidden: Boolean +} + +type ContentBlockNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ContentBlockNodeEdge]! +} + +"""A Relay edge containing a `ContentBlockNode` and its cursor.""" +type ContentBlockNodeEdge { + """The item at the end of the edge""" + node: ContentBlockNode + + """A cursor for use in pagination""" + cursor: String! +} + +type SnapshotObjectiveGroupNode implements Node { + """The ID of the object""" + id: ID! + title: String! + hidden: Boolean! + displayTitle: String! + objectives: [SnapshotObjectiveNode]! +} + +type SnapshotObjectiveNode implements Node { + """The ID of the object""" + id: ID! + hidden: Boolean! + text: String! +} + +type ObjectiveNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ObjectiveNodeEdge]! +} + +"""A Relay edge containing a `ObjectiveNode` and its cursor.""" +type ObjectiveNodeEdge { + """The item at the end of the edge""" + node: ObjectiveNode + + """A cursor for use in pagination""" + cursor: String! +} + +type SnapshotChangesNode { + hiddenObjectives: Int! + newObjectives: Int! + hiddenContentBlocks: Int! + newContentBlocks: Int! +} + +type AnswerNode implements Node { + """The ID of the object""" + id: ID! + owner: PublicUserNode! + data: JSONString! + survey: SurveyNode! + pk: Int +} + +""" +Allows use of a JSON String for input / output from the GraphQL schema. + +Use of this type is *not recommended* as you lose the benefits of having a defined, static +schema (one of the key benefits of GraphQL). +""" +scalar JSONString + +type ContentBlockBookmarkNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ContentBlockBookmarkNodeEdge]! +} + +"""A Relay edge containing a `ContentBlockBookmarkNode` and its cursor.""" +type ContentBlockBookmarkNodeEdge { + """The item at the end of the edge""" + node: ContentBlockBookmarkNode + + """A cursor for use in pagination""" + cursor: String! +} + +type ChapterBookmarkNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ChapterBookmarkNodeEdge]! +} + +"""A Relay edge containing a `ChapterBookmarkNode` and its cursor.""" +type ChapterBookmarkNodeEdge { + """The item at the end of the edge""" + node: ChapterBookmarkNode + + """A cursor for use in pagination""" + cursor: String! +} + +union BookmarkNode = ContentBlockBookmarkNode | ModuleBookmarkNode | ChapterBookmarkNode | InstrumentBookmarkNode + +type AnswerNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [AnswerNodeEdge]! +} + +"""A Relay edge containing a `AnswerNode` and its cursor.""" +type AnswerNodeEdge { + """The item at the end of the edge""" + node: AnswerNode + + """A cursor for use in pagination""" + cursor: String! +} + +type SurveyNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [SurveyNodeEdge]! +} + +"""A Relay edge containing a `SurveyNode` and its cursor.""" +type SurveyNodeEdge { + """The item at the end of the edge""" + node: SurveyNode + + """A cursor for use in pagination""" + cursor: String! +} + +type ProjectNode implements Node { + """The ID of the object""" + id: ID! + title: String! + description: String + slug: String! + objectives: String! + appearance: String! + student: PublicUserNode + final: Boolean! + schoolClass: SchoolClassNode + entries: [ProjectEntryNode] + pk: Int + entriesCount: Int +} + +type ProjectEntryNode implements Node { + documentUrl: String! + description: String! + created: DateTime! + project: ProjectNode! + + """The ID of the object""" + id: ID! +} + +union TopicOr404Node = TopicNode | NotFound + +type NotFound { + reason: String +} + +type TopicConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [TopicEdge]! + nodes: [TopicNode] +} + +"""A Relay edge containing a `Topic` and its cursor.""" +type TopicEdge { + """The item at the end of the edge""" + node: TopicNode + + """A cursor for use in pagination""" + cursor: String! +} + +type ModuleConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ModuleEdge]! + nodes: [ModuleNode] +} + +"""A Relay edge containing a `Module` and its cursor.""" +type ModuleEdge { + """The item at the end of the edge""" + node: ModuleNode + + """A cursor for use in pagination""" + cursor: String! +} + +type ChapterNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ChapterNodeEdge]! +} + +"""A Relay edge containing a `ChapterNode` and its cursor.""" +type ChapterNodeEdge { + """The item at the end of the edge""" + node: ChapterNode + + """A cursor for use in pagination""" + cursor: String! +} + +type ObjectiveGroupNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ObjectiveGroupNodeEdge]! +} + +"""A Relay edge containing a `ObjectiveGroupNode` and its cursor.""" +type ObjectiveGroupNodeEdge { + """The item at the end of the edge""" + node: ObjectiveGroupNode + + """A cursor for use in pagination""" + cursor: String! +} + +type RoomEntryNode implements Node { + """The ID of the object""" + id: ID! + title: String! + description: String + slug: String! + room: RoomNode! + author: PublicUserNode + + """""" + contents: GenericStreamFieldType + comments: [CommentNode] + pk: Int +} + +type RoomNode implements Node { + """The ID of the object""" + id: ID! + title: String! + description: String + slug: String! + schoolClass: SchoolClassNode! + appearance: String! + userCreated: Boolean! + restricted: Boolean! + roomEntries(offset: Int, before: String, after: String, first: Int, last: Int, slug: String): RoomEntryNodeConnection! + pk: Int + entryCount: Int +} + +type RoomEntryNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [RoomEntryNodeEdge]! +} + +"""A Relay edge containing a `RoomEntryNode` and its cursor.""" +type RoomEntryNodeEdge { + """The item at the end of the edge""" + node: RoomEntryNode + + """A cursor for use in pagination""" + cursor: String! +} + +type CommentNode implements Node { + text: String! + owner: PublicUserNode + created: DateTime! + + """The ID of the object""" + id: ID! +} + +type PrivateUserNode implements Node { + """ + Erforderlich. 150 Zeichen oder weniger. Nur Buchstaben, Ziffern und @/./+/-/_. + """ + username: String! + firstName: String! + lastName: String! + lastModule: ModuleNode + lastModuleLevel: ModuleLevelNode + lastTopic: TopicNode + avatarUrl: String! + email: String! + onboardingVisited: Boolean! + team: TeamNode + schoolClasses: [SchoolClassNode] + + """The ID of the object""" + id: ID! + pk: Int + permissions: [String] + selectedClass: SchoolClassNode + expiryDate: String + isTeacher: Boolean + oldClasses: [SchoolClassNode] + recentModules( + offset: Int + before: String + after: String + first: Int + last: Int + recentModules: ID + + """Sortierung""" + orderBy: String + ): ModuleNodeConnection + readOnly: Boolean +} + +type TeamNode implements Node { + """The ID of the object""" + id: ID! + name: String! + isDeleted: Boolean! + code: String + creator: PublicUserNode + members: [PublicUserNode] + pk: Int +} + +type PrivateUserNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [PrivateUserNodeEdge]! +} + +"""A Relay edge containing a `PrivateUserNode` and its cursor.""" +type PrivateUserNodeEdge { + """The item at the end of the edge""" + node: PrivateUserNode + + """A cursor for use in pagination""" + cursor: String! +} + +type InstrumentNodeConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [InstrumentNodeEdge]! +} + +"""A Relay edge containing a `InstrumentNode` and its cursor.""" +type InstrumentNodeEdge { + """The item at the end of the edge""" + node: InstrumentNode + + """A cursor for use in pagination""" + cursor: String! +} + +type ActivityNode { + topics: [TopicNode!]! + instruments: [InstrumentNode!]! +} + +"""Debugging information for the current query.""" +type DjangoDebug { + """Executed SQL queries for this API query.""" + sql: [DjangoDebugSQL] + + """Raise exceptions for this API query.""" + exceptions: [DjangoDebugException] +} + +"""Represents a single database query made to a Django managed DB.""" +type DjangoDebugSQL { + """The type of database being used (e.g. postrgesql, mysql, sqlite).""" + vendor: String! + + """The Django database alias (e.g. 'default').""" + alias: String! + + """The actual SQL sent to this database.""" + sql: String + + """Duration of this database query in seconds.""" + duration: Float! + + """The raw SQL of this query, without params.""" + rawSql: String! + + """JSON encoded database query parameters.""" + params: String! + + """Start time of this database query.""" + startTime: Float! + + """Stop time of this database query.""" + stopTime: Float! + + """Whether this database query took more than 10 seconds.""" + isSlow: Boolean! + + """Whether this database query was a SELECT.""" + isSelect: Boolean! + + """Postgres transaction ID if available.""" + transId: String + + """Postgres transaction status if available.""" + transStatus: String + + """Postgres isolation level if available.""" + isoLevel: String + + """Postgres connection encoding if available.""" + encoding: String +} + +"""Represents a single exception raised.""" +type DjangoDebugException { + """The class of the exception""" + excType: String! + + """The message of the exception""" + message: String! + + """The stack trace""" + stack: String! +} + +type Mutation { + spellCheck(input: SpellCheckInput!): SpellCheckPayload + addNote(input: AddNoteInput!): AddNotePayload + addHighlight(input: AddHighlightInput!): AddHighlightPayload + addContentHighlight(input: AddContentHighlightInput!): AddContentHighlightPayload + deleteHighlight(input: DeleteHighlightInput!): DeleteHighlightPayload + updateHighlight(input: UpdateHighlightInput!): UpdateHighlightPayload + updateNote(input: UpdateNoteInput!): UpdateNotePayload + updateContentBookmark(input: UpdateContentBookmarkInput!): UpdateContentBookmarkPayload + updateChapterBookmark(input: UpdateChapterBookmarkInput!): UpdateChapterBookmarkPayload + updateModuleBookmark(input: UpdateModuleBookmarkInput!): UpdateModuleBookmarkPayload + updateInstrumentBookmark(input: UpdateInstrumentBookmarkInput!): UpdateInstrumentBookmarkPayload + updateAnswer(input: UpdateAnswerInput!): UpdateAnswerPayload + updatePassword(input: UpdatePasswordInput!): UpdatePasswordPayload + updateAvatar(input: UpdateAvatarInput!): UpdateAvatarPayload + updateSetting(input: UpdateSettingInput!): UpdateSettingPayload + joinClass(input: JoinClassInput!): JoinClassPayload + addRemoveMember(input: AddRemoveMemberInput!): AddRemoveMemberPayload + updateSchoolClass(input: UpdateSchoolClassInput!): UpdateSchoolClassPayload + createSchoolClass(input: CreateSchoolClassInput!): CreateSchoolClassPayload + updateOnboardingProgress: UpdateOnboardingProgress + createTeam(input: CreateTeamInput!): CreateTeamPayload + joinTeam(input: JoinTeamInput!): JoinTeamPayload + updateTeam(input: UpdateTeamInput!): UpdateTeamPayload + leaveTeam: LeaveTeam + addProject(input: AddProjectInput!): AddProjectPayload + updateProject(input: UpdateProjectInput!): UpdateProjectPayload + deleteProject(input: DeleteProjectInput!): DeleteProjectPayload + addProjectEntry(input: AddProjectEntryInput!): AddProjectEntryPayload + updateProjectEntry(input: UpdateProjectEntryInput!): UpdateProjectEntryPayload + deleteProjectEntry(input: DeleteProjectEntryInput!): DeleteProjectEntryPayload + updateProjectSharedState(input: UpdateProjectSharedStateInput!): UpdateProjectSharedStatePayload + logout: Logout + coupon(input: CouponInput!): CouponPayload + updateObjectiveVisibility(input: UpdateObjectiveVisibilityInput!): UpdateObjectiveVisibilityPayload + updateObjectiveGroupVisibility(input: UpdateObjectiveGroupVisibilityInput!): UpdateObjectiveGroupVisibilityPayload + addObjective(input: AddObjectiveInput!): AddObjectivePayload + deleteObjective(input: DeleteObjectiveInput!): DeleteObjectivePayload + updateAssignment(input: UpdateAssignmentInput!): UpdateAssignmentPayload + updateSubmissionFeedback(input: UpdateSubmissionFeedbackInput!): UpdateSubmissionFeedbackPayload + updateRoom(input: UpdateRoomInput!): UpdateRoomPayload + addRoom(input: AddRoomInput!): AddRoomPayload + deleteRoom(input: DeleteRoomInput!): DeleteRoomPayload + addRoomEntry(input: AddRoomEntryInput!): AddRoomEntryPayload + addModuleRoomEntry(input: AddModuleRoomEntryInput!): AddModuleRoomEntryPayload + deleteRoomEntry(input: DeleteRoomEntryInput!): DeleteRoomEntryPayload + updateRoomEntry(input: UpdateRoomEntryInput!): UpdateRoomEntryPayload + addComment(input: AddCommentInput!): AddCommentPayload + updateRoomVisibility(input: UpdateRoomVisibilityInput!): UpdateRoomVisibilityPayload + mutateContentBlock(input: MutateContentBlockInput!): MutateContentBlockPayload + addContentBlock(input: AddContentBlockInput!): AddContentBlockPayload + deleteContentBlock(input: DeleteContentBlockInput!): DeleteContentBlockPayload + duplicateContentBlock(input: DuplicateContentBlockInput!): DuplicateContentBlockPayload + updateSolutionVisibility(input: UpdateSolutionVisibilityInput!): UpdateSolutionVisibilityPayload + updateLastModule(input: UpdateLastModuleInput!): UpdateLastModulePayload + updateLastTopic(input: UpdateLastTopicInput!): UpdateLastTopicPayload + updateLastModuleLevel(input: UpdateLastModuleLevelInput!): UpdateLastModuleLevelPayload + updateChapterVisibility(input: UpdateChapterVisibilityInput!): UpdateChapterVisibilityPayload + syncModuleVisibility(input: SyncModuleVisibilityInput!): SyncModuleVisibilityPayload + createSnapshot(input: CreateSnapshotInput!): CreateSnapshotPayload + applySnapshot(input: ApplySnapshotInput!): ApplySnapshotPayload + shareSnapshot(input: ShareSnapshotInput!): ShareSnapshotPayload + updateSnapshot(input: UpdateSnapshotInput!): UpdateSnapshotPayload + deleteSnapshot(input: DeleteSnapshotInput!): DeleteSnapshotPayload + _debug: DjangoDebug +} + +type SpellCheckPayload { + results: [SpellCheckStepNode] + correct: Boolean + clientMutationId: String +} + +type SpellCheckStepNode { + sentence: String + offset: Int + sentenceOffset: Int + length: Int + affected: String + corrected: String +} + +input SpellCheckInput { + text: String! + assignment: ID! + clientMutationId: String +} + +type AddNotePayload { + note: NoteNode + clientMutationId: String +} + +input AddNoteInput { + note: AddNoteArgument + clientMutationId: String +} + +input AddNoteArgument { + content: UUID + block: String + type: String + parent: ID + text: String! +} + +type AddHighlightPayload { + highlight: HighlightNode + clientMutationId: String +} + +input AddHighlightInput { + highlight: AddHighlightArgument + clientMutationId: String +} + +input AddHighlightArgument { + page: String! + paragraphIndex: Int! + text: String! + startPosition: Int! + selectionLength: Int! + color: String! +} + +type AddContentHighlightPayload { + highlight: HighlightNode + clientMutationId: String +} + +input AddContentHighlightInput { + highlight: AddContentHighlightArgument + clientMutationId: String +} + +input AddContentHighlightArgument { + page: String! + paragraphIndex: Int! + text: String! + startPosition: Int! + selectionLength: Int! + color: String! + contentIndex: Int! + contentUuid: UUID! +} + +type DeleteHighlightPayload { + success: Boolean! + clientMutationId: String +} + +input DeleteHighlightInput { + id: ID! + clientMutationId: String +} + +type UpdateHighlightPayload { + highlight: HighlightNode + clientMutationId: String +} + +input UpdateHighlightInput { + color: String + note: String + id: ID! + clientMutationId: String +} + +type UpdateNotePayload { + note: NoteNode + clientMutationId: String +} + +input UpdateNoteInput { + note: UpdateNoteArgument + clientMutationId: String +} + +input UpdateNoteArgument { + id: ID! + text: String! +} + +type UpdateContentBookmarkPayload { + success: Boolean + errors: String + clientMutationId: String +} + +input UpdateContentBookmarkInput { + uuid: UUID! + contentBlock: ID! + bookmarked: Boolean! + clientMutationId: String +} + +type UpdateChapterBookmarkPayload { + success: Boolean + clientMutationId: String +} + +input UpdateChapterBookmarkInput { + chapter: ID! + bookmarked: Boolean! + clientMutationId: String +} + +type UpdateModuleBookmarkPayload { + success: Boolean + clientMutationId: String +} + +input UpdateModuleBookmarkInput { + module: String! + bookmarked: Boolean! + clientMutationId: String +} + +type UpdateInstrumentBookmarkPayload { + success: Boolean + clientMutationId: String +} + +input UpdateInstrumentBookmarkInput { + uuid: UUID! + instrument: String! + bookmarked: Boolean! + clientMutationId: String +} + +type UpdateAnswerPayload { + answer: AnswerNode + clientMutationId: String +} + +input UpdateAnswerInput { + answer: UpdateAnswerArgument + clientMutationId: String +} + +input UpdateAnswerArgument { + surveyId: ID! + data: String! +} + +type UpdatePasswordPayload { + success: Boolean + errors: [UpdateError] + clientMutationId: String +} + +type UpdateError { + field: String + errors: [FieldError] +} + +type FieldError { + code: String +} + +input UpdatePasswordInput { + passwordInput: PasswordUpdateInput + clientMutationId: String +} + +input PasswordUpdateInput { + oldPassword: String + newPassword: String +} + +type UpdateAvatarPayload { + success: Boolean + errors: [UpdateError] + clientMutationId: String +} + +input UpdateAvatarInput { + avatarUrl: String + clientMutationId: String +} + +type UpdateSettingPayload { + success: Boolean + errors: [UpdateError] + clientMutationId: String +} + +input UpdateSettingInput { + id: ID! + clientMutationId: String +} + +type JoinClassPayload { + success: Boolean + schoolClass: SchoolClassNode + clientMutationId: String +} + +input JoinClassInput { + code: String! + clientMutationId: String +} + +type AddRemoveMemberPayload { + success: Boolean + clientMutationId: String +} + +input AddRemoveMemberInput { + member: ID! + schoolClass: ID! + active: Boolean! + clientMutationId: String +} + +type UpdateSchoolClassPayload { + success: Boolean + schoolClass: SchoolClassNode + clientMutationId: String +} + +input UpdateSchoolClassInput { + id: ID! + name: String + clientMutationId: String +} + +type CreateSchoolClassPayload { + result: CreateSchoolClassResult + clientMutationId: String +} + +union CreateSchoolClassResult = SchoolClassNode | DuplicateName + +type DuplicateName implements FailureNode { + reason: String +} + +interface FailureNode { + reason: String +} + +input CreateSchoolClassInput { + name: String + clientMutationId: String +} + +type UpdateOnboardingProgress { + success: Boolean +} + +type CreateTeamPayload { + result: CreateTeamResult + clientMutationId: String +} + +union CreateTeamResult = TeamNode | DuplicateName + +input CreateTeamInput { + name: String! + clientMutationId: String +} + +type JoinTeamPayload { + success: Boolean + team: TeamNode + clientMutationId: String +} + +input JoinTeamInput { + code: String! + clientMutationId: String +} + +type UpdateTeamPayload { + success: Boolean + team: TeamNode + clientMutationId: String +} + +input UpdateTeamInput { + id: ID! + name: String + clientMutationId: String +} + +type LeaveTeam { + success: Boolean +} + +type AddProjectPayload { + errors: [String] + project: ProjectNode + clientMutationId: String +} + +input AddProjectInput { + project: AddProjectArgument + clientMutationId: String +} + +input AddProjectArgument { + title: String + description: String + objectives: String + appearance: String +} + +type UpdateProjectPayload { + errors: [String] + project: ProjectNode + clientMutationId: String +} + +input UpdateProjectInput { + project: UpdateProjectArgument + clientMutationId: String +} + +input UpdateProjectArgument { + title: String + description: String + objectives: String + appearance: String + slug: String! + final: Boolean +} + +type DeleteProjectPayload { + success: Boolean + errors: [String] + clientMutationId: String +} + +input DeleteProjectInput { + slug: String! + clientMutationId: String +} + +type AddProjectEntryPayload { + errors: [String] + projectEntry: ProjectEntryNode + clientMutationId: String +} + +input AddProjectEntryInput { + projectEntry: AddProjectEntryArgument + clientMutationId: String +} + +input AddProjectEntryArgument { + description: String + documentUrl: String + project: String! +} + +type UpdateProjectEntryPayload { + errors: [String] + projectEntry: ProjectEntryNode + clientMutationId: String +} + +input UpdateProjectEntryInput { + projectEntry: UpdateProjectEntryArgument + clientMutationId: String +} + +input UpdateProjectEntryArgument { + description: String + documentUrl: String + id: ID! +} + +type DeleteProjectEntryPayload { + success: Boolean + errors: [String] + clientMutationId: String +} + +input DeleteProjectEntryInput { + id: ID! + clientMutationId: String +} + +type UpdateProjectSharedStatePayload { + success: Boolean + shared: Boolean + errors: [String] + clientMutationId: String +} + +input UpdateProjectSharedStateInput { + slug: String + shared: Boolean + clientMutationId: String +} + +type Logout { + success: Boolean +} + +type CouponPayload { + result: RedeemCouponResult + clientMutationId: String +} + +union RedeemCouponResult = Success | InvalidCoupon + +type Success implements SuccessNode { + message: String +} + +interface SuccessNode { + message: String +} + +type InvalidCoupon implements FailureNode { + reason: String +} + +input CouponInput { + couponCode: String + clientMutationId: String +} + +type UpdateObjectiveVisibilityPayload { + objective: ObjectiveNode + clientMutationId: String +} + +input UpdateObjectiveVisibilityInput { + """The ID of the objective""" + id: ID! + visibility: [UserGroupBlockVisibility] + clientMutationId: String +} + +input UserGroupBlockVisibility { + schoolClassId: ID! + hidden: Boolean! +} + +type UpdateObjectiveGroupVisibilityPayload { + objectiveGroup: ObjectiveGroupNode + clientMutationId: String +} + +input UpdateObjectiveGroupVisibilityInput { + """The ID of the objective group""" + id: ID! + visibility: [UserGroupBlockVisibility] + clientMutationId: String +} + +type AddObjectivePayload { + objective: ObjectiveNode + clientMutationId: String +} + +input AddObjectiveInput { + objective: AddObjectiveArgument + clientMutationId: String +} + +input AddObjectiveArgument { + text: String! + objectiveGroup: ID +} + +type DeleteObjectivePayload { + success: Boolean + clientMutationId: String +} + +input DeleteObjectiveInput { + id: ID! + clientMutationId: String +} + +type UpdateAssignmentPayload { + updatedAssignment: AssignmentNode + submission: StudentSubmissionNode + successful: Boolean + errors: [String] + clientMutationId: String +} + +input UpdateAssignmentInput { + assignment: AssignmentInput + clientMutationId: String +} + +input AssignmentInput { + id: ID! + answer: String! + document: String + final: Boolean +} + +type UpdateSubmissionFeedbackPayload { + updatedSubmissionFeedback: SubmissionFeedbackNode + successful: Boolean + errors: [String] + clientMutationId: String +} + +input UpdateSubmissionFeedbackInput { + submissionFeedback: SubmissionFeedbackInput + clientMutationId: String +} + +input SubmissionFeedbackInput { + id: ID + studentSubmission: ID! + text: String! + final: Boolean +} + +type UpdateRoomPayload { + errors: [String] + room: RoomNode + clientMutationId: String +} + +input UpdateRoomInput { + room: UpdateRoomArgument + clientMutationId: String +} + +input UpdateRoomArgument { + title: String + description: String + schoolClass: SchoolClassInput + appearance: String + id: ID! +} + +input SchoolClassInput { + id: ID + name: String +} + +type AddRoomPayload { + errors: [String] + room: RoomNode + clientMutationId: String +} + +input AddRoomInput { + room: AddRoomArgument + clientMutationId: String +} + +input AddRoomArgument { + title: String + description: String + schoolClass: SchoolClassInput + appearance: String +} + +type DeleteRoomPayload { + success: Boolean + errors: [String] + clientMutationId: String +} + +input DeleteRoomInput { + id: ID! + clientMutationId: String +} + +type AddRoomEntryPayload { + roomEntry: RoomEntryNode + errors: [String] + clientMutationId: String +} + +input AddRoomEntryInput { + roomEntry: AddRoomEntryArgument + clientMutationId: String +} + +input AddRoomEntryArgument { + title: String! + contents: [ContentElementInput] + roomSlug: String! +} + +input ContentElementInput { + id: String + type: InputTypes! + value: ContentElementValueInput + contents: [ContentElementInput] +} + +enum InputTypes { + text_block + assignment + image_block + image_url_block + link_block + video_block + document_block + content_list_item + subtitle + readonly +} + +input ContentElementValueInput { + """To be used for link_block, text_block types""" + text: String + + """To be used for link, image_block types""" + url: String + + """To be used for basic_knowledge type""" + description: String + + """To be used for image_block, assignment type""" + title: String + + """To be used for assignment type""" + assignment: String + + """To be used for assignment type""" + id: String +} + +type AddModuleRoomEntryPayload { + roomEntry: RoomEntryNode + errors: [String] + clientMutationId: String +} + +input AddModuleRoomEntryInput { + roomEntry: AddModuleRoomEntryArgument + clientMutationId: String +} + +input AddModuleRoomEntryArgument { + title: String! + contents: [ContentElementInput] + roomSlug: String! + schoolClass: String! +} + +type DeleteRoomEntryPayload { + success: Boolean + roomSlug: String + roomId: ID + errors: [String] + clientMutationId: String +} + +input DeleteRoomEntryInput { + slug: String! + clientMutationId: String +} + +type UpdateRoomEntryPayload { + roomEntry: RoomEntryNode + errors: [String] + clientMutationId: String +} + +input UpdateRoomEntryInput { + roomEntry: UpdateRoomEntryArgument + clientMutationId: String +} + +input UpdateRoomEntryArgument { + title: String! + contents: [ContentElementInput] + slug: String! +} + +type AddCommentPayload { + success: Boolean + comment: CommentNode + clientMutationId: String +} + +input AddCommentInput { + comment: String! + roomEntry: ID! + clientMutationId: String +} + +type UpdateRoomVisibilityPayload { + success: Boolean + room: RoomNode + clientMutationId: String +} + +input UpdateRoomVisibilityInput { + id: ID! + restricted: Boolean! + clientMutationId: String +} + +type MutateContentBlockPayload { + contentBlock: ContentBlockNode + clientMutationId: String +} + +input MutateContentBlockInput { + id: ID! + contentBlock: ContentBlockInput + clientMutationId: String +} + +input ContentBlockInput { + title: String + type: String + contents: [ContentElementInput] + visibility: [UserGroupBlockVisibility] +} + +type AddContentBlockPayload { + newContentBlock: ContentBlockNode + errors: [String] + clientMutationId: String +} + +input AddContentBlockInput { + contentBlock: ContentBlockInput + parent: ID + after: ID + clientMutationId: String +} + +type DeleteContentBlockPayload { + success: Boolean + errors: String + clientMutationId: String +} + +input DeleteContentBlockInput { + id: ID! + clientMutationId: String +} + +type DuplicateContentBlockPayload { + contentBlock: ContentBlockNode + clientMutationId: String +} + +input DuplicateContentBlockInput { + id: ID! + clientMutationId: String +} + +type UpdateSolutionVisibilityPayload { + success: Boolean + solutionsEnabled: Boolean + errors: [String] + clientMutationId: String +} + +input UpdateSolutionVisibilityInput { + slug: String + enabled: Boolean + clientMutationId: String +} + +type UpdateLastModulePayload { + lastModule: ModuleNode + clientMutationId: String +} + +input UpdateLastModuleInput { + id: ID + clientMutationId: String +} + +type UpdateLastTopicPayload { + topic: TopicNode + clientMutationId: String +} + +input UpdateLastTopicInput { + id: ID + clientMutationId: String +} + +type UpdateLastModuleLevelPayload { + user: PrivateUserNode + clientMutationId: String +} + +input UpdateLastModuleLevelInput { + id: ID + clientMutationId: String +} + +type UpdateChapterVisibilityPayload { + chapter: ChapterNode + clientMutationId: String +} + +input UpdateChapterVisibilityInput { + id: ID! + visibility: [UserGroupBlockVisibility] + type: String! + clientMutationId: String +} + +type SyncModuleVisibilityPayload { + success: Boolean + clientMutationId: String +} + +input SyncModuleVisibilityInput { + module: String! + templateSchoolClass: ID! + schoolClass: ID! + clientMutationId: String +} + +type CreateSnapshotPayload { + snapshot: SnapshotNode + success: Boolean + clientMutationId: String +} + +input CreateSnapshotInput { + module: String! + selectedClass: ID! + clientMutationId: String +} + +type ApplySnapshotPayload { + success: Boolean + module: ModuleNode + clientMutationId: String +} + +input ApplySnapshotInput { + snapshot: ID! + selectedClass: ID! + clientMutationId: String +} + +type ShareSnapshotPayload { + success: Boolean! + snapshot: SnapshotNode + clientMutationId: String +} + +input ShareSnapshotInput { + snapshot: ID! + shared: Boolean! + clientMutationId: String +} + +type UpdateSnapshotPayload { + snapshot: UpdateSnapshotResult + clientMutationId: String +} + +union UpdateSnapshotResult = SnapshotNode | NotOwner + +type NotOwner implements FailureNode { + reason: String +} + +input UpdateSnapshotInput { + id: ID! + title: String + clientMutationId: String +} + +type DeleteSnapshotPayload { + result: DeleteSnapshotResult + clientMutationId: String +} + +union DeleteSnapshotResult = Success | NotOwner + +input DeleteSnapshotInput { + id: ID! + clientMutationId: String +} \ No newline at end of file diff --git a/server/books/schema/interfaces/module.py b/server/books/schema/interfaces/module.py index 55b49b97..f7f89399 100644 --- a/server/books/schema/interfaces/module.py +++ b/server/books/schema/interfaces/module.py @@ -5,25 +5,9 @@ from api.graphene_wagtail import generate_image_url class ModuleInterface(relay.Node): pk = graphene.Int() - hero_image = graphene.String(required=True) + hero_image = graphene.Field('books.schema.nodes.WagtailImageNode') topic = graphene.Field('books.schema.nodes.TopicNode') - hero_image_json = graphene.Field('books.schema.nodes.WagtailImageNode') @staticmethod def resolve_pk(parent, info, **kwargs): return parent.id - - @staticmethod - def resolve_hero_image(parent, info, **kwargs): - if parent.hero_image: - image = Image.objects.get(id=parent.hero_image.id) - return generate_image_url(image, 'original') - - @staticmethod - def resolve_hero_image_json(parent, info, **kwargs): - if parent.hero_image: - return Image.objects.get(id=parent.hero_image.id) - - - - diff --git a/server/books/schema/nodes/module.py b/server/books/schema/nodes/module.py index 41edac3c..f8af8016 100644 --- a/server/books/schema/nodes/module.py +++ b/server/books/schema/nodes/module.py @@ -58,7 +58,6 @@ class ModuleNode(DjangoObjectType): level = graphene.Field(ModuleLevelNode) category = graphene.Field(ModuleCategoryNode) language = graphene.String() - hero_image_json = graphene.Field("books.schema.nodes.WagtailImageNode") highlights = graphene.List("notes.schema.HighlightNode") my_highlights = graphene.List( graphene.NonNull("notes.schema.HighlightNode"), required=True @@ -170,10 +169,6 @@ class ModuleNode(DjangoObjectType): def resolve_path(root: Module, info, **kwargs): return root.route - @staticmethod - def resolve_hero_image_json(root: Module, info, **kwargs): - return root.hero_image - class RecentModuleNode(DjangoObjectType): class Meta: