diff --git a/client/config/dev.env.js b/client/config/dev.env.js index 6aef4198..d6e712ee 100644 --- a/client/config/dev.env.js +++ b/client/config/dev.env.js @@ -4,6 +4,7 @@ const prodEnv = require('./prod.env') module.exports = merge(prodEnv, { NODE_ENV: '"development"', + HEP_URL: JSON.stringify(process.env.HEP_URL), MATOMO_HOST: JSON.stringify(process.env.MATOMO_HOST), MATOMO_SITE_ID: JSON.stringify(process.env.MATOMO_SITE_ID), }); diff --git a/client/config/prod.env.js b/client/config/prod.env.js index 3250dd1e..a5d20e78 100644 --- a/client/config/prod.env.js +++ b/client/config/prod.env.js @@ -1,6 +1,7 @@ 'use strict' module.exports = { NODE_ENV: '"production"', + HEP_URL: JSON.stringify(process.env.HEP_URL), MATOMO_HOST: JSON.stringify(process.env.MATOMO_HOST), MATOMO_SITE_ID: JSON.stringify(process.env.MATOMO_SITE_ID), } diff --git a/client/cypress/fixtures/schema.json b/client/cypress/fixtures/schema.json index ad190f83..464974da 100644 --- a/client/cypress/fixtures/schema.json +++ b/client/cypress/fixtures/schema.json @@ -1 +1 @@ -{"__schema": {"queryType": {"name": "Query"}, "mutationType": {"name": "Mutation"}, "subscriptionType": null, "types": [{"kind": "OBJECT", "name": "Query", "description": null, "fields": [{"name": "survey", "description": null, "args": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SurveyNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "surveys", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SurveyNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "project", "description": null, "args": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "projects", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ProjectNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "instrument", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "InstrumentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "instruments", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "InstrumentNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "studentSubmission", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignment", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignments", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AssignmentNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "node", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "INTERFACE", "name": "Node", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "book", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "BookNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "topic", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapter", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ChapterNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentBlock", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "books", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "BookNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "topics", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "TopicConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "modules", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapters", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ChapterNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectiveGroup", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectiveGroups", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "module_Slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "roomEntry", "description": null, "args": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "room", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "rooms", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "allRoomEntries", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomEntryNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "moduleRoom", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "classId", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "me", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "allUsers", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "username", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "email", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UserNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myActivity", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myInstrumentActivity", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "InstrumentNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "_debug", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "DjangoDebug", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SurveyNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "data", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "JSONString", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "answers", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AnswerNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "answer", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "AnswerNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "INTERFACE", "name": "Node", "description": "An object with an ID", "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [{"kind": "OBJECT", "name": "SurveyNode", "ofType": null}, {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}, {"kind": "OBJECT", "name": "UserNode", "ofType": null}, {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "ofType": null}, {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, {"kind": "OBJECT", "name": "ChapterBookmarkNode", "ofType": null}, {"kind": "OBJECT", "name": "ChapterNode", "ofType": null}, {"kind": "OBJECT", "name": "InstrumentBookmarkNode", "ofType": null}, {"kind": "OBJECT", "name": "InstrumentNode", "ofType": null}, {"kind": "OBJECT", "name": "ObjectiveGroupNode", "ofType": null}, {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, {"kind": "OBJECT", "name": "ObjectiveProgressStatusNode", "ofType": null}, {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, {"kind": "OBJECT", "name": "SubmissionFeedbackNode", "ofType": null}, {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, {"kind": "OBJECT", "name": "AnswerNode", "ofType": null}, {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, {"kind": "OBJECT", "name": "ProjectEntryNode", "ofType": null}, {"kind": "OBJECT", "name": "BookNode", "ofType": null}]}, {"kind": "SCALAR", "name": "ID", "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "String", "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ModuleNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "metaTitle", "description": "e.g. 'Intro' or 'Modul 1'", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "heroImage", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "teaser", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "intro", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignments", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AssignmentNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectiveGroups", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "module_Slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapters", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ChapterNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "topic", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "solutionsEnabled", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "bookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ModuleBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "mySubmissions", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "StudentSubmissionNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myAnswers", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AnswerNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myContentBookmarks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockBookmarkNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myChapterBookmarks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ChapterBookmarkNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AssignmentNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "AssignmentNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "PageInfo", "description": "The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.", "fields": [{"name": "hasNextPage", "description": "When paginating forwards, are there more items?", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "hasPreviousPage", "description": "When paginating backwards, are there more items?", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "startCursor", "description": "When paginating backwards, the cursor to continue.", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "endCursor", "description": "When paginating forwards, the cursor to continue.", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "Boolean", "description": "The `Boolean` scalar type represents `true` or `false`.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AssignmentNodeEdge", "description": "A Relay edge containing a `AssignmentNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AssignmentNode", "description": null, "fields": [{"name": "created", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "modified", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignment", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "solution", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleted", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "owner", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "userCreated", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "taskbaseId", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "submissions", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "submission", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "DateTime", "description": "The `DateTime` scalar type represents a DateTime\nvalue as specified by\n[iso8601](https://en.wikipedia.org/wiki/ISO_8601).", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UserNode", "description": null, "fields": [{"name": "username", "description": "Erforderlich. 150 Zeichen oder weniger. Nur Buchstaben, Ziffern und @/./+/-/_.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "firstName", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "lastName", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "lastModule", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "avatarUrl", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "email", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClasses", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "permissions", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "selectedClass", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isTeacher", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "oldClasses", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "SchoolClassNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SchoolClassNodeEdge", "description": "A Relay edge containing a `SchoolClassNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SchoolClassNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "name", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "isDeleted", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "users", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "username", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "email", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UserNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "code", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "moduleSet", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenContentBlocks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleContentBlocks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenObjectiveGroups", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "module_Slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleObjectiveGroups", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "module_Slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenObjectives", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleObjectives", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "rooms", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "members", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ClassMemberNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UserNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UserNodeEdge", "description": "A Relay edge containing a `UserNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "Int", "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31 - 1) and 2^31 - 1 since represented in JSON as double-precision floating point numbers specifiedby [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ModuleNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ModuleNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ModuleNodeEdge", "description": "A Relay edge containing a `ModuleNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ContentBlockNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockNodeEdge", "description": "A Relay edge containing a `ContentBlockNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "userCreated", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contents", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "GenericStreamFieldType", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "ContentBlockType", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "mine", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "bookmarks", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "GenericStreamFieldType", "description": null, "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "ContentBlockType", "description": "An enumeration.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "NORMAL", "description": "Normal", "isDeprecated": false, "deprecationReason": null}, {"name": "BASE_COMMUNICATION", "description": "Instrument Sprache & Kommunikation", "isDeprecated": false, "deprecationReason": null}, {"name": "TASK", "description": "Auftrag", "isDeprecated": false, "deprecationReason": null}, {"name": "BASE_SOCIETY", "description": "Instrument Gesellschaft", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "user", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "uuid", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "UUID", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentBlock", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "NoteNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "text", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentblockbookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "modulebookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ModuleBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapterbookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ChapterBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "instrumentbookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "InstrumentBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ModuleBookmarkNode", "description": null, "fields": [{"name": "user", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterBookmarkNode", "description": null, "fields": [{"name": "user", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapter", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ChapterNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentBlocks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "bookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ChapterBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "InstrumentBookmarkNode", "description": null, "fields": [{"name": "user", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "uuid", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "UUID", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "instrument", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "InstrumentNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "UUID", "description": "Leverages the internal Python implmeentation of UUID (uuid.UUID) to provide native UUID objects\nin fields, resolvers and input.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "InstrumentNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contents", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "GenericStreamFieldType", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "BasicKnowledgeType", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "bookmarks", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "InstrumentBookmarkNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "BasicKnowledgeType", "description": "An enumeration.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "LANGUAGE_COMMUNICATION", "description": "Sprache & Kommunikation", "isDeprecated": false, "deprecationReason": null}, {"name": "SOCIETY", "description": "Gesellschaft", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveGroupNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveGroupNodeEdge", "description": "A Relay edge containing a `ObjectiveGroupNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveGroupNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "ObjectiveGroupTitle", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "owner", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectives", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "displayTitle", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "mine", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "ObjectiveGroupTitle", "description": "An enumeration.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "LANGUAGE_COMMUNICATION", "description": "Sprache & Kommunikation", "isDeprecated": false, "deprecationReason": null}, {"name": "SOCIETY", "description": "Gesellschaft", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveNodeEdge", "description": "A Relay edge containing a `ObjectiveNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "text", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "group", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveGroupNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "owner", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectiveProgress", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "objective_Text", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "user_Username", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "done", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveProgressStatusNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "userCreated", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "mine", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveProgressStatusNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveProgressStatusNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveProgressStatusNodeEdge", "description": "A Relay edge containing a `ObjectiveProgressStatusNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveProgressStatusNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveProgressStatusNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "done", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "objective", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "user", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "RoomNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomNodeEdge", "description": "A Relay edge containing a `RoomNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomNode", "description": null, "fields": [{"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClass", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "appearance", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "userCreated", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "roomEntries", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomEntryNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "entryCount", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomEntryNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "RoomEntryNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomEntryNodeEdge", "description": "A Relay edge containing a `RoomEntryNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomEntryNode", "description": null, "fields": [{"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "room", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "author", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "contents", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "GenericStreamFieldType", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ClassMemberNode", "description": "We need to build this ourselves, because we want the active property on the node, because providing it on the\nConnection or Edge for a UserNodeConnection is difficult.", "fields": [{"name": "user", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "active", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "firstName", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "lastName", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isTeacher", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "StudentSubmissionNode", "description": null, "fields": [{"name": "created", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "modified", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "text", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "document", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignment", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "student", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "final", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "submissionFeedback", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SubmissionFeedbackNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SubmissionFeedbackNode", "description": null, "fields": [{"name": "created", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "modified", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "text", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "teacher", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "studentSubmission", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "final", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ChapterNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterNodeEdge", "description": "A Relay edge containing a `ChapterNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ChapterNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "order", "description": "Order of the topic", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Int", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "teaser", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "vimeoId", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "modules", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "StudentSubmissionNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "StudentSubmissionNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "StudentSubmissionNodeEdge", "description": "A Relay edge containing a `StudentSubmissionNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AnswerNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "AnswerNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AnswerNodeEdge", "description": "A Relay edge containing a `AnswerNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "AnswerNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AnswerNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "owner", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "data", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "JSONString", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "survey", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "SurveyNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "JSONString", "description": "Allows use of a JSON String for input / output from the GraphQL schema.\n\nUse of this type is *not recommended* as you lose the benefits of having a defined, static\nschema (one of the key benefits of GraphQL).", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockBookmarkNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ContentBlockBookmarkNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockBookmarkNodeEdge", "description": "A Relay edge containing a `ContentBlockBookmarkNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterBookmarkNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ChapterBookmarkNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterBookmarkNodeEdge", "description": "A Relay edge containing a `ChapterBookmarkNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ChapterBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SurveyNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "SurveyNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SurveyNodeEdge", "description": "A Relay edge containing a `SurveyNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "SurveyNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectives", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "appearance", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "student", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "final", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "entries", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ProjectEntryNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "entriesCount", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectEntryNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ProjectEntryNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectEntryNodeEdge", "description": "A Relay edge containing a `ProjectEntryNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ProjectEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectEntryNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "activity", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "reflection", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "nextSteps", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "documentUrl", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "created", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "project", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ProjectNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectNodeEdge", "description": "A Relay edge containing a `ProjectNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "InstrumentNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "InstrumentNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "InstrumentNodeEdge", "description": "A Relay edge containing a `InstrumentNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "InstrumentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "BookNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "topics", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "TopicNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "TopicNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicNodeEdge", "description": "A Relay edge containing a `TopicNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "BookNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "BookNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "BookNodeEdge", "description": "A Relay edge containing a `BookNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "BookNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "TopicEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicEdge", "description": "A Relay edge containing a `Topic` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DjangoDebug", "description": null, "fields": [{"name": "sql", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "DjangoDebugSQL", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DjangoDebugSQL", "description": null, "fields": [{"name": "vendor", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "alias", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "sql", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "duration", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Float", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "rawSql", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "params", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "startTime", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Float", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "stopTime", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Float", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isSlow", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isSelect", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "transId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "transStatus", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isoLevel", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "encoding", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "Float", "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "Mutation", "description": null, "fields": [{"name": "spellCheck", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "SpellCheckInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SpellCheckPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "registration", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "RegistrationInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RegistrationPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addNote", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddNoteInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddNotePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateNote", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateNoteInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateNotePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateContentBookmark", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateContentBookmarkInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateContentBookmarkPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateChapterBookmark", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateChapterBookmarkInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateChapterBookmarkPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateModuleBookmark", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateModuleBookmarkInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateModuleBookmarkPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateInstrumentBookmark", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateInstrumentBookmarkInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateInstrumentBookmarkPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateAnswer", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateAnswerInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateAnswerPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updatePassword", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdatePasswordInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdatePasswordPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateAvatar", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateAvatarInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateAvatarPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateSetting", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateSettingInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateSettingPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "joinClass", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "JoinClassInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "JoinClassPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addRemoveMember", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddRemoveMemberInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddRemoveMemberPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateSchoolClass", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateSchoolClassInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateSchoolClassPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "createSchoolClass", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "CreateSchoolClassInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "CreateSchoolClassPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addProject", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddProjectInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddProjectPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateProject", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateProjectInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateProjectPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteProject", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteProjectInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteProjectPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addProjectEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddProjectEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddProjectEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateProjectEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateProjectEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateProjectEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteProjectEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteProjectEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteProjectEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateProjectSharedState", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateProjectSharedStateInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateProjectSharedStatePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "logout", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "Logout", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateObjectiveProgress", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateObjectiveProgressInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateObjectiveProgressPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateObjectiveVisibility", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateObjectiveVisibilityInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateObjectiveVisibilityPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addObjective", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddObjectiveInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddObjectivePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteObjective", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteObjectiveInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteObjectivePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateAssignment", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateAssignmentInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateAssignmentPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateSubmissionFeedback", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateSubmissionFeedbackInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateSubmissionFeedbackPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateRoom", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateRoomInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateRoomPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addRoom", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddRoomInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddRoomPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteRoom", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteRoomInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteRoomPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addRoomEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddRoomEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddRoomEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteRoomEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteRoomEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteRoomEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateRoomEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateRoomEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateRoomEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "mutateContentBlock", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "MutateContentBlockInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "MutateContentBlockPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addContentBlock", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddContentBlockInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddContentBlockPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteContentBlock", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteContentBlockInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteContentBlockPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateSolutionVisibility", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateSolutionVisibilityInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateSolutionVisibilityPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateLastModule", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateLastModuleInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateLastModulePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "_debug", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "DjangoDebug", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SpellCheckPayload", "description": null, "fields": [{"name": "results", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "SpellCheckStepNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "correct", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SpellCheckStepNode", "description": null, "fields": [{"name": "sentence", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "offset", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "sentenceOffset", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "length", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "affected", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "corrected", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "SpellCheckInput", "description": null, "fields": null, "inputFields": [{"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "assignment", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RegistrationPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "MutationError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "MutationError", "description": null, "fields": [{"name": "field", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "PublicFieldError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "PublicFieldError", "description": null, "fields": [{"name": "code", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "RegistrationInput", "description": null, "fields": null, "inputFields": [{"name": "firstnameInput", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "lastnameInput", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "emailInput", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "licenseKeyInput", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddNotePayload", "description": null, "fields": [{"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddNoteInput", "description": null, "fields": null, "inputFields": [{"name": "note", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddNoteArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddNoteArgument", "description": null, "fields": null, "inputFields": [{"name": "content", "description": null, "type": {"kind": "SCALAR", "name": "UUID", "ofType": null}, "defaultValue": null}, {"name": "block", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "parent", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateNotePayload", "description": null, "fields": [{"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateNoteInput", "description": null, "fields": null, "inputFields": [{"name": "note", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateNoteArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateNoteArgument", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateContentBookmarkPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateContentBookmarkInput", "description": null, "fields": null, "inputFields": [{"name": "uuid", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "UUID", "ofType": null}}, "defaultValue": null}, {"name": "contentBlock", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "bookmarked", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateChapterBookmarkPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateChapterBookmarkInput", "description": null, "fields": null, "inputFields": [{"name": "chapter", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "bookmarked", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateModuleBookmarkPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateModuleBookmarkInput", "description": null, "fields": null, "inputFields": [{"name": "module", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "bookmarked", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateInstrumentBookmarkPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateInstrumentBookmarkInput", "description": null, "fields": null, "inputFields": [{"name": "uuid", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "UUID", "ofType": null}}, "defaultValue": null}, {"name": "instrument", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "bookmarked", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateAnswerPayload", "description": null, "fields": [{"name": "answer", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "AnswerNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateAnswerInput", "description": null, "fields": null, "inputFields": [{"name": "answer", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateAnswerArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateAnswerArgument", "description": null, "fields": null, "inputFields": [{"name": "surveyId", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "data", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdatePasswordPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "UpdateError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateError", "description": null, "fields": [{"name": "field", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "FieldError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "FieldError", "description": null, "fields": [{"name": "code", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdatePasswordInput", "description": null, "fields": null, "inputFields": [{"name": "passwordInput", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "PasswordUpdateInput", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "PasswordUpdateInput", "description": null, "fields": null, "inputFields": [{"name": "oldPassword", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "newPassword", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateAvatarPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "UpdateError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateAvatarInput", "description": null, "fields": null, "inputFields": [{"name": "avatarUrl", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateSettingPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "UpdateError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateSettingInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "JoinClassPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClass", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "JoinClassInput", "description": null, "fields": null, "inputFields": [{"name": "code", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddRemoveMemberPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRemoveMemberInput", "description": null, "fields": null, "inputFields": [{"name": "member", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "schoolClass", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "active", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateSchoolClassPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClass", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateSchoolClassInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "CreateSchoolClassPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClass", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "CreateSchoolClassInput", "description": null, "fields": null, "inputFields": [{"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddProjectPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "project", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddProjectInput", "description": null, "fields": null, "inputFields": [{"name": "project", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddProjectArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddProjectArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "objectives", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateProjectPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "project", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectInput", "description": null, "fields": null, "inputFields": [{"name": "project", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateProjectArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "objectives", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "final", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteProjectPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteProjectInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddProjectEntryPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "projectEntry", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ProjectEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddProjectEntryInput", "description": null, "fields": null, "inputFields": [{"name": "projectEntry", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddProjectEntryArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddProjectEntryArgument", "description": null, "fields": null, "inputFields": [{"name": "activity", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "reflection", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "nextSteps", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "documentUrl", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "project", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateProjectEntryPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "projectEntry", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ProjectEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectEntryInput", "description": null, "fields": null, "inputFields": [{"name": "projectEntry", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateProjectEntryArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectEntryArgument", "description": null, "fields": null, "inputFields": [{"name": "activity", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "reflection", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "nextSteps", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "documentUrl", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteProjectEntryPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteProjectEntryInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateProjectSharedStatePayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "shared", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectSharedStateInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "shared", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "Logout", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateObjectiveProgressPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "objective", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateObjectiveProgressInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": "The ID of the objective", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "done", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateObjectiveVisibilityPayload", "description": null, "fields": [{"name": "objective", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateObjectiveVisibilityInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": "The ID of the objective", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "visibility", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UserGroupBlockVisibility", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UserGroupBlockVisibility", "description": null, "fields": null, "inputFields": [{"name": "schoolClassId", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "hidden", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddObjectivePayload", "description": null, "fields": [{"name": "objective", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddObjectiveInput", "description": null, "fields": null, "inputFields": [{"name": "objective", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddObjectiveArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddObjectiveArgument", "description": null, "fields": null, "inputFields": [{"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "objectiveGroup", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteObjectivePayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteObjectiveInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateAssignmentPayload", "description": null, "fields": [{"name": "updatedAssignment", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "submission", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "successful", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateAssignmentInput", "description": null, "fields": null, "inputFields": [{"name": "assignment", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AssignmentInput", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AssignmentInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "answer", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "document", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "final", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateSubmissionFeedbackPayload", "description": null, "fields": [{"name": "updatedSubmissionFeedback", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SubmissionFeedbackNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "successful", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateSubmissionFeedbackInput", "description": null, "fields": null, "inputFields": [{"name": "submissionFeedback", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "SubmissionFeedbackInput", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "SubmissionFeedbackInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "studentSubmission", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "final", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateRoomPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "room", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateRoomInput", "description": null, "fields": null, "inputFields": [{"name": "room", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateRoomArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateRoomArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "schoolClass", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "SchoolClassInput", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "SchoolClassInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddRoomPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "room", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRoomInput", "description": null, "fields": null, "inputFields": [{"name": "room", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddRoomArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRoomArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "schoolClass", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "SchoolClassInput", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteRoomPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteRoomInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddRoomEntryPayload", "description": null, "fields": [{"name": "roomEntry", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRoomEntryInput", "description": null, "fields": null, "inputFields": [{"name": "roomEntry", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddRoomEntryArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRoomEntryArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "contents", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "ContentElementInput", "ofType": null}}, "defaultValue": null}, {"name": "room", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "ContentElementInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "InputTypes", "ofType": null}}, "defaultValue": null}, {"name": "value", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "ContentElementValueInput", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "InputTypes", "description": null, "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "text_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "assignment", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "image_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "image_url_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "link_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "video_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "document_block", "description": null, "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "ContentElementValueInput", "description": null, "fields": null, "inputFields": [{"name": "text", "description": "To be used for link_block, text_block types", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "url", "description": "To be used for link, image_block types", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": "To be used for basic_knowledge type", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": "To be used for image_block, assignment type", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "assignment", "description": "To be used for assignment type", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": "To be used for assignment type", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteRoomEntryPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "roomSlug", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "roomId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteRoomEntryInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateRoomEntryPayload", "description": null, "fields": [{"name": "roomEntry", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateRoomEntryInput", "description": null, "fields": null, "inputFields": [{"name": "roomEntry", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateRoomEntryArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateRoomEntryArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "contents", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "ContentElementInput", "ofType": null}}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "MutateContentBlockPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentBlock", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "MutateContentBlockInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "contentBlock", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "ContentBlockInput", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "ContentBlockInput", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "contents", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "ContentElementInput", "ofType": null}}, "defaultValue": null}, {"name": "visibility", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UserGroupBlockVisibility", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddContentBlockPayload", "description": null, "fields": [{"name": "newContentBlock", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddContentBlockInput", "description": null, "fields": null, "inputFields": [{"name": "contentBlock", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "ContentBlockInput", "ofType": null}, "defaultValue": null}, {"name": "parent", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteContentBlockPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteContentBlockInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateSolutionVisibilityPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "solutionsEnabled", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateSolutionVisibilityInput", "description": null, "fields": null, "inputFields": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "enabled", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateLastModulePayload", "description": null, "fields": [{"name": "module", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateLastModuleInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__Schema", "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation and subscription operations.", "fields": [{"name": "types", "description": "A list of all types supported by this server.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "queryType", "description": "The type that query operations will be rooted at.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "mutationType", "description": "If this server supports mutation, the type that mutation operations will be rooted at.", "args": [], "type": {"kind": "OBJECT", "name": "__Type", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "subscriptionType", "description": "If this server support subscription, the type that subscription operations will be rooted at.", "args": [], "type": {"kind": "OBJECT", "name": "__Type", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "directives", "description": "A list of all directives supported by this server.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Directive", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__Type", "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", "fields": [{"name": "kind", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "__TypeKind", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "name", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "fields", "description": null, "args": [{"name": "includeDeprecated", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": "false"}], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Field", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "interfaces", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "possibleTypes", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "enumValues", "description": null, "args": [{"name": "includeDeprecated", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": "false"}], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__EnumValue", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "inputFields", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__InputValue", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "ofType", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "__Type", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "__TypeKind", "description": "An enum describing what kind of type a given `__Type` is", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "SCALAR", "description": "Indicates this type is a scalar.", "isDeprecated": false, "deprecationReason": null}, {"name": "OBJECT", "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", "isDeprecated": false, "deprecationReason": null}, {"name": "INTERFACE", "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", "isDeprecated": false, "deprecationReason": null}, {"name": "UNION", "description": "Indicates this type is a union. `possibleTypes` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "ENUM", "description": "Indicates this type is an enum. `enumValues` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "INPUT_OBJECT", "description": "Indicates this type is an input object. `inputFields` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "LIST", "description": "Indicates this type is a list. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "NON_NULL", "description": "Indicates this type is a non-null. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "OBJECT", "name": "__Field", "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "args", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__InputValue", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "isDeprecated", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "deprecationReason", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__InputValue", "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "defaultValue", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__EnumValue", "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isDeprecated", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "deprecationReason", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__Directive", "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "locations", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "__DirectiveLocation", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "args", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__InputValue", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "onOperation", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": true, "deprecationReason": "Use `locations`."}, {"name": "onFragment", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": true, "deprecationReason": "Use `locations`."}, {"name": "onField", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": true, "deprecationReason": "Use `locations`."}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "__DirectiveLocation", "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "QUERY", "description": "Location adjacent to a query operation.", "isDeprecated": false, "deprecationReason": null}, {"name": "MUTATION", "description": "Location adjacent to a mutation operation.", "isDeprecated": false, "deprecationReason": null}, {"name": "SUBSCRIPTION", "description": "Location adjacent to a subscription operation.", "isDeprecated": false, "deprecationReason": null}, {"name": "FIELD", "description": "Location adjacent to a field.", "isDeprecated": false, "deprecationReason": null}, {"name": "FRAGMENT_DEFINITION", "description": "Location adjacent to a fragment definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "FRAGMENT_SPREAD", "description": "Location adjacent to a fragment spread.", "isDeprecated": false, "deprecationReason": null}, {"name": "INLINE_FRAGMENT", "description": "Location adjacent to an inline fragment.", "isDeprecated": false, "deprecationReason": null}, {"name": "SCHEMA", "description": "Location adjacent to a schema definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "SCALAR", "description": "Location adjacent to a scalar definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "OBJECT", "description": "Location adjacent to an object definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "FIELD_DEFINITION", "description": "Location adjacent to a field definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "ARGUMENT_DEFINITION", "description": "Location adjacent to an argument definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "INTERFACE", "description": "Location adjacent to an interface definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "UNION", "description": "Location adjacent to a union definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "ENUM", "description": "Location adjacent to an enum definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "ENUM_VALUE", "description": "Location adjacent to an enum value definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "INPUT_OBJECT", "description": "Location adjacent to an input object definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "INPUT_FIELD_DEFINITION", "description": "Location adjacent to an input object field definition.", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}], "directives": [{"name": "include", "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [{"name": "if", "description": "Included when true.", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}]}, {"name": "skip", "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [{"name": "if", "description": "Skipped when true.", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}]}]}} \ No newline at end of file +{"__schema": {"queryType": {"name": "Query"}, "mutationType": {"name": "Mutation"}, "subscriptionType": null, "types": [{"kind": "OBJECT", "name": "Query", "description": null, "fields": [{"name": "survey", "description": null, "args": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SurveyNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "surveys", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SurveyNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "project", "description": null, "args": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "projects", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ProjectNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "instrument", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "InstrumentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "instruments", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "InstrumentNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "studentSubmission", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignment", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignments", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AssignmentNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "node", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "INTERFACE", "name": "Node", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "book", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "BookNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "topic", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapter", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ChapterNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentBlock", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "books", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "BookNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "topics", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "TopicConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "modules", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapters", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ChapterNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectiveGroup", "description": "The ID of the object", "args": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectiveGroups", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "module_Slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "roomEntry", "description": null, "args": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "room", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "rooms", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "allRoomEntries", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomEntryNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "moduleRoom", "description": null, "args": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "classId", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "me", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "allUsers", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "username", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "email", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UserNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myActivity", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myInstrumentActivity", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "InstrumentNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"description": null, "args": [], "type": {"kind": "OBJECT", "name": "DjangoDebug", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SurveyNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "data", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "JSONString", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "answers", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AnswerNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "answer", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "AnswerNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "INTERFACE", "name": "Node", "description": "An object with an ID", "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [{"kind": "OBJECT", "name": "SurveyNode", "ofType": null}, {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}, {"kind": "OBJECT", "name": "UserNode", "ofType": null}, {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "ofType": null}, {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, {"kind": "OBJECT", "name": "ChapterBookmarkNode", "ofType": null}, {"kind": "OBJECT", "name": "ChapterNode", "ofType": null}, {"kind": "OBJECT", "name": "InstrumentBookmarkNode", "ofType": null}, {"kind": "OBJECT", "name": "InstrumentNode", "ofType": null}, {"kind": "OBJECT", "name": "ObjectiveGroupNode", "ofType": null}, {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, {"kind": "OBJECT", "name": "ObjectiveProgressStatusNode", "ofType": null}, {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, {"kind": "OBJECT", "name": "SubmissionFeedbackNode", "ofType": null}, {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, {"kind": "OBJECT", "name": "AnswerNode", "ofType": null}, {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, {"kind": "OBJECT", "name": "ProjectEntryNode", "ofType": null}, {"kind": "OBJECT", "name": "BookNode", "ofType": null}]}, {"kind": "SCALAR", "name": "ID", "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "String", "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ModuleNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "metaTitle", "description": "e.g. 'Intro' or 'Modul 1'", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "heroImage", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "teaser", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "intro", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignments", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AssignmentNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectiveGroups", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "module_Slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapters", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ChapterNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "topic", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "solutionsEnabled", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "bookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ModuleBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "mySubmissions", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "StudentSubmissionNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myAnswers", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AnswerNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myContentBookmarks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockBookmarkNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "myChapterBookmarks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ChapterBookmarkNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AssignmentNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "AssignmentNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "PageInfo", "description": "The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.", "fields": [{"name": "hasNextPage", "description": "When paginating forwards, are there more items?", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "hasPreviousPage", "description": "When paginating backwards, are there more items?", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "startCursor", "description": "When paginating backwards, the cursor to continue.", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "endCursor", "description": "When paginating forwards, the cursor to continue.", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "Boolean", "description": "The `Boolean` scalar type represents `true` or `false`.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AssignmentNodeEdge", "description": "A Relay edge containing a `AssignmentNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AssignmentNode", "description": null, "fields": [{"name": "created", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "modified", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignment", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "solution", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleted", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "owner", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "userCreated", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "taskbaseId", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "submissions", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "submission", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "DateTime", "description": "The `DateTime` scalar type represents a DateTime\nvalue as specified by\n[iso8601](https://en.wikipedia.org/wiki/ISO_8601).", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UserNode", "description": null, "fields": [{"name": "username", "description": "Erforderlich. 150 Zeichen oder weniger. Nur Buchstaben, Ziffern und @/./+/-/_.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "firstName", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "lastName", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "lastModule", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "avatarUrl", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "email", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClasses", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "permissions", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "selectedClass", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "expiryDate", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isTeacher", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "oldClasses", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "SchoolClassNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SchoolClassNodeEdge", "description": "A Relay edge containing a `SchoolClassNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SchoolClassNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "name", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "isDeleted", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "users", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "username", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "email", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UserNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "code", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "moduleSet", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenContentBlocks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleContentBlocks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenObjectiveGroups", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "module_Slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleObjectiveGroups", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "module_Slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenObjectives", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleObjectives", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "rooms", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "members", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ClassMemberNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UserNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UserNodeEdge", "description": "A Relay edge containing a `UserNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "Int", "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31 - 1) and 2^31 - 1 since represented in JSON as double-precision floating point numbers specifiedby [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ModuleNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ModuleNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ModuleNodeEdge", "description": "A Relay edge containing a `ModuleNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ContentBlockNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockNodeEdge", "description": "A Relay edge containing a `ContentBlockNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "userCreated", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contents", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "GenericStreamFieldType", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "ContentBlockType", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "mine", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "bookmarks", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "GenericStreamFieldType", "description": null, "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "ContentBlockType", "description": "An enumeration.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "NORMAL", "description": "Normal", "isDeprecated": false, "deprecationReason": null}, {"name": "BASE_COMMUNICATION", "description": "Instrument Sprache & Kommunikation", "isDeprecated": false, "deprecationReason": null}, {"name": "TASK", "description": "Auftrag", "isDeprecated": false, "deprecationReason": null}, {"name": "BASE_SOCIETY", "description": "Instrument Gesellschaft", "isDeprecated": false, "deprecationReason": null}, {"name": "BASE_INTERDISCIPLINARY", "description": "\u00dcberfachliches Instrument", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "user", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "uuid", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "UUID", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentBlock", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "NoteNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "text", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentblockbookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "modulebookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ModuleBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapterbookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ChapterBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "instrumentbookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "InstrumentBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ModuleBookmarkNode", "description": null, "fields": [{"name": "user", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterBookmarkNode", "description": null, "fields": [{"name": "user", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "chapter", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ChapterNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentBlocks", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ContentBlockNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "bookmark", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ChapterBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "InstrumentBookmarkNode", "description": null, "fields": [{"name": "user", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "uuid", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "UUID", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "instrument", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "InstrumentNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "UUID", "description": "Leverages the internal Python implmeentation of UUID (uuid.UUID) to provide native UUID objects\nin fields, resolvers and input.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "InstrumentNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contents", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "GenericStreamFieldType", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "BasicKnowledgeType", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "bookmarks", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "InstrumentBookmarkNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "BasicKnowledgeType", "description": "An enumeration.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "LANGUAGE_COMMUNICATION", "description": "Sprache & Kommunikation", "isDeprecated": false, "deprecationReason": null}, {"name": "SOCIETY", "description": "Gesellschaft", "isDeprecated": false, "deprecationReason": null}, {"name": "INTERDISCIPLINARY", "description": "\u00dcberfachliches Instrument", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveGroupNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveGroupNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveGroupNodeEdge", "description": "A Relay edge containing a `ObjectiveGroupNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveGroupNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveGroupNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "ObjectiveGroupTitle", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "module", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "owner", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectives", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "displayTitle", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "mine", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "ObjectiveGroupTitle", "description": "An enumeration.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "LANGUAGE_COMMUNICATION", "description": "Sprache & Kommunikation", "isDeprecated": false, "deprecationReason": null}, {"name": "SOCIETY", "description": "Gesellschaft", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveNodeEdge", "description": "A Relay edge containing a `ObjectiveNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "text", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "group", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveGroupNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "owner", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "hiddenFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "visibleFor", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SchoolClassNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectiveProgress", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "objective_Text", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "user_Username", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "done", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ObjectiveProgressStatusNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "userCreated", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "mine", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveProgressStatusNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveProgressStatusNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveProgressStatusNodeEdge", "description": "A Relay edge containing a `ObjectiveProgressStatusNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveProgressStatusNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ObjectiveProgressStatusNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "done", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "objective", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "user", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "RoomNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomNodeEdge", "description": "A Relay edge containing a `RoomNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomNode", "description": null, "fields": [{"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClass", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "appearance", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "userCreated", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "roomEntries", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RoomEntryNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "entryCount", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomEntryNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "RoomEntryNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomEntryNodeEdge", "description": "A Relay edge containing a `RoomEntryNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RoomEntryNode", "description": null, "fields": [{"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "room", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "author", "description": "", "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "contents", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "GenericStreamFieldType", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ClassMemberNode", "description": "We need to build this ourselves, because we want the active property on the node, because providing it on the\nConnection or Edge for a UserNodeConnection is difficult.", "fields": [{"name": "user", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "UserNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "active", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "firstName", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "lastName", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isTeacher", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "StudentSubmissionNode", "description": null, "fields": [{"name": "created", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "modified", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "text", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "document", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "assignment", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "student", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "final", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "submissionFeedback", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SubmissionFeedbackNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SubmissionFeedbackNode", "description": null, "fields": [{"name": "created", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "modified", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "text", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "teacher", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "studentSubmission", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "final", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ChapterNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterNodeEdge", "description": "A Relay edge containing a `ChapterNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ChapterNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "order", "description": "Order of the topic", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Int", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "teaser", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "vimeoId", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "instructions", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "modules", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ModuleNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "StudentSubmissionNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "StudentSubmissionNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "StudentSubmissionNodeEdge", "description": "A Relay edge containing a `StudentSubmissionNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AnswerNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "AnswerNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AnswerNodeEdge", "description": "A Relay edge containing a `AnswerNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "AnswerNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AnswerNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "owner", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "data", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "JSONString", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "survey", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "SurveyNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "JSONString", "description": "Allows use of a JSON String for input / output from the GraphQL schema.\n\nUse of this type is *not recommended* as you lose the benefits of having a defined, static\nschema (one of the key benefits of GraphQL).", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockBookmarkNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ContentBlockBookmarkNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ContentBlockBookmarkNodeEdge", "description": "A Relay edge containing a `ContentBlockBookmarkNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterBookmarkNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ChapterBookmarkNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ChapterBookmarkNodeEdge", "description": "A Relay edge containing a `ChapterBookmarkNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ChapterBookmarkNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SurveyNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "SurveyNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SurveyNodeEdge", "description": "A Relay edge containing a `SurveyNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "SurveyNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "title", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": "", "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "objectives", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "appearance", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "student", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "UserNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "final", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "entries", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "ProjectEntryNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "entriesCount", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectEntryNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ProjectEntryNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectEntryNodeEdge", "description": "A Relay edge containing a `ProjectEntryNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ProjectEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectEntryNode", "description": null, "fields": [{"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "activity", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "reflection", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "nextSteps", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "documentUrl", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "created", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "DateTime", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "project", "description": "", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "ProjectNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "ProjectNodeEdge", "description": "A Relay edge containing a `ProjectNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "InstrumentNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "InstrumentNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "InstrumentNodeEdge", "description": "A Relay edge containing a `InstrumentNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "InstrumentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "BookNode", "description": null, "fields": [{"name": "title", "description": "Der Seitentitel, der \u00f6ffentlich angezeigt werden soll", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "slug", "description": "Der Name der Seite, wie er in URLs angezeigt werden soll, z.B. http://domain.com/blog/[my-slug]/", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "id", "description": "The ID of the object.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "pk", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "topics", "description": null, "args": [{"name": "before", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "first", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "last", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "slug_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_Icontains", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title_In", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "TopicNodeConnection", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [{"kind": "INTERFACE", "name": "Node", "ofType": null}], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "TopicNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicNodeEdge", "description": "A Relay edge containing a `TopicNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "BookNodeConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "BookNodeEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "BookNodeEdge", "description": "A Relay edge containing a `BookNode` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "BookNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicConnection", "description": null, "fields": [{"name": "pageInfo", "description": "Pagination data for this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "PageInfo", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "edges", "description": "Contains the nodes in this connection.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "TopicEdge", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "TopicEdge", "description": "A Relay edge containing a `Topic` and its cursor.", "fields": [{"name": "node", "description": "The item at the end of the edge", "args": [], "type": {"kind": "OBJECT", "name": "TopicNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "cursor", "description": "A cursor for use in pagination", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DjangoDebug", "description": null, "fields": [{"name": "sql", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "DjangoDebugSQL", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DjangoDebugSQL", "description": null, "fields": [{"name": "vendor", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "alias", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "sql", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "duration", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Float", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "rawSql", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "params", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "startTime", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Float", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "stopTime", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Float", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isSlow", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isSelect", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "transId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "transStatus", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isoLevel", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "encoding", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "Float", "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "Mutation", "description": null, "fields": [{"name": "redeemCoupon", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "CouponInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "CouponPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "spellCheck", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "SpellCheckInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "SpellCheckPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "registration", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "RegistrationInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RegistrationPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addNote", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddNoteInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddNotePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateNote", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateNoteInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateNotePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateContentBookmark", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateContentBookmarkInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateContentBookmarkPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateChapterBookmark", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateChapterBookmarkInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateChapterBookmarkPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateModuleBookmark", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateModuleBookmarkInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateModuleBookmarkPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateInstrumentBookmark", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateInstrumentBookmarkInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateInstrumentBookmarkPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateAnswer", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateAnswerInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateAnswerPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updatePassword", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdatePasswordInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdatePasswordPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateAvatar", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateAvatarInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateAvatarPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateSetting", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateSettingInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateSettingPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "joinClass", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "JoinClassInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "JoinClassPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addRemoveMember", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddRemoveMemberInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddRemoveMemberPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateSchoolClass", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateSchoolClassInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateSchoolClassPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "createSchoolClass", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "CreateSchoolClassInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "CreateSchoolClassPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addProject", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddProjectInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddProjectPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateProject", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateProjectInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateProjectPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteProject", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteProjectInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteProjectPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addProjectEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddProjectEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddProjectEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateProjectEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateProjectEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateProjectEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteProjectEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteProjectEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteProjectEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateProjectSharedState", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateProjectSharedStateInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateProjectSharedStatePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "logout", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "Logout", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "coupon", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "CouponInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "CouponPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateObjectiveProgress", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateObjectiveProgressInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateObjectiveProgressPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateObjectiveVisibility", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateObjectiveVisibilityInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateObjectiveVisibilityPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addObjective", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddObjectiveInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddObjectivePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteObjective", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteObjectiveInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteObjectivePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateAssignment", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateAssignmentInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateAssignmentPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateSubmissionFeedback", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateSubmissionFeedbackInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateSubmissionFeedbackPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateRoom", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateRoomInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateRoomPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addRoom", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddRoomInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddRoomPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteRoom", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteRoomInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteRoomPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addRoomEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddRoomEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddRoomEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteRoomEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteRoomEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteRoomEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateRoomEntry", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateRoomEntryInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateRoomEntryPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "mutateContentBlock", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "MutateContentBlockInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "MutateContentBlockPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "addContentBlock", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "AddContentBlockInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "AddContentBlockPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "deleteContentBlock", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "DeleteContentBlockInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "DeleteContentBlockPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateSolutionVisibility", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateSolutionVisibilityInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateSolutionVisibilityPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "updateLastModule", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UpdateLastModuleInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "UpdateLastModulePayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "_debug", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "DjangoDebug", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "CouponPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "CouponInput", "description": null, "fields": null, "inputFields": [{"name": "couponCode", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SpellCheckPayload", "description": null, "fields": [{"name": "results", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "SpellCheckStepNode", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "correct", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "SpellCheckStepNode", "description": null, "fields": [{"name": "sentence", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "offset", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "sentenceOffset", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "length", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "affected", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "corrected", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "SpellCheckInput", "description": null, "fields": null, "inputFields": [{"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "assignment", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RegistrationPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "message", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "RegistrationInput", "description": null, "fields": null, "inputFields": [{"name": "confirmationKey", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "userId", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddNotePayload", "description": null, "fields": [{"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddNoteInput", "description": null, "fields": null, "inputFields": [{"name": "note", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddNoteArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddNoteArgument", "description": null, "fields": null, "inputFields": [{"name": "content", "description": null, "type": {"kind": "SCALAR", "name": "UUID", "ofType": null}, "defaultValue": null}, {"name": "block", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "parent", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateNotePayload", "description": null, "fields": [{"name": "note", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "NoteNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateNoteInput", "description": null, "fields": null, "inputFields": [{"name": "note", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateNoteArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateNoteArgument", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateContentBookmarkPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateContentBookmarkInput", "description": null, "fields": null, "inputFields": [{"name": "uuid", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "UUID", "ofType": null}}, "defaultValue": null}, {"name": "contentBlock", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "bookmarked", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateChapterBookmarkPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateChapterBookmarkInput", "description": null, "fields": null, "inputFields": [{"name": "chapter", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "bookmarked", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateModuleBookmarkPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateModuleBookmarkInput", "description": null, "fields": null, "inputFields": [{"name": "module", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "bookmarked", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateInstrumentBookmarkPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateInstrumentBookmarkInput", "description": null, "fields": null, "inputFields": [{"name": "uuid", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "UUID", "ofType": null}}, "defaultValue": null}, {"name": "instrument", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "bookmarked", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateAnswerPayload", "description": null, "fields": [{"name": "answer", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "AnswerNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateAnswerInput", "description": null, "fields": null, "inputFields": [{"name": "answer", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateAnswerArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateAnswerArgument", "description": null, "fields": null, "inputFields": [{"name": "surveyId", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "data", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdatePasswordPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "UpdateError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateError", "description": null, "fields": [{"name": "field", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "FieldError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "FieldError", "description": null, "fields": [{"name": "code", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdatePasswordInput", "description": null, "fields": null, "inputFields": [{"name": "passwordInput", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "PasswordUpdateInput", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "PasswordUpdateInput", "description": null, "fields": null, "inputFields": [{"name": "oldPassword", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "newPassword", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateAvatarPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "UpdateError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateAvatarInput", "description": null, "fields": null, "inputFields": [{"name": "avatarUrl", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateSettingPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "UpdateError", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateSettingInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "JoinClassPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClass", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "JoinClassInput", "description": null, "fields": null, "inputFields": [{"name": "code", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddRemoveMemberPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRemoveMemberInput", "description": null, "fields": null, "inputFields": [{"name": "member", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "schoolClass", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "active", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateSchoolClassPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClass", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateSchoolClassInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "CreateSchoolClassPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "schoolClass", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SchoolClassNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "CreateSchoolClassInput", "description": null, "fields": null, "inputFields": [{"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddProjectPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "project", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddProjectInput", "description": null, "fields": null, "inputFields": [{"name": "project", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddProjectArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddProjectArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "objectives", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateProjectPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "project", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ProjectNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectInput", "description": null, "fields": null, "inputFields": [{"name": "project", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateProjectArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "objectives", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "final", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteProjectPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteProjectInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddProjectEntryPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "projectEntry", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ProjectEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddProjectEntryInput", "description": null, "fields": null, "inputFields": [{"name": "projectEntry", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddProjectEntryArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddProjectEntryArgument", "description": null, "fields": null, "inputFields": [{"name": "activity", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "reflection", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "nextSteps", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "documentUrl", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "project", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateProjectEntryPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "projectEntry", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ProjectEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectEntryInput", "description": null, "fields": null, "inputFields": [{"name": "projectEntry", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateProjectEntryArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectEntryArgument", "description": null, "fields": null, "inputFields": [{"name": "activity", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "reflection", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "nextSteps", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "documentUrl", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteProjectEntryPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteProjectEntryInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateProjectSharedStatePayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "shared", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateProjectSharedStateInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "shared", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "Logout", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateObjectiveProgressPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "objective", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateObjectiveProgressInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": "The ID of the objective", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "done", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateObjectiveVisibilityPayload", "description": null, "fields": [{"name": "objective", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateObjectiveVisibilityInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": "The ID of the objective", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "visibility", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UserGroupBlockVisibility", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UserGroupBlockVisibility", "description": null, "fields": null, "inputFields": [{"name": "schoolClassId", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "hidden", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddObjectivePayload", "description": null, "fields": [{"name": "objective", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ObjectiveNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddObjectiveInput", "description": null, "fields": null, "inputFields": [{"name": "objective", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddObjectiveArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddObjectiveArgument", "description": null, "fields": null, "inputFields": [{"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "objectiveGroup", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteObjectivePayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteObjectiveInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateAssignmentPayload", "description": null, "fields": [{"name": "updatedAssignment", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "AssignmentNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "submission", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "StudentSubmissionNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "successful", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateAssignmentInput", "description": null, "fields": null, "inputFields": [{"name": "assignment", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AssignmentInput", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AssignmentInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "answer", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "document", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "final", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateSubmissionFeedbackPayload", "description": null, "fields": [{"name": "updatedSubmissionFeedback", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "SubmissionFeedbackNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "successful", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateSubmissionFeedbackInput", "description": null, "fields": null, "inputFields": [{"name": "submissionFeedback", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "SubmissionFeedbackInput", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "SubmissionFeedbackInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "studentSubmission", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "text", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "final", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateRoomPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "room", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateRoomInput", "description": null, "fields": null, "inputFields": [{"name": "room", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateRoomArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateRoomArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "schoolClass", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "SchoolClassInput", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "SchoolClassInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "name", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddRoomPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "room", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "RoomNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRoomInput", "description": null, "fields": null, "inputFields": [{"name": "room", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddRoomArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRoomArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "schoolClass", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "SchoolClassInput", "ofType": null}, "defaultValue": null}, {"name": "appearance", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteRoomPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteRoomInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddRoomEntryPayload", "description": null, "fields": [{"name": "roomEntry", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRoomEntryInput", "description": null, "fields": null, "inputFields": [{"name": "roomEntry", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "AddRoomEntryArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddRoomEntryArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "contents", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "ContentElementInput", "ofType": null}}, "defaultValue": null}, {"name": "room", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "ContentElementInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "InputTypes", "ofType": null}}, "defaultValue": null}, {"name": "value", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "ContentElementValueInput", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "InputTypes", "description": null, "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "text_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "assignment", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "image_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "image_url_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "link_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "video_block", "description": null, "isDeprecated": false, "deprecationReason": null}, {"name": "document_block", "description": null, "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "ContentElementValueInput", "description": null, "fields": null, "inputFields": [{"name": "text", "description": "To be used for link_block, text_block types", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "url", "description": "To be used for link, image_block types", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "description", "description": "To be used for basic_knowledge type", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "title", "description": "To be used for image_block, assignment type", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "assignment", "description": "To be used for assignment type", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "id", "description": "To be used for assignment type", "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteRoomEntryPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "roomSlug", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "roomId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteRoomEntryInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateRoomEntryPayload", "description": null, "fields": [{"name": "roomEntry", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "RoomEntryNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateRoomEntryInput", "description": null, "fields": null, "inputFields": [{"name": "roomEntry", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "UpdateRoomEntryArgument", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateRoomEntryArgument", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "defaultValue": null}, {"name": "contents", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "ContentElementInput", "ofType": null}}, "defaultValue": null}, {"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "MutateContentBlockPayload", "description": null, "fields": [{"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "contentBlock", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "MutateContentBlockInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "contentBlock", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "ContentBlockInput", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "ContentBlockInput", "description": null, "fields": null, "inputFields": [{"name": "title", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "type", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "contents", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "ContentElementInput", "ofType": null}}, "defaultValue": null}, {"name": "visibility", "description": null, "type": {"kind": "LIST", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "UserGroupBlockVisibility", "ofType": null}}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "AddContentBlockPayload", "description": null, "fields": [{"name": "newContentBlock", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ContentBlockNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "AddContentBlockInput", "description": null, "fields": null, "inputFields": [{"name": "contentBlock", "description": null, "type": {"kind": "INPUT_OBJECT", "name": "ContentBlockInput", "ofType": null}, "defaultValue": null}, {"name": "parent", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "after", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DeleteContentBlockPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "DeleteContentBlockInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "ID", "ofType": null}}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateSolutionVisibilityPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "solutionsEnabled", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateSolutionVisibilityInput", "description": null, "fields": null, "inputFields": [{"name": "slug", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "enabled", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "UpdateLastModulePayload", "description": null, "fields": [{"name": "module", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "ModuleNode", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "errors", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "UpdateLastModuleInput", "description": null, "fields": null, "inputFields": [{"name": "id", "description": null, "type": {"kind": "SCALAR", "name": "ID", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__Schema", "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation and subscription operations.", "fields": [{"name": "types", "description": "A list of all types supported by this server.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "queryType", "description": "The type that query operations will be rooted at.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "mutationType", "description": "If this server supports mutation, the type that mutation operations will be rooted at.", "args": [], "type": {"kind": "OBJECT", "name": "__Type", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "subscriptionType", "description": "If this server support subscription, the type that subscription operations will be rooted at.", "args": [], "type": {"kind": "OBJECT", "name": "__Type", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "directives", "description": "A list of all directives supported by this server.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Directive", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__Type", "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", "fields": [{"name": "kind", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "__TypeKind", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "name", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "fields", "description": null, "args": [{"name": "includeDeprecated", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": "false"}], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Field", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "interfaces", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "possibleTypes", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "enumValues", "description": null, "args": [{"name": "includeDeprecated", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": "false"}], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__EnumValue", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "inputFields", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__InputValue", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "ofType", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "__Type", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "__TypeKind", "description": "An enum describing what kind of type a given `__Type` is", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "SCALAR", "description": "Indicates this type is a scalar.", "isDeprecated": false, "deprecationReason": null}, {"name": "OBJECT", "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", "isDeprecated": false, "deprecationReason": null}, {"name": "INTERFACE", "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", "isDeprecated": false, "deprecationReason": null}, {"name": "UNION", "description": "Indicates this type is a union. `possibleTypes` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "ENUM", "description": "Indicates this type is an enum. `enumValues` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "INPUT_OBJECT", "description": "Indicates this type is an input object. `inputFields` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "LIST", "description": "Indicates this type is a list. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "NON_NULL", "description": "Indicates this type is a non-null. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "OBJECT", "name": "__Field", "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "args", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__InputValue", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "isDeprecated", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "deprecationReason", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__InputValue", "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "defaultValue", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__EnumValue", "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isDeprecated", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "deprecationReason", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__Directive", "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "locations", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "__DirectiveLocation", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "args", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__InputValue", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "onOperation", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": true, "deprecationReason": "Use `locations`."}, {"name": "onFragment", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": true, "deprecationReason": "Use `locations`."}, {"name": "onField", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": true, "deprecationReason": "Use `locations`."}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "__DirectiveLocation", "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "QUERY", "description": "Location adjacent to a query operation.", "isDeprecated": false, "deprecationReason": null}, {"name": "MUTATION", "description": "Location adjacent to a mutation operation.", "isDeprecated": false, "deprecationReason": null}, {"name": "SUBSCRIPTION", "description": "Location adjacent to a subscription operation.", "isDeprecated": false, "deprecationReason": null}, {"name": "FIELD", "description": "Location adjacent to a field.", "isDeprecated": false, "deprecationReason": null}, {"name": "FRAGMENT_DEFINITION", "description": "Location adjacent to a fragment definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "FRAGMENT_SPREAD", "description": "Location adjacent to a fragment spread.", "isDeprecated": false, "deprecationReason": null}, {"name": "INLINE_FRAGMENT", "description": "Location adjacent to an inline fragment.", "isDeprecated": false, "deprecationReason": null}, {"name": "SCHEMA", "description": "Location adjacent to a schema definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "SCALAR", "description": "Location adjacent to a scalar definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "OBJECT", "description": "Location adjacent to an object definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "FIELD_DEFINITION", "description": "Location adjacent to a field definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "ARGUMENT_DEFINITION", "description": "Location adjacent to an argument definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "INTERFACE", "description": "Location adjacent to an interface definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "UNION", "description": "Location adjacent to a union definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "ENUM", "description": "Location adjacent to an enum definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "ENUM_VALUE", "description": "Location adjacent to an enum value definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "INPUT_OBJECT", "description": "Location adjacent to an input object definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "INPUT_FIELD_DEFINITION", "description": "Location adjacent to an input object field definition.", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}], "directives": [{"name": "include", "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [{"name": "if", "description": "Included when true.", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}]}, {"name": "skip", "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [{"name": "if", "description": "Skipped when true.", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}]}]}} diff --git a/client/cypress/fixtures/schema_public.json b/client/cypress/fixtures/schema_public.json new file mode 100644 index 00000000..4ef34d28 --- /dev/null +++ b/client/cypress/fixtures/schema_public.json @@ -0,0 +1 @@ +{"__schema": {"queryType": {"name": "Query"}, "mutationType": {"name": "Mutation"}, "subscriptionType": null, "types": [{"kind": "OBJECT", "name": "Query", "description": null, "fields": [{"name": "meaningOfLife", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "Int", "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31 - 1) and 2^31 - 1 since represented in JSON as double-precision floating point numbers specifiedby [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "Mutation", "description": null, "fields": [{"name": "registration", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "RegistrationInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "RegistrationPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "login", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "LoginInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "LoginPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "betaLogin", "description": null, "args": [{"name": "input", "description": null, "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "INPUT_OBJECT", "name": "BetaLoginInput", "ofType": null}}, "defaultValue": null}], "type": {"kind": "OBJECT", "name": "BetaLoginPayload", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"description": null, "args": [], "type": {"kind": "OBJECT", "name": "DjangoDebug", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "RegistrationPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "message", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "Boolean", "description": "The `Boolean` scalar type represents `true` or `false`.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "String", "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "RegistrationInput", "description": null, "fields": null, "inputFields": [{"name": "confirmationKey", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "userId", "description": null, "type": {"kind": "SCALAR", "name": "Int", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "LoginPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "message", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "LoginInput", "description": null, "fields": null, "inputFields": [{"name": "tokenInput", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "BetaLoginPayload", "description": null, "fields": [{"name": "success", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "message", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "clientMutationId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "INPUT_OBJECT", "name": "BetaLoginInput", "description": null, "fields": null, "inputFields": [{"name": "usernameInput", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "passwordInput", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}, {"name": "clientMutationId", "description": null, "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "defaultValue": null}], "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DjangoDebug", "description": null, "fields": [{"name": "sql", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "OBJECT", "name": "DjangoDebugSQL", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "DjangoDebugSQL", "description": null, "fields": [{"name": "vendor", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "alias", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "sql", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "duration", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Float", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "rawSql", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "params", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "startTime", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Float", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "stopTime", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Float", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isSlow", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isSelect", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "transId", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "transStatus", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isoLevel", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "encoding", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "SCALAR", "name": "Float", "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__Schema", "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation and subscription operations.", "fields": [{"name": "types", "description": "A list of all types supported by this server.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "queryType", "description": "The type that query operations will be rooted at.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "mutationType", "description": "If this server supports mutation, the type that mutation operations will be rooted at.", "args": [], "type": {"kind": "OBJECT", "name": "__Type", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "subscriptionType", "description": "If this server support subscription, the type that subscription operations will be rooted at.", "args": [], "type": {"kind": "OBJECT", "name": "__Type", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "directives", "description": "A list of all directives supported by this server.", "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Directive", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__Type", "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", "fields": [{"name": "kind", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "__TypeKind", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "name", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "fields", "description": null, "args": [{"name": "includeDeprecated", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": "false"}], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Field", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "interfaces", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "possibleTypes", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "enumValues", "description": null, "args": [{"name": "includeDeprecated", "description": null, "type": {"kind": "SCALAR", "name": "Boolean", "ofType": null}, "defaultValue": "false"}], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__EnumValue", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "inputFields", "description": null, "args": [], "type": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__InputValue", "ofType": null}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "ofType", "description": null, "args": [], "type": {"kind": "OBJECT", "name": "__Type", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "__TypeKind", "description": "An enum describing what kind of type a given `__Type` is", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "SCALAR", "description": "Indicates this type is a scalar.", "isDeprecated": false, "deprecationReason": null}, {"name": "OBJECT", "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", "isDeprecated": false, "deprecationReason": null}, {"name": "INTERFACE", "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", "isDeprecated": false, "deprecationReason": null}, {"name": "UNION", "description": "Indicates this type is a union. `possibleTypes` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "ENUM", "description": "Indicates this type is an enum. `enumValues` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "INPUT_OBJECT", "description": "Indicates this type is an input object. `inputFields` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "LIST", "description": "Indicates this type is a list. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null}, {"name": "NON_NULL", "description": "Indicates this type is a non-null. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}, {"kind": "OBJECT", "name": "__Field", "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "args", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__InputValue", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "isDeprecated", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "deprecationReason", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__InputValue", "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "type", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__Type", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "defaultValue", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__EnumValue", "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "isDeprecated", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "deprecationReason", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "OBJECT", "name": "__Directive", "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", "fields": [{"name": "name", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "String", "ofType": null}}, "isDeprecated": false, "deprecationReason": null}, {"name": "description", "description": null, "args": [], "type": {"kind": "SCALAR", "name": "String", "ofType": null}, "isDeprecated": false, "deprecationReason": null}, {"name": "locations", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "ENUM", "name": "__DirectiveLocation", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "args", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "LIST", "name": null, "ofType": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "OBJECT", "name": "__InputValue", "ofType": null}}}}, "isDeprecated": false, "deprecationReason": null}, {"name": "onOperation", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": true, "deprecationReason": "Use `locations`."}, {"name": "onFragment", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": true, "deprecationReason": "Use `locations`."}, {"name": "onField", "description": null, "args": [], "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "isDeprecated": true, "deprecationReason": "Use `locations`."}], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null}, {"kind": "ENUM", "name": "__DirectiveLocation", "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [{"name": "QUERY", "description": "Location adjacent to a query operation.", "isDeprecated": false, "deprecationReason": null}, {"name": "MUTATION", "description": "Location adjacent to a mutation operation.", "isDeprecated": false, "deprecationReason": null}, {"name": "SUBSCRIPTION", "description": "Location adjacent to a subscription operation.", "isDeprecated": false, "deprecationReason": null}, {"name": "FIELD", "description": "Location adjacent to a field.", "isDeprecated": false, "deprecationReason": null}, {"name": "FRAGMENT_DEFINITION", "description": "Location adjacent to a fragment definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "FRAGMENT_SPREAD", "description": "Location adjacent to a fragment spread.", "isDeprecated": false, "deprecationReason": null}, {"name": "INLINE_FRAGMENT", "description": "Location adjacent to an inline fragment.", "isDeprecated": false, "deprecationReason": null}, {"name": "SCHEMA", "description": "Location adjacent to a schema definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "SCALAR", "description": "Location adjacent to a scalar definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "OBJECT", "description": "Location adjacent to an object definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "FIELD_DEFINITION", "description": "Location adjacent to a field definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "ARGUMENT_DEFINITION", "description": "Location adjacent to an argument definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "INTERFACE", "description": "Location adjacent to an interface definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "UNION", "description": "Location adjacent to a union definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "ENUM", "description": "Location adjacent to an enum definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "ENUM_VALUE", "description": "Location adjacent to an enum value definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "INPUT_OBJECT", "description": "Location adjacent to an input object definition.", "isDeprecated": false, "deprecationReason": null}, {"name": "INPUT_FIELD_DEFINITION", "description": "Location adjacent to an input object field definition.", "isDeprecated": false, "deprecationReason": null}], "possibleTypes": null}], "directives": [{"name": "include", "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [{"name": "if", "description": "Included when true.", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}]}, {"name": "skip", "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [{"name": "if", "description": "Skipped when true.", "type": {"kind": "NON_NULL", "name": null, "ofType": {"kind": "SCALAR", "name": "Boolean", "ofType": null}}, "defaultValue": null}]}]}} diff --git a/client/cypress/integration/login-page.spec.js b/client/cypress/integration/beta-login.spec.js similarity index 76% rename from client/cypress/integration/login-page.spec.js rename to client/cypress/integration/beta-login.spec.js index da4dbb4e..c8618595 100644 --- a/client/cypress/integration/login-page.spec.js +++ b/client/cypress/integration/beta-login.spec.js @@ -2,8 +2,7 @@ describe('The Login Page', () => { it('login and redirect to main page', () => { const username = 'test'; const password = 'test'; - - cy.visit('/'); + cy.visit('/beta-login'); cy.login(username, password, true); cy.get('body').contains('Neues Wissen erwerben'); }); @@ -12,7 +11,7 @@ describe('The Login Page', () => { const username = ''; const password = 'test'; - cy.visit('/'); + cy.visit('/beta-login'); cy.login(username, password); cy.get('[data-cy=email-local-errors]').contains('E-Mail ist ein Pflichtfeld'); }); @@ -21,7 +20,7 @@ describe('The Login Page', () => { const username = 'test'; const password = ''; - cy.visit('/'); + cy.visit('/beta-login'); cy.login(username, password); cy.get('[data-cy=password-local-errors]').contains('Passwort ist ein Pflichtfeld'); }); @@ -30,23 +29,18 @@ describe('The Login Page', () => { const username = 'test'; const password = '12345'; - cy.visit('/'); + cy.visit('/beta-login'); cy.login(username, password); cy.get('[data-cy=login-error]').contains('Die E-Mail oder das Passwort ist falsch. Bitte versuchen Sie nochmals.'); }); - it('redirect after login', () => { - const username = 'test'; - const password = 'test'; + it('logs out then logs in again', () => { - cy.visit('/book/topic/berufliche-grundbildung'); - cy.login(username, password); - cy.get('body').contains('Berufliche Grundbildung'); - }); + const user = 'rahel.cueni'; + const pw = 'test' - it.only('logs out then logs in again', () => { cy.viewport('macbook-15'); - cy.apolloLogin('rahel.cueni', 'test'); + cy.apolloLogin(user, pw); cy.visit('/me/my-class'); cy.get('[data-cy=header-user-widget]').should('exist').within(() => { cy.get('[data-cy=user-widget-avatar]').should('exist').click(); @@ -54,7 +48,11 @@ describe('The Login Page', () => { cy.get('[data-cy=logout]').click(); - cy.login('rahel.cueni', 'test'); + cy.get('[data-cy=email-input]').should('exist').within(() => { + cy.visit('/beta-login'); + }); + + cy.login(user, pw); cy.get('[data-cy=header-user-widget]').should('exist').within(() => { cy.get('[data-cy=user-widget-avatar]').should('exist').click(); diff --git a/client/cypress/integration/coupon.spec.js b/client/cypress/integration/coupon.spec.js new file mode 100644 index 00000000..046748b5 --- /dev/null +++ b/client/cypress/integration/coupon.spec.js @@ -0,0 +1,76 @@ +import { GraphQLError } from "graphql"; + +const schema = require('../fixtures/schema.json'); + +describe('Email Verifcation', () => { + beforeEach(() => { + cy.server(); + }); + + it('forwards to homepage if confirmation key is correct', () => { + cy.viewport('macbook-15'); + cy.mockGraphql({ + schema: schema, + operations: { + Coupon: { + coupon: { + success: true + } + }, + } + }); + cy.login('rahel.cueni', 'test', true) + cy.get('[data-cy="rooms-link"]').contains('Alle Räume anzeigen'); + + cy.visit('/license-activation'); + cy.redeemCoupon('12345asfd'); + cy.get('body').contains('Neues Wissen erwerben'); + + }); + + it('displays error if input is missing', () => { + cy.viewport('macbook-15'); + cy.login('rahel.cueni', 'test', true) + cy.get('[data-cy="rooms-link"]').contains('Alle Räume anzeigen'); + + cy.visit('/license-activation'); + cy.redeemCoupon(''); + cy.get('[data-cy="coupon-local-errors"]').contains('Coupon ist ein Pflichtfeld.'); + + }); + + it('displays error if coupon input is wrong', () => { + cy.viewport('macbook-15'); + cy.mockGraphql({ + schema: schema, + operations: { + Coupon: new GraphQLError('invalid_coupon') + } + }); + cy.login('rahel.cueni', 'test', true) + cy.get('[data-cy="rooms-link"]').contains('Alle Räume anzeigen'); + + cy.visit('/license-activation'); + cy.redeemCoupon('12345asfd'); + cy.get('[data-cy="coupon-remote-errors"]').contains('Der angegebene Coupon-Code ist ungültig.'); + + }); + + it('displays error if an error occures', () => { + cy.viewport('macbook-15'); + cy.mockGraphql({ + schema: schema, + operations: { + Coupon: new GraphQLError("unknown_error") + } + }); + cy.login('rahel.cueni', 'test', true) + cy.get('[data-cy="rooms-link"]').contains('Alle Räume anzeigen'); + + cy.visit('/license-activation'); + cy.redeemCoupon('12345asfd'); + cy.get('[data-cy="coupon-remote-errors"]').contains('Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals oder kontaktieren Sie den Administrator.'); + + }); + +}); diff --git a/client/cypress/integration/email-verification.spec.js b/client/cypress/integration/email-verification.spec.js new file mode 100644 index 00000000..845c2193 --- /dev/null +++ b/client/cypress/integration/email-verification.spec.js @@ -0,0 +1,94 @@ +const schema = require('../fixtures/schema_public.json'); + +describe('Email Verifcation', () => { + beforeEach(() => { + cy.server(); + }); + + it('forwards to homepage if confirmation key is correct', () => { + cy.viewport('macbook-15'); + cy.mockGraphql({ + schema: schema, + operations: { + Registration: { + registration: { + message: "success", + success: true + } + }, + } + }); + + cy.visit('/verify-email?confirmation=abcd1234&id=12'); + + // user should be logged in at that stage. As the cookie cannot be set at the right time + // we just check if the user gets redirected to the login page as we can't log her in + cy.url().should('include', 'hello?redirect=%2F'); + + }); + + it('displays error if key is incorrect', () => { + cy.viewport('macbook-15'); + cy.mockGraphql({ + schema: schema, + // endpoint: '/api/graphql' + operations: { + Registration: { + registration: { + message: "invalid_key", + success: false + } + }, + } + }); + + cy.visit('/verify-email?confirmation=abcd1234&id=12'); + cy.get('[data-cy="code-nok-msg"]').contains('Der angegebene Verifizierungscode ist ungültig oder abgelaufen.'); + cy.get('[data-cy="code-ok-msg"]').should('not.exist'); + + }); + + it('displays error if an error occured', () => { + cy.viewport('macbook-15'); + cy.mockGraphql({ + schema: schema, + // endpoint: '/api/graphql' + operations: { + Registration: { + registration: { + message: "unkown_error", + success: false + } + }, + } + }); + + cy.visit('/verify-email?confirmation=abcd1234&id=12'); + cy.get('[data-cy="code-nok-msg"]').contains('Ein Fehler ist aufgetreten. Bitte kontaktieren Sie den Administrator.'); + + }); + + it('forwards to coupon page if user has no valid license', () => { + cy.viewport('macbook-15'); + cy.mockGraphql({ + schema: schema, + // endpoint: '/api/graphql' + operations: { + Registration: { + registration: { + message: "no_valid_license", + success: false + } + }, + } + }); + + cy.visit('/verify-email?confirmation=abcd1234&id=12'); + + // user should be logged in at that stage. As the cookie cannot be set at the right time + // we just check if the user gets redirected to the coupon page as we can't log her in + cy.url().should('include', 'hello?redirect=%2Flicense-activation'); + + }); + +}); diff --git a/client/cypress/integration/home-page-logged-in.spec.js b/client/cypress/integration/home-page-logged-in.spec.js deleted file mode 100644 index 4b846114..00000000 --- a/client/cypress/integration/home-page-logged-in.spec.js +++ /dev/null @@ -1,9 +0,0 @@ -describe('The Logged In Home Page', () => { - it('successfully loads', () => { - // todo: use graphql login - cy.visit('/'); - cy.login('test', 'test'); - - cy.get('.block-title__title').should('contain', 'Inhalte') - }) -}) diff --git a/client/cypress/integration/login.spec.js b/client/cypress/integration/login.spec.js new file mode 100644 index 00000000..43d39485 --- /dev/null +++ b/client/cypress/integration/login.spec.js @@ -0,0 +1,73 @@ +const schema = require('../fixtures/schema_public.json'); +const isEmailAvailableUrl = '**/rest/deutsch/V1/customers/isEmailAvailable'; +const checkPasswordUrl = '**/rest/deutsch/V1/integration/customer/token'; + +describe('Login', () => { + beforeEach(() => { + cy.server(); + }); + + it('works with valid email and password', () => { + cy.viewport('macbook-15'); + + cy.mockGraphql({ + schema: schema, + operations: { + Login: variables => { + return { + login: { + errors: [], + message: "success", + success: true + } + } + }, + } + }); + + cy.route('POST', isEmailAvailableUrl, 'false'); + cy.route({ + method: 'POST', + url: checkPasswordUrl, + response: 'token12345ABCD+', + }); + + cy.visit('/hello'); + cy.checkEmailAvailable('feuz@aebi.ch'); + + cy.get('[data-cy="login-title"]').contains('Bitte geben Sie das passende Passwort ein'); + cy.enterPassword('abcd1234'); + // As we cannot set the cookie in the right manner, we just check for the absence of errors. + // In real world the user gets redirect to another page + cy.get('[data-cy="email-local-errors"]').should('not.exist'); + }); + + it('displays error message if password is wrong', () => { + cy.viewport('macbook-15'); + cy.route('POST', isEmailAvailableUrl, 'false'); + cy.route({ + method: 'POST', + status: 401, + response: { + message: "Sie haben sich nicht korrekt eingeloggt oder Ihr Konto ist vor\u00fcbergehend deaktiviert." + }, + url: checkPasswordUrl + }); + + cy.visit('/hello'); + + cy.checkEmailAvailable('feuz@aebi.ch'); + cy.get('[data-cy="login-title"]').contains('Bitte geben Sie das passende Passwort ein'); + + cy.enterPassword('abcd1234'); + cy.get('[data-cy="password-errors"]').contains('Sie haben sich nicht korrekt eingeloggt oder Ihr Konto ist vorübergehend deaktiviert.'); + }); + + it('displays error message if input is not an email address', () => { + cy.viewport('macbook-15'); + cy.visit('/hello'); + + cy.checkEmailAvailable('feuzaebi.ch'); + cy.get('[data-cy="email-local-errors"]').contains('Bitte geben Sie eine gülitge E-Mail an'); + }) +}); diff --git a/client/cypress/integration/registration-page.spec.js b/client/cypress/integration/registration-page.spec.js deleted file mode 100644 index d01d40de..00000000 --- a/client/cypress/integration/registration-page.spec.js +++ /dev/null @@ -1,77 +0,0 @@ -describe('The Regstration Page', () => { - // works locally, but not in pipelines. - // it('register user', () => { - - // let timestamp = Math.round((new Date()).getTime() / 1000); - - // const firstname = 'pesche'; - // const lastname = 'peschemann'; - // const email = `skillboxtest${timestamp}@iterativ.ch`; - // const licenseKey = 'c1fa2e2a-2e27-480d-8469-2e88414c4ad8'; - - // cy.visit('/register'); - // cy.register(firstname, lastname, email, licenseKey); - // cy.get('.reset__heading').contains('Schauen Sie in Ihr Postfach'); - // }); - - it('user sees error message if firstname is omitted', () => { - let timestamp = Math.round((new Date()).getTime() / 1000); - const firstname = ''; - const lastname = 'peschemann'; - const email = `skillboxtest${timestamp}@iterativ.ch`; - const licenseKey = 'c1fa2e2a-2e27-480d-8469-2e88414c4ad8'; - - cy.visit('/register'); - cy.register(firstname, lastname, email, licenseKey); - cy.get('[data-cy="firstname-local-errors"]').contains('Vorname ist ein Pflichtfeld.'); - }); - - it('user sees error message if lastname is omitted', () => { - let timestamp = Math.round((new Date()).getTime() / 1000); - const firstname = 'pesche'; - const lastname = ''; - const email = `skillboxtest${timestamp}@iterativ.ch`; - const licenseKey = 'c1fa2e2a-2e27-480d-8469-2e88414c4ad8'; - - cy.visit('/register'); - cy.register(firstname, lastname, email, licenseKey); - cy.get('[data-cy="lastname-local-errors"]').contains('Nachname ist ein Pflichtfeld.'); - }); - - it('user sees error message if email is omitted', () => { - let timestamp = Math.round((new Date()).getTime() / 1000); - const firstname = 'pesche'; - const lastname = 'peschemann'; - const email = ``; - const licenseKey = 'c1fa2e2a-2e27-480d-8469-2e88414c4ad8'; - - cy.visit('/register'); - cy.register(firstname, lastname, email, licenseKey); - cy.get('[data-cy="email-local-errors"]').contains('E-Mail ist ein Pflichtfeld.'); - }); - - it('user sees error message if license is omitted', () => { - let timestamp = Math.round((new Date()).getTime() / 1000); - const firstname = 'pesche'; - const lastname = 'peschemann'; - const email = `skillboxtest${timestamp}@iterativ.ch`; - const licenseKey = ''; - - cy.visit('/register'); - cy.register(firstname, lastname, email, licenseKey); - cy.get('[data-cy="licenseKey-local-errors"]').contains('Lizenz ist ein Pflichtfeld.'); - }); - - it('user sees error message if license key is wrong', () => { - let timestamp = Math.round((new Date()).getTime() / 1000); - const firstname = 'pesche'; - const lastname = 'peschemann'; - const email = `skillboxtest${timestamp}@iterativ.ch`; - const licenseKey = 'asdsafsadfsadfasdf'; - - cy.visit('/register'); - cy.register(firstname, lastname, email, licenseKey); - cy.get('[data-cy="licenseKey-remote-errors"]').contains('Die angegebenen Lizenz ist unglültig'); - }); - -}) diff --git a/client/cypress/integration/registration.spec.js b/client/cypress/integration/registration.spec.js new file mode 100644 index 00000000..1967b42d --- /dev/null +++ b/client/cypress/integration/registration.spec.js @@ -0,0 +1,152 @@ +const isEmailAvailableUrl = 'https://stage.hep-verlag.ch/rest/deutsch/V1/customers/isEmailAvailable'; +const registerUrl = '/api/proxy/registration/'; + +let registrationResponse = { + id: 84215, + group_id: 1, + confirmation: "91cf39007547feae7e33778d89fc71db", + created_at: "2020-02-06 13:56:54", + updated_at: "2020-02-06 13:56:54", + created_in: "hep verlag", + email: "feuz@aebi.ch", + firstname: "Kari", + lastname: "Feuz", + prefix: "Herr", + gender: 1, + store_id: 1, + website_id: 1, + addresses: [] +}; + +describe('Registration', () => { + beforeEach(() => { + cy.viewport('macbook-15'); + cy.server(); + }); + + it('works with valid data', () => { + cy.route('POST', isEmailAvailableUrl, "true"); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, registrationResponse.firstname, registrationResponse.lastname, 'Weg 1', 'Bern', '3001', 'Abcd1234!', 'Abcd1234!'); + cy.get('[data-cy="email-check"]').contains('Eine Email ist auf dem Weg, bitte überprüfen sie ihre E-mail Konto.'); + }); + + it('displays error if firstname is missing', () => { + cy.route('POST', isEmailAvailableUrl, "true"); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, '', registrationResponse.lastname, 'Weg 1', 'Bern', '3001', 'Abcd1234!', 'Abcd1234!'); + cy.get('[data-cy="firstname-local-errors"]').contains('Vorname ist ein Pflichtfeld'); + }); + + it('displays error if lastname is missing', () => { + cy.route('POST', isEmailAvailableUrl, "true"); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, registrationResponse.firstname, '', 'Weg 1', 'Bern', '3001', 'Abcd1234!', 'Abcd1234!'); + cy.get('[data-cy="lastname-local-errors"]').contains('Nachname ist ein Pflichtfeld'); + }); + + it('displays error if street is missing', () => { + cy.route('POST', isEmailAvailableUrl, 'true'); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, registrationResponse.firstname, registrationResponse.lastname, '', 'Bern', '3001', 'Abcd1234!', 'Abcd1234!'); + cy.get('[data-cy="street-local-errors"]').contains('Strasse ist ein Pflichtfeld'); + }); + + it('displays error if city is missing', () => { + cy.route('POST', isEmailAvailableUrl, 'true'); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, registrationResponse.firstname, registrationResponse.lastname, 'Weg 1', '', '3001', 'Abcd1234!', 'Abcd1234!'); + cy.get('[data-cy="city-local-errors"]').contains('Ort ist ein Pflichtfeld'); + }); + + it('displays error if postcode is missing', () => { + cy.route('POST', isEmailAvailableUrl, 'true'); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, registrationResponse.firstname, registrationResponse.lastname, 'Weg 1', 'Bern', '', 'Abcd1234!', 'Abcd1234!'); + cy.get('[data-cy="postcode-local-errors"]').contains('Postleitzahl ist ein Pflichtfeld'); + }); + + it('displays error if password is missing', () => { + cy.route('POST', isEmailAvailableUrl, "true"); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, registrationResponse.firstname, registrationResponse.lastname, 'Weg 1', 'Bern', '3001', '', 'Abcd1234!'); + cy.get('[data-cy="password-local-errors"]').contains('Passwort ist ein Pflichtfeld'); + }); + + it('displays error if passwords are not secure', () => { + cy.route('POST', isEmailAvailableUrl, "true"); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, registrationResponse.firstname, registrationResponse.lastname, 'Weg 1', 'Bern', '3001', 'Abcd1234', 'Abcd1234'); + cy.get('[data-cy="password-local-errors"]').contains('Das Passwort muss Grossbuchstaben, Zahlen und Sonderzeichen beinhalten und mindestens 8 Zeichen lang sein'); + }); + + it('displays error if passwords are too short', () => { + cy.route('POST', isEmailAvailableUrl, "true"); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, registrationResponse.firstname, registrationResponse.lastname, 'Weg 1', 'Bern', '3001', 'Abcd12!', 'Abcd12!'); + cy.get('[data-cy="password-local-errors"]').contains('Das Passwort muss Grossbuchstaben, Zahlen und Sonderzeichen beinhalten und mindestens 8 Zeichen lang sein'); + }); + + it('displays error if passwords are not matching', () => { + cy.route('POST', isEmailAvailableUrl, "true"); + cy.route('POST', registerUrl, registrationResponse); + + cy.visit('/hello'); + cy.checkEmailAvailable(registrationResponse.email); + + cy.get('[data-cy="registration-title"]').contains('Damit Sie mySkillbox verwenden können, müssen Sie ein Konto erstellen.'); + cy.register(registrationResponse.gender, registrationResponse.firstname, registrationResponse.lastname, 'Weg 1', 'Bern', '3001', 'Abcd1234!', 'Abcd129999!'); + cy.get('[data-cy="passwordConfirmation-local-errors"]').contains('Die Bestätigung von Passwort wiederholen stimmt nicht überein'); + }); + + it('redirects to hello if email is missing', () => { + cy.visit('/register'); + cy.get('[data-cy="hello-title"]').contains('Wollen sie mySkillbox jetzt im Unterricht verwenden?'); + }); + +}); diff --git a/client/cypress/integration/room-page.spec.js b/client/cypress/integration/room-page.spec.js index a8206451..afc1bb75 100644 --- a/client/cypress/integration/room-page.spec.js +++ b/client/cypress/integration/room-page.spec.js @@ -3,8 +3,8 @@ describe('The Room Page', () => { // todo: mock all the graphql queries and mutations cy.viewport('macbook-15'); + cy.apolloLogin('rahel.cueni', 'test'); cy.visit('/room/ein-historisches-festival'); - cy.login('rahel.cueni', 'test'); cy.get('[data-cy=add-room-entry-button]').click(); cy.get('.add-content-element:first-of-type').click(); diff --git a/client/cypress/integration/rooms-page.spec.js b/client/cypress/integration/rooms-page.spec.js index 99604cb4..73dcb0a9 100644 --- a/client/cypress/integration/rooms-page.spec.js +++ b/client/cypress/integration/rooms-page.spec.js @@ -1,16 +1,16 @@ describe('The Rooms Page', () => { // todo: mock all the graphql queries and mutations it('goes to the rooms page', () => { + cy.apolloLogin('nico.zickgraf', 'test'); cy.visit('/rooms'); - cy.login('nico.zickgraf', 'test'); cy.get('[data-cy=add-room]').should('exist'); }); it('add room should not exist for student', () => { + cy.apolloLogin('rahel.cueni', 'test'); cy.visit('/rooms'); - cy.login('rahel.cueni', 'test'); cy.get('[data-cy=add-room]').should('not.exist'); diff --git a/client/cypress/support/commands.js b/client/cypress/support/commands.js index 208fac7e..8eb91930 100644 --- a/client/cypress/support/commands.js +++ b/client/cypress/support/commands.js @@ -29,16 +29,17 @@ // import 'cypress-graphql-mock'; import '@iam4x/cypress-graphql-mock'; + Cypress.Commands.add('apolloLogin', (username, password) => { const payload = { - 'operationName': 'Login', + 'operationName': 'BetaLogin', 'variables': { 'input': { 'usernameInput': username, 'passwordInput': password } }, - 'query': 'mutation Login($input: LoginInput!) {\n login(input: $input) {\n success\n errors {\n field\n __typename\n }\n __typename\n }\n}\n' + 'query': 'mutation BetaLogin($input: BetaLoginInput!) {\n betaLogin(input: $input) {\n success\n __typename\n }\n}\n' }; cy.request({ @@ -53,7 +54,7 @@ Cypress.Commands.add('apolloLogin', (username, password) => { // todo: replace with apollo call Cypress.Commands.add("login", (username, password, visitLogin = false) => { if (visitLogin) { - cy.visit('/login'); + cy.visit('/beta-login'); } if (username != '') { @@ -110,22 +111,53 @@ Cypress.Commands.add('changePassword', (oldPassword, newPassword) => { cy.get('[data-cy=change-password-button]').click(); }); -Cypress.Commands.add('register', (firstname, lastname, email, licenseKey) => { - if (firstname != '') { - cy.get('[data-cy=firstname-input]').type(firstname); - } - - if (lastname != '') { - cy.get('[data-cy=lastname-input]').type(lastname); - } - - if (email != '') { - cy.get('[data-cy=email-input]').type(email); - } - - if (licenseKey != '') { - cy.get('[data-cy=licenseKey-input]').type(licenseKey); - } - - cy.get('[data-cy=register-button]').click(); +Cypress.Commands.add('checkEmailAvailable', (email) => { + cy.get('[data-cy="email-input"]').type(email); + cy.get('[data-cy="hello-button"]').click(); }); + +Cypress.Commands.add('enterPassword', (password) => { + cy.get('[data-cy="password-input"]').type(password); + cy.get('[data-cy="login-button"]').click(); +}); + +Cypress.Commands.add('register', (prefix, firstname, lastname, street, city, postcode, password, passwordConfirmation) => { + + let selection = prefix === 1 ? 'Herr' : 'Frau'; + + cy.get('[data-cy="prefix-selection"]').select(selection); + + if (firstname !== '') { + cy.get('[data-cy="firstname-input"]').type(firstname); + } + if (lastname !== '') { + cy.get('[data-cy="lastname-input"]').type(lastname); + } + + if (street !== '') { + cy.get('[data-cy="street-input"]').type(street); + } + + if (city !== '') { + cy.get('[data-cy="city-input"]').type(city); + } + + if (postcode !== '') { + cy.get('[data-cy="postcode-input"]').type(postcode); + } + + if (password !== '') { + cy.get('[data-cy="password-input"]').type(password); + } + + cy.get('[data-cy="passwordConfirmation-input"]').type(passwordConfirmation); + cy.get('[data-cy="register-button"]').click(); +}); + +Cypress.Commands.add('redeemCoupon', coupon => { + if (coupon !== '') { + cy.get('[data-cy="coupon-input"]').type(coupon); + } + cy.get('[data-cy="coupon-button"]').click(); +}) + diff --git a/client/package-lock.json b/client/package-lock.json index d6e213e0..33145ffa 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -2460,7 +2460,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -2492,7 +2492,7 @@ }, "onetime": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", "dev": true }, @@ -9595,9 +9595,9 @@ } }, "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", @@ -9810,13 +9810,20 @@ } }, "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", + "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", "requires": { "glob": "~7.1.1", - "lodash": "~4.17.10", + "lodash": "~4.17.12", "minimatch": "~3.0.2" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } } }, "graceful-fs": { @@ -10425,9 +10432,9 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "in-publish": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", - "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==" }, "indent-string": { "version": "2.1.0", @@ -13334,7 +13341,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -13517,21 +13524,11 @@ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", "dev": true }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" - }, "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" - }, "lodash.create": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", @@ -13576,11 +13573,6 @@ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" }, - "lodash.mergewith": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", - "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==" - }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -14177,7 +14169,8 @@ "nan": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "optional": true }, "nanomatch": { "version": "1.2.13", @@ -14465,9 +14458,9 @@ } }, "node-sass": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.2.tgz", - "integrity": "sha512-LdxoJLZutx0aQXHtWIYwJKMj+9pTjneTcLWJgzf2XbGu0q5pRNqW5QvFCEdm3mc5rJOdru/mzln5d0EZLacf6g==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz", + "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==", "requires": { "async-foreach": "^0.1.3", "chalk": "^1.1.1", @@ -14476,20 +14469,29 @@ "get-stdin": "^4.0.1", "glob": "^7.0.3", "in-publish": "^2.0.0", - "lodash.assign": "^4.2.0", - "lodash.clonedeep": "^4.3.2", - "lodash.mergewith": "^4.6.0", + "lodash": "^4.17.15", "meow": "^3.7.0", "mkdirp": "^0.5.1", - "nan": "^2.10.0", - "node-gyp": "^3.3.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", "npmlog": "^4.0.0", - "request": "2.87.0", + "request": "^2.88.0", "sass-graph": "^2.2.4", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" }, "dependencies": { + "ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", @@ -14516,10 +14518,80 @@ "which": "^1.2.9" } }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } } } }, @@ -17151,8 +17223,7 @@ "psl": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", - "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==", - "dev": true + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" }, "public-encrypt": { "version": "4.0.2", @@ -18592,9 +18663,9 @@ "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" }, "stdout-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", - "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", "requires": { "readable-stream": "^2.0.1" } @@ -18805,12 +18876,12 @@ "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=" }, "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", "requires": { "block-stream": "*", - "fstream": "^1.0.2", + "fstream": "^1.0.12", "inherits": "2" } }, @@ -19098,25 +19169,11 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, "true-case-path": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", - "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", "requires": { - "glob": "^6.0.4" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "glob": "^7.1.2" } }, "tryer": { diff --git a/client/package.json b/client/package.json index 4f278e53..c5ce50e6 100644 --- a/client/package.json +++ b/client/package.json @@ -57,7 +57,7 @@ "lodash": "^4.17.10", "moment": "^2.24.0", "node-notifier": "^5.1.2", - "node-sass": "^4.9.2", + "node-sass": "^4.13.1", "optimize-css-assets-webpack-plugin": "^3.2.0", "ora": "^1.2.0", "portfinder": "^1.0.13", diff --git a/client/src/graphql/client.js b/client/src/graphql/client.js index 255d1d09..45a6838d 100644 --- a/client/src/graphql/client.js +++ b/client/src/graphql/client.js @@ -18,12 +18,16 @@ const writeLocalCache = cache => { sidebar: { __typename: 'Sidebar', open: false - } + }, + helloEmail: { + __typename: 'HelloEmail', + email: '' + }, } }); }; -export default function (uri) { +export default function (uri, networkErrorCallback) { const httpLink = createHttpLink({ // uri: process.env.NODE_ENV !== 'production' ? 'http://localhost:8000/api/graphql/' : '/api/graphql/', uri, @@ -58,6 +62,11 @@ export default function (uri) { }); const errorLink = onError(({response, operation, networkError, graphQLErrors}) => { + if (networkError && networkErrorCallback) { + networkErrorCallback(networkError.statusCode); + return Observable.of(); + } + if (graphQLErrors) { graphQLErrors.forEach(({message, locations, path}) => console.log( diff --git a/client/src/graphql/gql/fragments/userParts.gql b/client/src/graphql/gql/fragments/userParts.gql index befaf6f0..4724b6dd 100644 --- a/client/src/graphql/gql/fragments/userParts.gql +++ b/client/src/graphql/gql/fragments/userParts.gql @@ -7,6 +7,7 @@ fragment UserParts on UserNode { firstName lastName avatarUrl + expiryDate lastModule { id slug diff --git a/client/src/graphql/gql/local/helloEmail.gql b/client/src/graphql/gql/local/helloEmail.gql new file mode 100644 index 00000000..4a9dfe6e --- /dev/null +++ b/client/src/graphql/gql/local/helloEmail.gql @@ -0,0 +1,5 @@ +query HelloEmail { + helloEmail @client { + email + } +} diff --git a/client/src/graphql/gql/local/mutations/helloEmail.gql b/client/src/graphql/gql/local/mutations/helloEmail.gql new file mode 100644 index 00000000..b171cb1b --- /dev/null +++ b/client/src/graphql/gql/local/mutations/helloEmail.gql @@ -0,0 +1,3 @@ +mutation($helloEmail: String!) { + helloEmail(email: $helloEmail) @client +} diff --git a/client/src/graphql/gql/mutations/betaLogin.gql b/client/src/graphql/gql/mutations/betaLogin.gql new file mode 100644 index 00000000..3275f77a --- /dev/null +++ b/client/src/graphql/gql/mutations/betaLogin.gql @@ -0,0 +1,6 @@ +mutation BetaLogin($input: BetaLoginInput!) { + betaLogin(input: $input) { + success + message + } +} diff --git a/client/src/graphql/gql/mutations/login.gql b/client/src/graphql/gql/mutations/login.gql index ff107cce..c687d933 100644 --- a/client/src/graphql/gql/mutations/login.gql +++ b/client/src/graphql/gql/mutations/login.gql @@ -1,8 +1,6 @@ mutation Login($input: LoginInput!) { login(input: $input) { success - errors { - field - } + message } } diff --git a/client/src/graphql/gql/mutations/redeemCoupon.gql b/client/src/graphql/gql/mutations/redeemCoupon.gql new file mode 100644 index 00000000..1b9c7f9f --- /dev/null +++ b/client/src/graphql/gql/mutations/redeemCoupon.gql @@ -0,0 +1,5 @@ +mutation Coupon($input: CouponInput!){ + coupon(input: $input) { + success + } +} diff --git a/client/src/graphql/gql/mutations/registration.gql b/client/src/graphql/gql/mutations/registration.gql index 4a5f8367..125133a9 100644 --- a/client/src/graphql/gql/mutations/registration.gql +++ b/client/src/graphql/gql/mutations/registration.gql @@ -1,8 +1,6 @@ -mutation Registration($input: RegistrationInput!){ +mutation Registration($input: RegistrationInput!) { registration(input: $input) { success - errors { - field - } + message } } diff --git a/client/src/graphql/resolvers.js b/client/src/graphql/resolvers.js index bf816210..11cd35eb 100644 --- a/client/src/graphql/resolvers.js +++ b/client/src/graphql/resolvers.js @@ -1,4 +1,5 @@ import SCROLL_POSITION from '@/graphql/gql/local/scrollPosition.gql'; +import HELLO_EMAIL from '@/graphql/gql/local/helloEmail.gql'; import SIDEBAR from '@/graphql/gql/local/sidebar.gql'; export const resolvers = { @@ -9,6 +10,12 @@ export const resolvers = { cache.writeQuery({query: SCROLL_POSITION, data}); return data.scrollPosition; }, + helloEmail: (_, {email}, {cache}) => { + const data = cache.readQuery({query: HELLO_EMAIL}); + data.helloEmail.email = email; + cache.writeQuery({query: HELLO_EMAIL, data}); + return data.helloEmail; + }, toggleSidebar: (_, {open}, {cache}) => { const data = cache.readQuery({query: SIDEBAR}); data.sidebar.open = open; diff --git a/client/src/graphql/typedefs.js b/client/src/graphql/typedefs.js index acd05f0c..c17dd4a3 100644 --- a/client/src/graphql/typedefs.js +++ b/client/src/graphql/typedefs.js @@ -1,15 +1,24 @@ import gql from 'graphql-tag'; export const typeDefs = gql` - type ScrollPosition { + type ScrollPosition { scrollTo: String! } - - type Sidebar { + + type HelloEmail { + email: String! + } + + + type Sidebar { open: Boolean! } - + type Mutation { scrollTo(scrollTo: String!): ScrollPosition } + + type Mutation { + helloEmail(email: String!): HelloEmail + } `; diff --git a/client/src/hep-client/index.js b/client/src/hep-client/index.js new file mode 100644 index 00000000..a26cc268 --- /dev/null +++ b/client/src/hep-client/index.js @@ -0,0 +1,18 @@ +import * as axios from 'axios' + +const hepBaseUrl = process.env.HEP_URL; + +export function register(registrationData) { + return axios.post('/api/proxy/registration/', registrationData); +} + +export function login(username, password) { + return axios.post(`${hepBaseUrl}/rest/deutsch/V1/integration/customer/token`, {username, password}); +} + +export function emailExists(email) { + return axios.post(`${hepBaseUrl}/rest/deutsch/V1/customers/isEmailAvailable`, { + customerEmail: email, + websiteId: 1 + }); +} diff --git a/client/src/layouts/PublicLayout.vue b/client/src/layouts/PublicLayout.vue index d42d53df..a2b2c82c 100644 --- a/client/src/layouts/PublicLayout.vue +++ b/client/src/layouts/PublicLayout.vue @@ -1,17 +1,22 @@ - @@ -20,17 +25,46 @@ import Logo from '@/components/icons/Logo'; @import "@/styles/_mixins.scss"; @import "@/styles/_default-layout.scss"; - .public { + @mixin content-block { + padding-right: $medium-spacing; + padding-left: $medium-spacing; max-width: 800px; min-width: 320px; - padding-top: 4*$large-spacing; + width: 100%; + margin: 0 auto; + } + + .logo { + position: relative; + + width: 260px; + height: 43px; + } + + .public { + grid-template-areas: "h" "c" "f"; + + &__content { + @include content-block(); + margin-bottom: $large-spacing; + } &__logo { - position: relative; + @include content-block(); + margin-top: $medium-spacing + } - width: 260px; - height: 43px; + &__footer { + background-color: $color-silver-light; + display: block; } } + .footer { + padding-top: $large-spacing; + + &__content { + @include content-block(); + } + } diff --git a/client/src/main.js b/client/src/main.js index 123f1a2e..5e71d707 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -10,7 +10,7 @@ import router from './router' import store from '@/store/index' import VueScrollTo from 'vue-scrollto'; import {Validator, install as VeeValidate} from 'vee-validate/dist/vee-validate.minimal.esm.js'; -import {required, min} from 'vee-validate/dist/rules.esm.js'; +import {required, min, decimal, confirmed} from 'vee-validate/dist/rules.esm.js'; import veeDe from 'vee-validate/dist/locale/de'; import {dateFilter} from './filters/date-filter'; import autoGrow from '@/directives/auto-grow' @@ -45,8 +45,8 @@ if (process.env.MATOMO_HOST) { Vue.directive('click-outside', clickOutside); Vue.directive('auto-grow', autoGrow); -const publicApolloClient = apolloClientFactory('/api/graphql-public/'); -const privateApolloClient = apolloClientFactory('/api/graphql/'); +const publicApolloClient = apolloClientFactory('/api/graphql-public/', null); +const privateApolloClient = apolloClientFactory('/api/graphql/', networkErrorCallback); const apolloProvider = new VueApollo({ clients: { @@ -57,6 +57,8 @@ const apolloProvider = new VueApollo({ Validator.extend('required', required); Validator.extend('min', min); +Validator.extend('decimal', decimal); +Validator.extend('confirmed', confirmed); const dict = { custom: { @@ -72,9 +74,10 @@ const dict = { Validator.localize('de', veeDe) Validator.localize('de', dict) + // https://github.com/baianat/vee-validate/issues/51 Validator.extend('strongPassword', { - getMessage: field => 'Das Passwort muss Grossbuchstaben, Zahlen und Sonderzeichen beinhalten', + getMessage: field => 'Das Passwort muss Grossbuchstaben, Zahlen und Sonderzeichen beinhalten und mindestens 8 Zeichen lang sein', validate: value => { const strongRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*?(),.":{}|<>+])(?=.{8,})/; return strongRegex.test(value); @@ -112,28 +115,43 @@ function unauthorizedAccess(to) { return loginRequired(to) && getCookieValue('loginStatus') !== 'true'; } +function redirectUsersWithoutValidLicense(to) { + return privateApolloClient.query({ + query: ME_QUERY, + }).then(({data}) => data.me.expiryDate == null); +} + function redirectStudentsWithoutClass() { return privateApolloClient.query({ query: ME_QUERY, }).then(({data}) => data.me.schoolClasses.edges.length === 0 && data.me.permissions.length === 0); } +function networkErrorCallback(statusCode) { + if (statusCode === 402) { + router.push({name: 'licenseActivation'}, 0); + } +} + router.beforeEach(async (to, from, next) => { - // handle logout if (to.path === '/logout') { - privateApolloClient.resetStore(); publicApolloClient.resetStore(); - next({name: 'login'}); + next({name: 'hello'}); return } if (unauthorizedAccess(to)) { - const redirectUrl = `/login?redirect=${to.path}`; + const redirectUrl = `/hello?redirect=${to.path}`; next(redirectUrl); - return + return; } - if (to.name !== 'join-class' && loginRequired(to) && await redirectStudentsWithoutClass()) { + if (to.name !== 'licenseActivation' && loginRequired(to) && await redirectUsersWithoutValidLicense()) { + next({name: 'licenseActivation'}) + return; + } + + if ((to.name !== 'join-class' && to.name !== 'licenseActivation') && loginRequired(to) && await redirectStudentsWithoutClass()) { next({name: 'join-class'}) return } diff --git a/client/src/pages/beta-login.vue b/client/src/pages/beta-login.vue new file mode 100644 index 00000000..56559ec1 --- /dev/null +++ b/client/src/pages/beta-login.vue @@ -0,0 +1,169 @@ + + + + + diff --git a/client/src/pages/check-email.vue b/client/src/pages/check-email.vue new file mode 100644 index 00000000..03211c62 --- /dev/null +++ b/client/src/pages/check-email.vue @@ -0,0 +1,17 @@ + + + diff --git a/client/src/pages/email-verification.vue b/client/src/pages/email-verification.vue new file mode 100644 index 00000000..7550cefb --- /dev/null +++ b/client/src/pages/email-verification.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/client/src/pages/forgot-password.vue b/client/src/pages/forgot-password.vue new file mode 100644 index 00000000..981712fb --- /dev/null +++ b/client/src/pages/forgot-password.vue @@ -0,0 +1,33 @@ + + + diff --git a/client/src/pages/hello.vue b/client/src/pages/hello.vue new file mode 100644 index 00000000..3523ec92 --- /dev/null +++ b/client/src/pages/hello.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/client/src/pages/joinClass.vue b/client/src/pages/joinClass.vue index bbacf9d0..a7709cbb 100644 --- a/client/src/pages/joinClass.vue +++ b/client/src/pages/joinClass.vue @@ -21,7 +21,7 @@
Klasse beitreten - Abbrechen +
@@ -31,6 +31,7 @@ + + diff --git a/client/src/pages/login.vue b/client/src/pages/login.vue index 47860638..f9fb8dbd 100644 --- a/client/src/pages/login.vue +++ b/client/src/pages/login.vue @@ -1,33 +1,10 @@ @@ -147,10 +153,20 @@ export default { } .actions { + display: flex; &__reset { display: inline-block; - margin-left: $large-spacing; + margin-left: auto; + line-height: 19px;; + display: inline-block; + padding: $small-spacing; } } +.back-button { + font-size: 1rem; + line-height: normal; + margin-left: $medium-spacing; +} + diff --git a/client/src/pages/registration.vue b/client/src/pages/registration.vue index 7ff3d1b8..bcdaa8a9 100644 --- a/client/src/pages/registration.vue +++ b/client/src/pages/registration.vue @@ -1,8 +1,28 @@ diff --git a/client/src/pages/start.vue b/client/src/pages/start.vue index 32ae16aa..3f00ccf9 100644 --- a/client/src/pages/start.vue +++ b/client/src/pages/start.vue @@ -20,6 +20,7 @@ class="start-sections__section" title="Räume" subtitle="Beiträge mit der Klasse teilen" + data-cy="rooms-link" link-text="Alle Räume anzeigen" route="/rooms" > diff --git a/client/src/pages/waitForClass.vue b/client/src/pages/waitForClass.vue deleted file mode 100644 index 7531fe01..00000000 --- a/client/src/pages/waitForClass.vue +++ /dev/null @@ -1,31 +0,0 @@ - - - - diff --git a/client/src/router/index.js b/client/src/router/index.js index 64c777d4..44214e50 100644 --- a/client/src/router/index.js +++ b/client/src/router/index.js @@ -28,8 +28,13 @@ import surveyPage from '@/pages/survey' import styleGuidePage from '@/pages/styleguide' import moduleRoom from '@/pages/moduleRoom' import login from '@/pages/login' +import betaLogin from '@/pages/beta-login' +import hello from '@/pages/hello' import registration from '@/pages/registration' -import waitForClass from '@/pages/waitForClass' +import checkEmail from '@/pages/check-email' +import emailVerification from '@/pages/email-verification' +import licenseActivation from '@/pages/license-activation' +import forgotPassword from '@/pages/forgot-password' import joinClass from '@/pages/joinClass' import oldClasses from '@/pages/oldClasses'; import createClass from '@/pages/createClass'; @@ -53,6 +58,24 @@ const routes = [ public: true } }, + { + path: '/hello', + name: 'hello', + component: hello, + meta: { + layout: 'public', + public: true + } + }, + { + path: '/beta-login', + name: 'betaLogin', + component: betaLogin, + meta: { + layout: 'public', + public: true + } + }, { path: '/module/:slug', component: moduleBase, @@ -124,7 +147,7 @@ const routes = [ {path: 'show-code', name: 'show-code', component: showCode, meta: {layout: 'simple'}}, ] }, - {path: 'join-class', name: 'join-class', component: joinClass, meta: {layout: 'simple'}}, + {path: 'join-class', name: 'join-class', component: joinClass, meta: {layout: 'public'}}, { path: '/survey/:id', component: surveyPage, @@ -142,10 +165,39 @@ const routes = [ } }, { - path: '/no-class', - component: waitForClass, - name: 'noClass', - meta: {layout: 'public'} + path: '/check-email', + component: checkEmail, + name: 'checkEmail', + meta: { + public: true, + layout: 'public' + } + }, + { + path: '/verify-email', + component: emailVerification, + name: 'emailVerification', + meta: { + public: true, + layout: 'public' + } + }, + { + path: '/license-activation', + component: licenseActivation, + name: 'licenseActivation', + meta: { + layout: 'public' + } + }, + { + path: '/forgot-password', + component: forgotPassword, + name: 'forgotPassword', + meta: { + layout: 'public', + public: true + } }, {path: '/styleguide', component: styleGuidePage}, {path: '*', component: p404} diff --git a/client/src/styles/_info-header.scss b/client/src/styles/_info-header.scss new file mode 100644 index 00000000..145162ba --- /dev/null +++ b/client/src/styles/_info-header.scss @@ -0,0 +1,13 @@ +.info-header { + margin-top: $large-spacing; + margin-bottom: $large-spacing; + + &__text { + font-family: $sans-serif-font-family; + } + + &__emph { + color: $color-brand; + font-weight: 600; + } +} diff --git a/client/src/styles/_mixins.scss b/client/src/styles/_mixins.scss index 1df1b9eb..9f4e1589 100644 --- a/client/src/styles/_mixins.scss +++ b/client/src/styles/_mixins.scss @@ -176,3 +176,12 @@ @mixin popover-defaults() { bottom: $popover-default-bottom; } + +@mixin content-block { + padding-right: $medium-spacing; + padding-left: $medium-spacing; + max-width: 800px; + min-width: 320px; + width: 100%; + margin: 0 auto; +} diff --git a/client/src/styles/_password_forms.scss b/client/src/styles/_password_forms.scss index 3159ff7a..d7b4a076 100644 --- a/client/src/styles/_password_forms.scss +++ b/client/src/styles/_password_forms.scss @@ -6,6 +6,7 @@ &__label { margin-bottom: 10px; display: inline-block; + font-weight: 600; } &__input { diff --git a/client/src/styles/_typography.scss b/client/src/styles/_typography.scss index a13ac756..e6a43a5a 100644 --- a/client/src/styles/_typography.scss +++ b/client/src/styles/_typography.scss @@ -75,3 +75,8 @@ input, textarea, select, button { .inline-title { @include inline-title; } + +.hep-link { + font-family: $sans-serif-font-family; + color: $color-brand-dark; +} diff --git a/client/src/styles/main.scss b/client/src/styles/main.scss index 9493d8dd..84f3bb6a 100644 --- a/client/src/styles/main.scss +++ b/client/src/styles/main.scss @@ -22,6 +22,7 @@ @import "public-page"; @import "student-submission"; @import "module-activity"; +@import "info-header"; @import "book-subnavigation"; @import "simple-list"; @import "widget-popover"; diff --git a/client/vue.config.js b/client/vue.config.js index adb5f4c4..0249610b 100644 --- a/client/vue.config.js +++ b/client/vue.config.js @@ -8,5 +8,5 @@ module.exports = { ` } } - } + }, }; diff --git a/server/api/schema.py b/server/api/schema.py index 85fb202f..afd53d37 100644 --- a/server/api/schema.py +++ b/server/api/schema.py @@ -10,6 +10,7 @@ from assignments.schema.queries import AssignmentsQuery, StudentSubmissionQuery from basicknowledge.queries import BasicKnowledgeQuery from books.schema.mutations.main import BookMutations from books.schema.queries import BookQuery +from core.schema.mutations.coupon import CouponMutations from core.schema.mutations.main import CoreMutations from notes.mutations import NoteMutations from objectives.mutations import ObjectiveMutations @@ -36,7 +37,7 @@ class Query(UsersQuery, AllUsersQuery, ModuleRoomsQuery, RoomsQuery, ObjectivesQ class Mutation(BookMutations, RoomMutations, AssignmentMutations, ObjectiveMutations, CoreMutations, PortfolioMutations, ProfileMutations, SurveyMutations, NoteMutations, RegistrationMutations, SpellCheckMutations, - graphene.ObjectType): + CouponMutations, graphene.ObjectType): if settings.DEBUG: debug = graphene.Field(DjangoDebug, name='_debug') diff --git a/server/api/schema_public.py b/server/api/schema_public.py index e2d91f72..1f643dae 100644 --- a/server/api/schema_public.py +++ b/server/api/schema_public.py @@ -12,4 +12,16 @@ class Mutation(UserMutations, RegistrationMutations, graphene.ObjectType): debug = graphene.Field(DjangoDebug, name='__debug') -schema = graphene.Schema(mutation=Mutation) +# graphene neets some kind of schema in order to create a schema +class DummyQuery(object): + meaning_of_life = graphene.Int() + + def resolve_meaning_of_life(self, info, **kwargs): + return 42 + + +class Query(DummyQuery, graphene.ObjectType): + pass + + +schema = graphene.Schema(mutation=Mutation, query=Query) diff --git a/server/api/urls.py b/server/api/urls.py index 69beea15..000ed89e 100644 --- a/server/api/urls.py +++ b/server/api/urls.py @@ -1,21 +1,26 @@ from django.conf import settings from django.conf.urls import url +from django.urls import include from django.views.decorators.csrf import csrf_exempt from graphene_django.views import GraphQLView from api.schema_public import schema -from core.views import PrivateGraphQLView +from core.views import PrivateGraphQLView, ConfirmationKeyDisplayView app_name = 'api' urlpatterns = [ url(r'^graphql-public', csrf_exempt(GraphQLView.as_view(schema=schema))), url(r'^graphql', csrf_exempt(PrivateGraphQLView.as_view())), + + # hep proxy + url(r'^proxy/', include('registration.urls', namespace="registration")), ] if settings.DEBUG: urlpatterns += [url(r'^graphiql-public', csrf_exempt(GraphQLView.as_view(schema=schema, graphiql=True, pretty=True)))] urlpatterns += [url(r'^graphiql', csrf_exempt(PrivateGraphQLView.as_view(graphiql=True, pretty=True)))] + urlpatterns += [url(r'^confirmation', ConfirmationKeyDisplayView.as_view(), name='confirmation_key_display')] diff --git a/server/core/hep_client.py b/server/core/hep_client.py new file mode 100644 index 00000000..0b14170f --- /dev/null +++ b/server/core/hep_client.py @@ -0,0 +1,228 @@ +from datetime import datetime, timedelta + +from django.conf import settings +import logging +import requests + +logger = logging.getLogger(__name__) + +TEACHER_EDITION_DURATION = 365 +STUDENT_EDITION_DURATION = 4*365 + +TEACHER_KEY = 'teacher' +STUDENT_KEY = 'student' + +MYSKILLBOX_TEACHER_EDITION_ISBN = "978-3-0355-1823-8" +MYSKILLBOX_STUDENT_EDITION_ISBN = "978-3-0355-1397-4" + + +class HepClientException(Exception): + pass + + +class HepClientUnauthorizedException(Exception): + pass + + +class HepClient: + URL = settings.HEP_URL + WEBSITE_ID = 1 + HEADERS = { + 'accept': 'application/json', + 'content-type': 'application/json' + } + + def _call(self, url, method='get', data=None, additional_headers=None): + + request_url = f'{self.URL}{url}' + + if additional_headers: + headers = {**additional_headers, **self.HEADERS} + else: + headers = self.HEADERS + + if method == 'post': + response = requests.post(request_url, json=data, headers=headers) + elif method == 'get': + if data: + response = requests.get(request_url, headers=headers, data=data) + else: + response = requests.get(request_url, headers=headers) + elif method == 'put': + response = requests.put(request_url, data=data) + + # Todo handle 401 and most important network errors + if response.status_code == 401: + raise HepClientUnauthorizedException(response.status_code, response.json()) + elif response.status_code != 200: + raise HepClientException(response.status_code, response.json()) + + return response + + def fetch_admin_token(self, admin_user, password): + response = self._call('/rest/deutsch/V1/integration/admin/token', 'post', + data={'username': admin_user, 'password': password}) + return response.content.decode('utf-8')[1:-1] + + def is_email_available(self, email): + response = self._call('/rest/deutsch/V1/customers/isEmailAvailable', method='post', + data={'customerEmail': email, 'websiteId': self.WEBSITE_ID}) + return response.json() + + def is_email_verified(self, user_data): + return 'confirmation' not in user_data + + def customer_verify_email(self, confirmation_key): + response = self._call('/rest/V1/customers/me', method='put', data={'confirmationKey': confirmation_key}) + return response.json() + + def customer_create(self, customer_data): + response = self._call('/rest/deutsch/V1/customers', method='post', data=customer_data) + return response.json() + + def customer_token(self, username, password): + response = self._call('/rest/deutsch/V1/integration/customer/token', 'post', + data={'username': username, 'password': password}) + return response.json() + + def customer_me(self, token): + response = self._call('/rest/V1/customers/me', additional_headers={'authorization': f'Bearer {token}'}) + return response.json() + + def customer_activate(self, confirmation_key, user_id): + response = self._call(f'/customer/account/confirm/?back_url=&id={user_id}&key={confirmation_key}', method='get') + return response + + def customers_search(self, admin_token, email): + response = self._call('/rest/V1/customers/search?searchCriteria[filterGroups][0][filters][0][field]=' + f'email&searchCriteria[filterGroups][0][filters][0][value]={email}', + additional_headers={'authorization': f'Bearer {admin_token}'}) + + json_data = response.json() + if len(json_data['items']) > 0: + return json_data['items'][0] + return None + + def customers_by_id(self, admin_token, user_id): + response = self._call('/rest/V1/customers/{}'.format(user_id), + additional_headers={'authorization': f'Bearer {admin_token}'}) + return response.json() + + def _customer_orders(self, admin_token, customer_id): + url = ('/rest/V1/orders/?searchCriteria[filterGroups][0][filters][0][' + f'field]=customer_id&searchCriteria[filterGroups][0][filters][0][value]={customer_id}') + + response = self._call(url, additional_headers={'authorization': 'Bearer {}'.format(admin_token)}) + return response.json() + + def coupon_redeem(self, coupon, customer_id): + try: + response = self._call(f'/rest/deutsch/V1/coupon/{coupon}/customer/{customer_id}', method='put') + except HepClientException: + return None + + response_data = response.json() + if response_data[0] == '201': + return None + + return response_data[0] + + def myskillbox_product_for_customer(self, admin_token, customer_id): + orders = self._customer_orders(admin_token, customer_id) + products = self._extract_myskillbox_products(orders) + + if len(products) == 0: + return None + else: + return self._get_relevant_product(products) + + def _extract_myskillbox_products(self, orders): + products = [] + + for order_item in orders['items']: + + status = '' + if 'status' in order_item: + status = order_item['status'] + + for item in order_item['items']: + + order_id = -1 + if 'order_id' in item: + order_id = item['order_id'] + + if item['sku'] == MYSKILLBOX_TEACHER_EDITION_ISBN or \ + item['sku'] == MYSKILLBOX_STUDENT_EDITION_ISBN: + + product = { + 'raw': item, + 'activated': self._get_item_activation(order_item), + 'status': status, + 'order_id': order_id + } + + if item['sku'] == MYSKILLBOX_TEACHER_EDITION_ISBN: + product['edition'] = TEACHER_KEY + + else: + product['edition'] = STUDENT_KEY + + products.append(product) + + return products + + def _get_item_activation(self, item): + if 'created_at' in item: + return datetime.strptime(item['created_at'], '%Y-%m-%d %H:%M:%S') + + def _get_relevant_product(self, products): + + def filter_valid_products(product): + + if product['status'] != 'complete': + return False + + if product['edition'] == TEACHER_KEY: + expiry_delta = product['activated'] + timedelta(TEACHER_EDITION_DURATION) + else: + expiry_delta = product['activated'] + timedelta(STUDENT_EDITION_DURATION) + + if HepClient.is_product_active(expiry_delta, product['edition']): + return True + else: + return False + + active_products = list(filter(filter_valid_products, products)) + + if len(active_products) == 0: + return None + elif len(active_products) == 1: + return active_products[0] + else: + return self._select_from_teacher_products(active_products) + + def _select_from_teacher_products(self, active_products): + teacher_edition = None + + # select first teacher product, as they are all valid it does not matter which one + for product in active_products: + if product['edition'] == TEACHER_KEY: + teacher_edition = product + break + + # select a student product, as they are all valid it does not matter which one + if not teacher_edition: + return active_products[0] + + return teacher_edition + + @staticmethod + def is_product_active(expiry_date, edition): + if edition == TEACHER_KEY: + duration = TEACHER_EDITION_DURATION + else: + duration = STUDENT_EDITION_DURATION + + now = datetime.now() + + return expiry_date >= now >= expiry_date - timedelta(days=duration) diff --git a/server/core/management/commands/dummy_data.py b/server/core/management/commands/dummy_data.py index 501f03a8..fee625f8 100644 --- a/server/core/management/commands/dummy_data.py +++ b/server/core/management/commands/dummy_data.py @@ -113,5 +113,3 @@ class Command(BaseCommand): # now create all and rooms management.call_command('dummy_rooms', verbosity=0) - # create license - management.call_command('create_dummy_license', verbosity=0) diff --git a/server/core/management/commands/export_schema_for_cypress.py b/server/core/management/commands/export_schema_for_cypress.py index 095b08e2..7ed49d83 100644 --- a/server/core/management/commands/export_schema_for_cypress.py +++ b/server/core/management/commands/export_schema_for_cypress.py @@ -7,9 +7,23 @@ import os class Command(BaseCommand): def handle(self, *args, **options): - filename = 'schema.json' + schemas = [ + { + 'filename': 'schema.json', + 'schema': 'api.schema.schema' + }, + { + 'filename': 'schema_public.json', + 'schema': 'api.schema_public.schema' + } + ] + + for schema in schemas: + self.create_schema(schema['filename'], schema['schema']) + + def create_schema(self, filename, schema): cypress_path = os.path.join(settings.BASE_DIR, '..', 'client', 'cypress', 'fixtures', filename) - call_command('graphql_schema', schema='api.schema.schema', out=filename, indent=4) + call_command('graphql_schema', schema=schema, out=filename, indent=4) with open(filename) as f: initial_json = json.loads(f.read()) diff --git a/server/core/management/commands/update_admin_token.py b/server/core/management/commands/update_admin_token.py new file mode 100644 index 00000000..94902889 --- /dev/null +++ b/server/core/management/commands/update_admin_token.py @@ -0,0 +1,14 @@ +import os +import shutil + +from django.core.management import BaseCommand + +from core.models import AdminData + + +class Command(BaseCommand): + + def handle(self, *args, **options): + "Update admin token via cronjob" + AdminData.objects.update_admin_token() + diff --git a/server/core/managers.py b/server/core/managers.py new file mode 100644 index 00000000..c9b20303 --- /dev/null +++ b/server/core/managers.py @@ -0,0 +1,30 @@ +from django.conf import settings +from django.db import models +from datetime import timedelta +from django.utils import timezone + +from core.hep_client import HepClient + +DEFAULT_PK = 1 + + +class AdminDataManager(models.Manager): + hep_client = HepClient() + + def update_admin_token(self): + admin_token = self.hep_client.fetch_admin_token(settings.HEP_ADMIN_USER, settings.HEP_ADMIN_PASSWORD) + + admin_data, created = self.get_or_create(pk=DEFAULT_PK) + admin_data.hep_admin_token = admin_token + admin_data.save() + return admin_data.hep_admin_token + + def get_admin_token(self): + try: + admin_token = self.get(pk=DEFAULT_PK) + if admin_token.updated_at < timezone.now() + timedelta(hours=1): + admin_token = self.update_admin_token() + except self.model.DoesNotExist: + admin_token = self.update_admin_token() + + return admin_token diff --git a/server/core/middleware.py b/server/core/middleware.py index c0b362c5..3d3752c5 100644 --- a/server/core/middleware.py +++ b/server/core/middleware.py @@ -1,10 +1,13 @@ +import json import re from django.conf import settings -from django.http import Http404, HttpResponsePermanentRedirect +from django.http import Http404, HttpResponsePermanentRedirect, HttpResponse from django.shortcuts import redirect from django.utils.deprecation import MiddlewareMixin +from core.utils import is_private_api_call_allowed + try: from threading import local except ImportError: @@ -95,3 +98,13 @@ class UserLoggedInCookieMiddleWare(MiddlewareMixin): #else if if no user and cookie remove user cookie, logout response.delete_cookie(self.cookie_name) return response + + +class UserHasLicenseMiddleWare(MiddlewareMixin): + + def process_response(self, request, response): + if request.path == '/api/graphql/': + if not is_private_api_call_allowed(request.user, request.body): + return HttpResponse(json.dumps({'errors': ['no active license']}), status=402) + + return response diff --git a/server/core/migrations/0001_initial.py b/server/core/migrations/0001_initial.py new file mode 100644 index 00000000..6be51120 --- /dev/null +++ b/server/core/migrations/0001_initial.py @@ -0,0 +1,22 @@ +# Generated by Django 2.0.6 on 2020-02-05 13:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='AdminData', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('hep_admin_token', models.CharField(max_length=100)), + ('updated_at', models.DateTimeField(auto_now=True, null=True)), + ], + ), + ] diff --git a/server/core/migrations/__init__.py b/server/core/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/core/models.py b/server/core/models.py new file mode 100644 index 00000000..70d41d26 --- /dev/null +++ b/server/core/models.py @@ -0,0 +1,12 @@ +from datetime import datetime + +from django.db import models + +from core.managers import AdminDataManager + + +class AdminData(models.Model): + hep_admin_token = models.CharField(max_length=100, blank=False, null=False) + updated_at = models.DateTimeField(blank=False, null=True, auto_now=True) + + objects = AdminDataManager() diff --git a/server/core/schema/mutations/coupon.py b/server/core/schema/mutations/coupon.py new file mode 100644 index 00000000..ab309cd8 --- /dev/null +++ b/server/core/schema/mutations/coupon.py @@ -0,0 +1,44 @@ +import graphene +from graphene import relay + +from core.hep_client import HepClient, HepClientException +from users.user_signup_login_handler import check_and_create_licenses, create_role_for_user + + +class Coupon(relay.ClientIDMutation): + class Input: + coupon_code = graphene.String() + + success = graphene.Boolean() + + @classmethod + def mutate_and_get_payload(cls, root, info, **kwargs): + coupon_code = kwargs.get('coupon_code').strip() + hep_client = HepClient() + + try: + hep_id = info.context.user.hep_id + except AttributeError: + raise Exception('not_authenticated') + + try: + response = hep_client.coupon_redeem(coupon_code, hep_id) + except HepClientException: + raise Exception('unknown_error') + + if not response: + raise Exception('invalid_coupon') + + license, error_msg = check_and_create_licenses(hep_client, info.context.user) + + # todo fail if no license + if error_msg: + raise Exception(error_msg) + + create_role_for_user(info.context.user, license.for_role.key) + + return cls(success=True) + + +class CouponMutations: + redeem_coupon = Coupon.Field() diff --git a/server/core/schema/mutations/main.py b/server/core/schema/mutations/main.py index b87afabe..ea0140c7 100644 --- a/server/core/schema/mutations/main.py +++ b/server/core/schema/mutations/main.py @@ -7,8 +7,10 @@ # # Created on 22.10.18 # @author: chrigu +from core.schema.mutations.coupon import Coupon from core.schema.mutations.logout import Logout class CoreMutations(object): logout = Logout.Field() + coupon = Coupon.Field() diff --git a/server/core/settings.py b/server/core/settings.py index edce4155..d96c84d3 100644 --- a/server/core/settings.py +++ b/server/core/settings.py @@ -126,6 +126,7 @@ MIDDLEWARE += [ 'core.middleware.ThreadLocalMiddleware', 'core.middleware.CommonRedirectMiddleware', 'core.middleware.UserLoggedInCookieMiddleWare', + 'core.middleware.UserHasLicenseMiddleWare', ] ROOT_URLCONF = 'core.urls' @@ -380,6 +381,12 @@ EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER") EMAIL_USE_TLS = True EMAIL_USE_SSL = False +ALLOW_BETA_LOGIN = True + +# HEP +HEP_ADMIN_USER = os.environ.get("HEP_ADMIN_USER") +HEP_ADMIN_PASSWORD = os.environ.get("HEP_ADMIN_PASSWORD") +HEP_URL = os.environ.get("HEP_URL") TASKBASE_USER = os.environ.get("TASKBASE_USER") TASKBASE_PASSWORD = os.environ.get("TASKBASE_PASSWORD") @@ -391,3 +398,4 @@ TASKBASE_BASEURL = os.environ.get("TASKBASE_BASEURL") TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner' TEST_OUTPUT_DIR = './test-reports/' TEST_OUTPUT_VERBOSE = 1 + diff --git a/server/core/settings_test.py b/server/core/settings_test.py index d7fef8b6..904154df 100644 --- a/server/core/settings_test.py +++ b/server/core/settings_test.py @@ -15,3 +15,5 @@ MIGRATION_MODULES = DisableMigrations() SENDGRID_API_KEY = "" EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' LOGIN_REDIRECT_URL = '/accounts/login/' + +USE_LOCAL_REGISTRATION = False diff --git a/server/core/templates/confirmation_key.html b/server/core/templates/confirmation_key.html new file mode 100644 index 00000000..d5209f7a --- /dev/null +++ b/server/core/templates/confirmation_key.html @@ -0,0 +1,10 @@ + + + + + Confirmation + + + Email bestätitgen + + diff --git a/server/core/tests/mock_data/email_not_confirmed_me.json b/server/core/tests/mock_data/email_not_confirmed_me.json new file mode 100644 index 00000000..d9590f6b --- /dev/null +++ b/server/core/tests/mock_data/email_not_confirmed_me.json @@ -0,0 +1,41 @@ +{ + "id": 49124, + "group_id": 1, + "default_billing": "47579", + "default_shipping": "47579", + "confirmation": "41b58ba6598a618095e8c70625d7f052", + "created_at": "2018-07-19 15:05:27", + "updated_at": "2019-11-26 17:04:29", + "created_in": "hep verlag", + "email": "1heptest19072018@mailinator.com", + "firstname": "Test", + "lastname": "Test", + "prefix": "Frau", + "gender": 2, + "store_id": 1, + "website_id": 1, + "addresses": [ + { + "id": 47579, + "customer_id": 49124, + "region": { + "region_code": null, + "region": null, + "region_id": 0 + }, + "region_id": 0, + "country_id": "CH", + "street": [ + "Test" + ], + "telephone": "", + "postcode": "0000", + "city": "Test", + "firstname": "Test", + "lastname": "Test", + "prefix": "Frau", + "default_shipping": true, + "default_billing": true + } + ] +} diff --git a/server/core/tests/mock_data/me_data.json b/server/core/tests/mock_data/me_data.json new file mode 100644 index 00000000..111c8d94 --- /dev/null +++ b/server/core/tests/mock_data/me_data.json @@ -0,0 +1,40 @@ +{ + "id": 49124, + "group_id": 1, + "default_billing": "47579", + "default_shipping": "47579", + "created_at": "2018-07-19 15:05:27", + "updated_at": "2019-11-26 17:04:29", + "created_in": "hep verlag", + "email": "1heptest19072018@mailinator.com", + "firstname": "Test", + "lastname": "Test", + "prefix": "Frau", + "gender": 2, + "store_id": 1, + "website_id": 1, + "addresses": [ + { + "id": 47579, + "customer_id": 49124, + "region": { + "region_code": null, + "region": null, + "region_id": 0 + }, + "region_id": 0, + "country_id": "CH", + "street": [ + "Test" + ], + "telephone": "", + "postcode": "0000", + "city": "Test", + "firstname": "Test", + "lastname": "Test", + "prefix": "Frau", + "default_shipping": true, + "default_billing": true + } + ] +} diff --git a/server/core/tests/mock_data/valid_student_orders.json b/server/core/tests/mock_data/valid_student_orders.json new file mode 100644 index 00000000..397d1a06 --- /dev/null +++ b/server/core/tests/mock_data/valid_student_orders.json @@ -0,0 +1,526 @@ +{ + "items": [ + { + "base_currency_code": "CHF", + "base_discount_amount": 0, + "base_grand_total": 46, + "base_discount_tax_compensation_amount": 0, + "base_shipping_amount": 0, + "base_shipping_discount_amount": 0, + "base_shipping_incl_tax": 0, + "base_shipping_tax_amount": 0, + "base_subtotal": 44.88, + "base_subtotal_incl_tax": 46, + "base_tax_amount": 1.12, + "base_total_due": 46, + "base_to_global_rate": 1, + "base_to_order_rate": 1, + "billing_address_id": 83693, + "created_at": "2018-07-19 15:05:33", + "customer_email": "1heptest19072018@mailinator.com", + "customer_firstname": "Test", + "customer_gender": 2, + "customer_group_id": 4, + "customer_id": 49124, + "customer_is_guest": 0, + "customer_lastname": "Test", + "customer_note": "coupon", + "customer_note_notify": 1, + "customer_prefix": "Frau", + "discount_amount": 0, + "email_sent": 1, + "entity_id": 57612, + "global_currency_code": "CHF", + "grand_total": 46, + "discount_tax_compensation_amount": 0, + "increment_id": "1004614768", + "is_virtual": 1, + "order_currency_code": "CHF", + "protect_code": "71aedb", + "quote_id": 104401, + "shipping_amount": 0, + "shipping_discount_amount": 0, + "shipping_discount_tax_compensation_amount": 0, + "shipping_incl_tax": 0, + "shipping_tax_amount": 0, + "state": "complete", + "status": "complete", + "store_currency_code": "CHF", + "store_id": 1, + "store_name": "hep verlag\nhep verlag\nhep verlag", + "store_to_base_rate": 0, + "store_to_order_rate": 0, + "subtotal": 44.88, + "subtotal_incl_tax": 46, + "tax_amount": 1.12, + "total_due": 46, + "total_item_count": 1, + "total_qty_ordered": 1, + "updated_at": "2018-07-19 15:05:33", + "weight": 0, + "items": [ + { + "amount_refunded": 0, + "base_amount_refunded": 0, + "base_discount_amount": 0, + "base_discount_invoiced": 0, + "base_discount_tax_compensation_amount": 0, + "base_original_price": 46, + "base_price": 44.88, + "base_price_incl_tax": 46, + "base_row_invoiced": 0, + "base_row_total": 44.88, + "base_row_total_incl_tax": 46, + "base_tax_amount": 1.12, + "base_tax_invoiced": 0, + "created_at": "2018-07-19 15:05:33", + "discount_amount": 0, + "discount_invoiced": 0, + "discount_percent": 0, + "free_shipping": 0, + "discount_tax_compensation_amount": 0, + "is_qty_decimal": 0, + "is_virtual": 1, + "item_id": 80317, + "name": "Myskillbox Schüler Edition", + "no_discount": 0, + "order_id": 57612, + "original_price": 46, + "price": 44.88, + "price_incl_tax": 46, + "product_id": 8652, + "product_type": "virtual", + "qty_canceled": 0, + "qty_invoiced": 0, + "qty_ordered": 1, + "qty_refunded": 0, + "qty_shipped": 0, + "quote_item_id": 135166, + "row_invoiced": 0, + "row_total": 44.88, + "row_total_incl_tax": 46, + "sku": "978-3-0355-1397-4", + "store_id": 1, + "tax_amount": 1.12, + "tax_invoiced": 0, + "tax_percent": 2.5, + "updated_at": "2018-07-19 15:05:33", + "weight": 0.01 + } + ], + "billing_address": { + "address_type": "billing", + "city": "Test", + "country_id": "CH", + "customer_address_id": 47579, + "email": "1heptest19072018@mailinator.com", + "entity_id": 83693, + "firstname": "Test", + "lastname": "Test", + "parent_id": 57612, + "postcode": "0000", + "prefix": "Frau", + "street": [ + "Test" + ], + "telephone": null + }, + "payment": { + "account_status": null, + "additional_information": [ + "Rechnung", + null, + null + ], + "amount_ordered": 46, + "base_amount_ordered": 46, + "base_shipping_amount": 0, + "cc_last4": null, + "entity_id": 57612, + "method": "checkmo", + "parent_id": 57612, + "shipping_amount": 0, + "extension_attributes": [] + }, + "status_histories": [ + { + "comment": "payed by couponcode", + "created_at": "2018-07-19 15:05:33", + "entity_id": 244885, + "entity_name": "order", + "is_customer_notified": null, + "is_visible_on_front": 0, + "parent_id": 57612, + "status": "complete" + }, + { + "comment": "licence-coupon \"ebf81a59b968\"", + "created_at": "2018-07-19 15:05:33", + "entity_id": 244884, + "entity_name": "order", + "is_customer_notified": null, + "is_visible_on_front": 0, + "parent_id": 57612, + "status": "complete" + }, + { + "comment": null, + "created_at": "2018-07-19 15:05:33", + "entity_id": 244883, + "entity_name": "order", + "is_customer_notified": 0, + "is_visible_on_front": 0, + "parent_id": 57612, + "status": "complete" + }, + { + "comment": "Exported to ERP", + "created_at": "2018-07-19 15:05:33", + "entity_id": 244882, + "entity_name": "order", + "is_customer_notified": 0, + "is_visible_on_front": 0, + "parent_id": 57612, + "status": "complete" + } + ], + "extension_attributes": { + "shipping_assignments": [ + { + "shipping": { + "total": { + "base_shipping_amount": 0, + "base_shipping_discount_amount": 0, + "base_shipping_incl_tax": 0, + "base_shipping_tax_amount": 0, + "shipping_amount": 0, + "shipping_discount_amount": 0, + "shipping_discount_tax_compensation_amount": 0, + "shipping_incl_tax": 0, + "shipping_tax_amount": 0 + } + }, + "items": [ + { + "amount_refunded": 0, + "base_amount_refunded": 0, + "base_discount_amount": 0, + "base_discount_invoiced": 0, + "base_discount_tax_compensation_amount": 0, + "base_original_price": 46, + "base_price": 44.88, + "base_price_incl_tax": 46, + "base_row_invoiced": 0, + "base_row_total": 44.88, + "base_row_total_incl_tax": 46, + "base_tax_amount": 1.12, + "base_tax_invoiced": 0, + "created_at": "2018-07-19 15:05:33", + "discount_amount": 0, + "discount_invoiced": 0, + "discount_percent": 0, + "free_shipping": 0, + "discount_tax_compensation_amount": 0, + "is_qty_decimal": 0, + "is_virtual": 1, + "item_id": 80317, + "name": "Gesellschaft Ausgabe A (eLehrmittel, Neuauflage)", + "no_discount": 0, + "order_id": 57612, + "original_price": 46, + "price": 44.88, + "price_incl_tax": 46, + "product_id": 8652, + "product_type": "virtual", + "qty_canceled": 0, + "qty_invoiced": 0, + "qty_ordered": 1, + "qty_refunded": 0, + "qty_shipped": 0, + "quote_item_id": 135166, + "row_invoiced": 0, + "row_total": 44.88, + "row_total_incl_tax": 46, + "sku": "978-3-0355-1082-9", + "store_id": 1, + "tax_amount": 1.12, + "tax_invoiced": 0, + "tax_percent": 2.5, + "updated_at": "2018-07-19 15:05:33", + "weight": 0.01 + } + ] + } + ] + } + }, + { + "base_currency_code": "CHF", + "base_discount_amount": 0, + "base_grand_total": 24, + "base_discount_tax_compensation_amount": 0, + "base_shipping_amount": 0, + "base_shipping_discount_amount": 0, + "base_shipping_incl_tax": 0, + "base_shipping_tax_amount": 0, + "base_subtotal": 23.41, + "base_subtotal_incl_tax": 24, + "base_tax_amount": 0.59, + "base_total_due": 24, + "base_to_global_rate": 1, + "base_to_order_rate": 1, + "billing_address_id": 83696, + "created_at": "2018-07-19 15:19:00", + "customer_email": "1heptest19072018@mailinator.com", + "customer_firstname": "Test", + "customer_gender": 2, + "customer_group_id": 4, + "customer_id": 49124, + "customer_is_guest": 0, + "customer_lastname": "Test", + "customer_note": "coupon", + "customer_note_notify": 1, + "customer_prefix": "Frau", + "discount_amount": 0, + "email_sent": 1, + "entity_id": 57614, + "global_currency_code": "CHF", + "grand_total": 24, + "discount_tax_compensation_amount": 0, + "increment_id": "1004614770", + "is_virtual": 1, + "order_currency_code": "CHF", + "protect_code": "1a88e9", + "quote_id": 104403, + "shipping_amount": 0, + "shipping_discount_amount": 0, + "shipping_discount_tax_compensation_amount": 0, + "shipping_incl_tax": 0, + "shipping_tax_amount": 0, + "state": "complete", + "status": "complete", + "store_currency_code": "CHF", + "store_id": 1, + "store_name": "hep verlag\nhep verlag\nhep verlag", + "store_to_base_rate": 0, + "store_to_order_rate": 0, + "subtotal": 23.41, + "subtotal_incl_tax": 24, + "tax_amount": 0.59, + "total_due": 24, + "total_item_count": 1, + "total_qty_ordered": 1, + "updated_at": "2018-07-19 15:19:00", + "weight": 0, + "items": [ + { + "amount_refunded": 0, + "base_amount_refunded": 0, + "base_discount_amount": 0, + "base_discount_invoiced": 0, + "base_discount_tax_compensation_amount": 0, + "base_original_price": 24, + "base_price": 23.41, + "base_price_incl_tax": 24, + "base_row_invoiced": 0, + "base_row_total": 23.41, + "base_row_total_incl_tax": 24, + "base_tax_amount": 0.59, + "base_tax_invoiced": 0, + "created_at": "2018-07-19 15:19:00", + "discount_amount": 0, + "discount_invoiced": 0, + "discount_percent": 0, + "free_shipping": 0, + "discount_tax_compensation_amount": 0, + "is_qty_decimal": 0, + "is_virtual": 1, + "item_id": 80320, + "name": "Gesellschaft Ausgabe A, Arbeitsheft (eLehrmittel, Neuauflage)", + "no_discount": 0, + "order_id": 57614, + "original_price": 24, + "price": 23.41, + "price_incl_tax": 24, + "product_id": 8654, + "product_type": "virtual", + "qty_canceled": 0, + "qty_invoiced": 0, + "qty_ordered": 1, + "qty_refunded": 0, + "qty_shipped": 0, + "quote_item_id": 135169, + "row_invoiced": 0, + "row_total": 23.41, + "row_total_incl_tax": 24, + "sku": "978-3-0355-1185-7", + "store_id": 1, + "tax_amount": 0.59, + "tax_invoiced": 0, + "tax_percent": 2.5, + "updated_at": "2018-07-19 15:19:00", + "weight": 0.01 + } + ], + "billing_address": { + "address_type": "billing", + "city": "Test", + "country_id": "CH", + "customer_address_id": 47579, + "email": "1heptest19072018@mailinator.com", + "entity_id": 83696, + "firstname": "Test", + "lastname": "Test", + "parent_id": 57614, + "postcode": "0000", + "prefix": "Frau", + "street": [ + "Test" + ], + "telephone": null + }, + "payment": { + "account_status": null, + "additional_information": [ + "Rechnung", + null, + null + ], + "amount_ordered": 24, + "base_amount_ordered": 24, + "base_shipping_amount": 0, + "cc_last4": null, + "entity_id": 57614, + "method": "checkmo", + "parent_id": 57614, + "shipping_amount": 0, + "extension_attributes": [] + }, + "status_histories": [ + { + "comment": "payed by couponcode", + "created_at": "2018-07-19 15:19:00", + "entity_id": 244890, + "entity_name": "order", + "is_customer_notified": null, + "is_visible_on_front": 0, + "parent_id": 57614, + "status": "complete" + }, + { + "comment": "licence-coupon \"ece5e74a2b36\"", + "created_at": "2018-07-19 15:19:00", + "entity_id": 244889, + "entity_name": "order", + "is_customer_notified": null, + "is_visible_on_front": 0, + "parent_id": 57614, + "status": "complete" + }, + { + "comment": null, + "created_at": "2018-07-19 15:19:00", + "entity_id": 244888, + "entity_name": "order", + "is_customer_notified": 0, + "is_visible_on_front": 0, + "parent_id": 57614, + "status": "complete" + }, + { + "comment": "Exported to ERP", + "created_at": "2018-07-19 15:19:00", + "entity_id": 244887, + "entity_name": "order", + "is_customer_notified": 0, + "is_visible_on_front": 0, + "parent_id": 57614, + "status": "complete" + } + ], + "extension_attributes": { + "shipping_assignments": [ + { + "shipping": { + "total": { + "base_shipping_amount": 0, + "base_shipping_discount_amount": 0, + "base_shipping_incl_tax": 0, + "base_shipping_tax_amount": 0, + "shipping_amount": 0, + "shipping_discount_amount": 0, + "shipping_discount_tax_compensation_amount": 0, + "shipping_incl_tax": 0, + "shipping_tax_amount": 0 + } + }, + "items": [ + { + "amount_refunded": 0, + "base_amount_refunded": 0, + "base_discount_amount": 0, + "base_discount_invoiced": 0, + "base_discount_tax_compensation_amount": 0, + "base_original_price": 24, + "base_price": 23.41, + "base_price_incl_tax": 24, + "base_row_invoiced": 0, + "base_row_total": 23.41, + "base_row_total_incl_tax": 24, + "base_tax_amount": 0.59, + "base_tax_invoiced": 0, + "created_at": "2018-07-19 15:19:00", + "discount_amount": 0, + "discount_invoiced": 0, + "discount_percent": 0, + "free_shipping": 0, + "discount_tax_compensation_amount": 0, + "is_qty_decimal": 0, + "is_virtual": 1, + "item_id": 80320, + "name": "Gesellschaft Ausgabe A, Arbeitsheft (eLehrmittel, Neuauflage)", + "no_discount": 0, + "order_id": 57614, + "original_price": 24, + "price": 23.41, + "price_incl_tax": 24, + "product_id": 8654, + "product_type": "virtual", + "qty_canceled": 0, + "qty_invoiced": 0, + "qty_ordered": 1, + "qty_refunded": 0, + "qty_shipped": 0, + "quote_item_id": 135169, + "row_invoiced": 0, + "row_total": 23.41, + "row_total_incl_tax": 24, + "sku": "978-3-0355-1185-7", + "store_id": 1, + "tax_amount": 0.59, + "tax_invoiced": 0, + "tax_percent": 2.5, + "updated_at": "2018-07-19 15:19:00", + "weight": 0.01 + } + ] + } + ] + } + } + ], + "search_criteria": { + "filter_groups": [ + { + "filters": [ + { + "field": "customer_id", + "value": "49124", + "condition_type": "eq" + } + ] + } + ] + }, + "total_count": 2 +} diff --git a/server/core/tests/mock_data/valid_teacher_orders.json b/server/core/tests/mock_data/valid_teacher_orders.json new file mode 100644 index 00000000..85ac8751 --- /dev/null +++ b/server/core/tests/mock_data/valid_teacher_orders.json @@ -0,0 +1,526 @@ +{ + "items": [ + { + "base_currency_code": "CHF", + "base_discount_amount": 0, + "base_grand_total": 46, + "base_discount_tax_compensation_amount": 0, + "base_shipping_amount": 0, + "base_shipping_discount_amount": 0, + "base_shipping_incl_tax": 0, + "base_shipping_tax_amount": 0, + "base_subtotal": 44.88, + "base_subtotal_incl_tax": 46, + "base_tax_amount": 1.12, + "base_total_due": 46, + "base_to_global_rate": 1, + "base_to_order_rate": 1, + "billing_address_id": 83693, + "created_at": "2018-07-19 15:05:33", + "customer_email": "1heptest19072018@mailinator.com", + "customer_firstname": "Test", + "customer_gender": 2, + "customer_group_id": 4, + "customer_id": 49124, + "customer_is_guest": 0, + "customer_lastname": "Test", + "customer_note": "coupon", + "customer_note_notify": 1, + "customer_prefix": "Frau", + "discount_amount": 0, + "email_sent": 1, + "entity_id": 57612, + "global_currency_code": "CHF", + "grand_total": 46, + "discount_tax_compensation_amount": 0, + "increment_id": "1004614768", + "is_virtual": 1, + "order_currency_code": "CHF", + "protect_code": "71aedb", + "quote_id": 104401, + "shipping_amount": 0, + "shipping_discount_amount": 0, + "shipping_discount_tax_compensation_amount": 0, + "shipping_incl_tax": 0, + "shipping_tax_amount": 0, + "state": "complete", + "status": "complete", + "store_currency_code": "CHF", + "store_id": 1, + "store_name": "hep verlag\nhep verlag\nhep verlag", + "store_to_base_rate": 0, + "store_to_order_rate": 0, + "subtotal": 44.88, + "subtotal_incl_tax": 46, + "tax_amount": 1.12, + "total_due": 46, + "total_item_count": 1, + "total_qty_ordered": 1, + "updated_at": "2018-07-19 15:05:33", + "weight": 0, + "items": [ + { + "amount_refunded": 0, + "base_amount_refunded": 0, + "base_discount_amount": 0, + "base_discount_invoiced": 0, + "base_discount_tax_compensation_amount": 0, + "base_original_price": 46, + "base_price": 44.88, + "base_price_incl_tax": 46, + "base_row_invoiced": 0, + "base_row_total": 44.88, + "base_row_total_incl_tax": 46, + "base_tax_amount": 1.12, + "base_tax_invoiced": 0, + "created_at": "2018-07-19 15:05:33", + "discount_amount": 0, + "discount_invoiced": 0, + "discount_percent": 0, + "free_shipping": 0, + "discount_tax_compensation_amount": 0, + "is_qty_decimal": 0, + "is_virtual": 1, + "item_id": 80317, + "name": "Myskillbox Lehreredition", + "no_discount": 0, + "order_id": 57612, + "original_price": 46, + "price": 44.88, + "price_incl_tax": 46, + "product_id": 8652, + "product_type": "virtual", + "qty_canceled": 0, + "qty_invoiced": 0, + "qty_ordered": 1, + "qty_refunded": 0, + "qty_shipped": 0, + "quote_item_id": 135166, + "row_invoiced": 0, + "row_total": 44.88, + "row_total_incl_tax": 46, + "sku": "978-3-0355-1823-8", + "store_id": 1, + "tax_amount": 1.12, + "tax_invoiced": 0, + "tax_percent": 2.5, + "updated_at": "2018-07-19 15:05:33", + "weight": 0.01 + } + ], + "billing_address": { + "address_type": "billing", + "city": "Test", + "country_id": "CH", + "customer_address_id": 47579, + "email": "1heptest19072018@mailinator.com", + "entity_id": 83693, + "firstname": "Test", + "lastname": "Test", + "parent_id": 57612, + "postcode": "0000", + "prefix": "Frau", + "street": [ + "Test" + ], + "telephone": null + }, + "payment": { + "account_status": null, + "additional_information": [ + "Rechnung", + null, + null + ], + "amount_ordered": 46, + "base_amount_ordered": 46, + "base_shipping_amount": 0, + "cc_last4": null, + "entity_id": 57612, + "method": "checkmo", + "parent_id": 57612, + "shipping_amount": 0, + "extension_attributes": [] + }, + "status_histories": [ + { + "comment": "payed by couponcode", + "created_at": "2018-07-19 15:05:33", + "entity_id": 244885, + "entity_name": "order", + "is_customer_notified": null, + "is_visible_on_front": 0, + "parent_id": 57612, + "status": "complete" + }, + { + "comment": "licence-coupon \"ebf81a59b968\"", + "created_at": "2018-07-19 15:05:33", + "entity_id": 244884, + "entity_name": "order", + "is_customer_notified": null, + "is_visible_on_front": 0, + "parent_id": 57612, + "status": "complete" + }, + { + "comment": null, + "created_at": "2018-07-19 15:05:33", + "entity_id": 244883, + "entity_name": "order", + "is_customer_notified": 0, + "is_visible_on_front": 0, + "parent_id": 57612, + "status": "complete" + }, + { + "comment": "Exported to ERP", + "created_at": "2018-07-19 15:05:33", + "entity_id": 244882, + "entity_name": "order", + "is_customer_notified": 0, + "is_visible_on_front": 0, + "parent_id": 57612, + "status": "complete" + } + ], + "extension_attributes": { + "shipping_assignments": [ + { + "shipping": { + "total": { + "base_shipping_amount": 0, + "base_shipping_discount_amount": 0, + "base_shipping_incl_tax": 0, + "base_shipping_tax_amount": 0, + "shipping_amount": 0, + "shipping_discount_amount": 0, + "shipping_discount_tax_compensation_amount": 0, + "shipping_incl_tax": 0, + "shipping_tax_amount": 0 + } + }, + "items": [ + { + "amount_refunded": 0, + "base_amount_refunded": 0, + "base_discount_amount": 0, + "base_discount_invoiced": 0, + "base_discount_tax_compensation_amount": 0, + "base_original_price": 46, + "base_price": 44.88, + "base_price_incl_tax": 46, + "base_row_invoiced": 0, + "base_row_total": 44.88, + "base_row_total_incl_tax": 46, + "base_tax_amount": 1.12, + "base_tax_invoiced": 0, + "created_at": "2018-07-19 15:05:33", + "discount_amount": 0, + "discount_invoiced": 0, + "discount_percent": 0, + "free_shipping": 0, + "discount_tax_compensation_amount": 0, + "is_qty_decimal": 0, + "is_virtual": 1, + "item_id": 80317, + "name": "Gesellschaft Ausgabe A (eLehrmittel, Neuauflage)", + "no_discount": 0, + "order_id": 57612, + "original_price": 46, + "price": 44.88, + "price_incl_tax": 46, + "product_id": 8652, + "product_type": "virtual", + "qty_canceled": 0, + "qty_invoiced": 0, + "qty_ordered": 1, + "qty_refunded": 0, + "qty_shipped": 0, + "quote_item_id": 135166, + "row_invoiced": 0, + "row_total": 44.88, + "row_total_incl_tax": 46, + "sku": "978-3-0355-1082-9", + "store_id": 1, + "tax_amount": 1.12, + "tax_invoiced": 0, + "tax_percent": 2.5, + "updated_at": "2018-07-19 15:05:33", + "weight": 0.01 + } + ] + } + ] + } + }, + { + "base_currency_code": "CHF", + "base_discount_amount": 0, + "base_grand_total": 24, + "base_discount_tax_compensation_amount": 0, + "base_shipping_amount": 0, + "base_shipping_discount_amount": 0, + "base_shipping_incl_tax": 0, + "base_shipping_tax_amount": 0, + "base_subtotal": 23.41, + "base_subtotal_incl_tax": 24, + "base_tax_amount": 0.59, + "base_total_due": 24, + "base_to_global_rate": 1, + "base_to_order_rate": 1, + "billing_address_id": 83696, + "created_at": "2018-07-19 15:19:00", + "customer_email": "1heptest19072018@mailinator.com", + "customer_firstname": "Test", + "customer_gender": 2, + "customer_group_id": 4, + "customer_id": 49124, + "customer_is_guest": 0, + "customer_lastname": "Test", + "customer_note": "coupon", + "customer_note_notify": 1, + "customer_prefix": "Frau", + "discount_amount": 0, + "email_sent": 1, + "entity_id": 57614, + "global_currency_code": "CHF", + "grand_total": 24, + "discount_tax_compensation_amount": 0, + "increment_id": "1004614770", + "is_virtual": 1, + "order_currency_code": "CHF", + "protect_code": "1a88e9", + "quote_id": 104403, + "shipping_amount": 0, + "shipping_discount_amount": 0, + "shipping_discount_tax_compensation_amount": 0, + "shipping_incl_tax": 0, + "shipping_tax_amount": 0, + "state": "complete", + "status": "complete", + "store_currency_code": "CHF", + "store_id": 1, + "store_name": "hep verlag\nhep verlag\nhep verlag", + "store_to_base_rate": 0, + "store_to_order_rate": 0, + "subtotal": 23.41, + "subtotal_incl_tax": 24, + "tax_amount": 0.59, + "total_due": 24, + "total_item_count": 1, + "total_qty_ordered": 1, + "updated_at": "2018-07-19 15:19:00", + "weight": 0, + "items": [ + { + "amount_refunded": 0, + "base_amount_refunded": 0, + "base_discount_amount": 0, + "base_discount_invoiced": 0, + "base_discount_tax_compensation_amount": 0, + "base_original_price": 24, + "base_price": 23.41, + "base_price_incl_tax": 24, + "base_row_invoiced": 0, + "base_row_total": 23.41, + "base_row_total_incl_tax": 24, + "base_tax_amount": 0.59, + "base_tax_invoiced": 0, + "created_at": "2018-07-19 15:19:00", + "discount_amount": 0, + "discount_invoiced": 0, + "discount_percent": 0, + "free_shipping": 0, + "discount_tax_compensation_amount": 0, + "is_qty_decimal": 0, + "is_virtual": 1, + "item_id": 80320, + "name": "Gesellschaft Ausgabe A, Arbeitsheft (eLehrmittel, Neuauflage)", + "no_discount": 0, + "order_id": 57614, + "original_price": 24, + "price": 23.41, + "price_incl_tax": 24, + "product_id": 8654, + "product_type": "virtual", + "qty_canceled": 0, + "qty_invoiced": 0, + "qty_ordered": 1, + "qty_refunded": 0, + "qty_shipped": 0, + "quote_item_id": 135169, + "row_invoiced": 0, + "row_total": 23.41, + "row_total_incl_tax": 24, + "sku": "978-3-0355-1185-7", + "store_id": 1, + "tax_amount": 0.59, + "tax_invoiced": 0, + "tax_percent": 2.5, + "updated_at": "2018-07-19 15:19:00", + "weight": 0.01 + } + ], + "billing_address": { + "address_type": "billing", + "city": "Test", + "country_id": "CH", + "customer_address_id": 47579, + "email": "1heptest19072018@mailinator.com", + "entity_id": 83696, + "firstname": "Test", + "lastname": "Test", + "parent_id": 57614, + "postcode": "0000", + "prefix": "Frau", + "street": [ + "Test" + ], + "telephone": null + }, + "payment": { + "account_status": null, + "additional_information": [ + "Rechnung", + null, + null + ], + "amount_ordered": 24, + "base_amount_ordered": 24, + "base_shipping_amount": 0, + "cc_last4": null, + "entity_id": 57614, + "method": "checkmo", + "parent_id": 57614, + "shipping_amount": 0, + "extension_attributes": [] + }, + "status_histories": [ + { + "comment": "payed by couponcode", + "created_at": "2018-07-19 15:19:00", + "entity_id": 244890, + "entity_name": "order", + "is_customer_notified": null, + "is_visible_on_front": 0, + "parent_id": 57614, + "status": "complete" + }, + { + "comment": "licence-coupon \"ece5e74a2b36\"", + "created_at": "2018-07-19 15:19:00", + "entity_id": 244889, + "entity_name": "order", + "is_customer_notified": null, + "is_visible_on_front": 0, + "parent_id": 57614, + "status": "complete" + }, + { + "comment": null, + "created_at": "2018-07-19 15:19:00", + "entity_id": 244888, + "entity_name": "order", + "is_customer_notified": 0, + "is_visible_on_front": 0, + "parent_id": 57614, + "status": "complete" + }, + { + "comment": "Exported to ERP", + "created_at": "2018-07-19 15:19:00", + "entity_id": 244887, + "entity_name": "order", + "is_customer_notified": 0, + "is_visible_on_front": 0, + "parent_id": 57614, + "status": "complete" + } + ], + "extension_attributes": { + "shipping_assignments": [ + { + "shipping": { + "total": { + "base_shipping_amount": 0, + "base_shipping_discount_amount": 0, + "base_shipping_incl_tax": 0, + "base_shipping_tax_amount": 0, + "shipping_amount": 0, + "shipping_discount_amount": 0, + "shipping_discount_tax_compensation_amount": 0, + "shipping_incl_tax": 0, + "shipping_tax_amount": 0 + } + }, + "items": [ + { + "amount_refunded": 0, + "base_amount_refunded": 0, + "base_discount_amount": 0, + "base_discount_invoiced": 0, + "base_discount_tax_compensation_amount": 0, + "base_original_price": 24, + "base_price": 23.41, + "base_price_incl_tax": 24, + "base_row_invoiced": 0, + "base_row_total": 23.41, + "base_row_total_incl_tax": 24, + "base_tax_amount": 0.59, + "base_tax_invoiced": 0, + "created_at": "2018-07-19 15:19:00", + "discount_amount": 0, + "discount_invoiced": 0, + "discount_percent": 0, + "free_shipping": 0, + "discount_tax_compensation_amount": 0, + "is_qty_decimal": 0, + "is_virtual": 1, + "item_id": 80320, + "name": "Gesellschaft Ausgabe A, Arbeitsheft (eLehrmittel, Neuauflage)", + "no_discount": 0, + "order_id": 57614, + "original_price": 24, + "price": 23.41, + "price_incl_tax": 24, + "product_id": 8654, + "product_type": "virtual", + "qty_canceled": 0, + "qty_invoiced": 0, + "qty_ordered": 1, + "qty_refunded": 0, + "qty_shipped": 0, + "quote_item_id": 135169, + "row_invoiced": 0, + "row_total": 23.41, + "row_total_incl_tax": 24, + "sku": "978-3-0355-1185-7", + "store_id": 1, + "tax_amount": 0.59, + "tax_invoiced": 0, + "tax_percent": 2.5, + "updated_at": "2018-07-19 15:19:00", + "weight": 0.01 + } + ] + } + ] + } + } + ], + "search_criteria": { + "filter_groups": [ + { + "filters": [ + { + "field": "customer_id", + "value": "49124", + "condition_type": "eq" + } + ] + } + ] + }, + "total_count": 2 +} diff --git a/server/core/tests/mock_hep_data_factory.py b/server/core/tests/mock_hep_data_factory.py new file mode 100644 index 00000000..28e34408 --- /dev/null +++ b/server/core/tests/mock_hep_data_factory.py @@ -0,0 +1,47 @@ +import json +import os +from datetime import datetime, timedelta + + +class MockResponse: + def __init__(self, status_code, data={}): + self.status_code = status_code + self.data = data + + def json(self): + return self.data + + +## Setup json data + +def make_orders_valid(order_items): + for order_item in order_items['items']: + if 'created_at' in order_item: + yesterday = datetime.now() - timedelta(1) + order_item['created_at'] = datetime.strftime(yesterday, '%Y-%m-%d %H:%M:%S') + + return order_items + +# Load data +dir_path = os.path.dirname(os.path.realpath(__file__)) + +with open('{}/mock_data/valid_teacher_orders.json'.format(dir_path), 'r') as file: + valid_teacher_order_data = file.read() + +with open('{}/mock_data/valid_student_orders.json'.format(dir_path), 'r') as file: + valid_student_order_data = file.read() + +with open('{}/mock_data/me_data.json'.format(dir_path), 'r') as file: + me_data = file.read() + +with open('{}/mock_data/email_not_confirmed_me.json'.format(dir_path), 'r') as file: + not_confirmed_email_me_data = file.read() + +ME_DATA = json.loads(me_data) +NOT_CONFIRMED_ME = json.loads(not_confirmed_email_me_data) + +valid_teacher_order_items = json.loads(valid_teacher_order_data) +VALID_TEACHERS_ORDERS = make_orders_valid(valid_teacher_order_items) + +valid_student_order_items = json.loads(valid_student_order_data) +VALID_STUDENT_ORDERS = make_orders_valid(valid_student_order_items) diff --git a/server/core/tests/test_api.py b/server/core/tests/test_api.py index e5949e94..ed43720d 100644 --- a/server/core/tests/test_api.py +++ b/server/core/tests/test_api.py @@ -20,7 +20,7 @@ class ApiAccessTestCase(TestCase): self.assertEqual(response.url, '/login?next=/api/graphql/') def test_graphqlEndpoint_shouldBeAccessibleWithLogin(self): - user = UserFactory(username='admin') + UserFactory(username='admin') c = Client() c.login(username='admin', password='test') @@ -31,14 +31,11 @@ class ApiAccessTestCase(TestCase): def test_publicGraphqlEndpoint_shouldBeAccessibleWithoutLogin(self): query= json.dumps({ - 'operationName': 'Login', + 'operationName': 'BetaLogin', 'query': ''' - mutation Login($input: LoginInput!){ - login(input: $input) { + mutation BetaLogin($input: BetaLoginInput!){ + betaLogin(input: $input) { success - errors { - field - } } } ''', diff --git a/server/core/tests/test_coupon.py b/server/core/tests/test_coupon.py new file mode 100644 index 00000000..27c30852 --- /dev/null +++ b/server/core/tests/test_coupon.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +# +# ITerativ GmbH +# http://www.iterativ.ch/ +# +# Copyright (c) 2020 ITerativ GmbH. All rights reserved. +# +# Created on 03.02.20 +# @author: chrigu +from unittest.mock import patch + +import requests +from django.contrib.sessions.middleware import SessionMiddleware +from django.test import TestCase, RequestFactory +from graphene.test import Client + +from api.schema import schema +from core.factories import UserFactory +from core.hep_client import HepClient +from core.tests.mock_hep_data_factory import MockResponse, VALID_TEACHERS_ORDERS +from users.models import License, Role, SchoolClass, UserRole + + +class CouponTests(TestCase): + def setUp(self): + Role.objects.create_default_roles() + + self.user = UserFactory(username='aschi@iterativ.ch', email='aschi@iterativ.ch', hep_id=3) + Role.objects.create_default_roles() + self.teacher_role = Role.objects.get_default_teacher_role() + + # adding session + request = RequestFactory().post('/') + middleware = SessionMiddleware() + middleware.process_request(request) + request.user = self.user + request.session.save() + self.client = Client(schema=schema, context_value=request) + + def make_coupon_mutation(self, coupon_code, client): + mutation = ''' + mutation Coupon($input: CouponInput!){ + coupon(input: $input) { + success + } + } + ''' + + return client.execute(mutation, variables={ + 'input': { + 'couponCode': coupon_code + } + }) + + @patch.object(requests, 'put', return_value=MockResponse(200, data=['200', 'Coupon successfully redeemed'])) + @patch.object(HepClient, '_customer_orders', return_value=VALID_TEACHERS_ORDERS) + @patch.object(HepClient, 'fetch_admin_token', return_value={'token': 'AABBCCDDEE**44566'}) + def test_user_has_valid_coupon(self, admin_mock, orders_mock, response_mock): + result = self.make_coupon_mutation('COUPON--1234', self.client) + + user_role_key = self.user.user_roles.get(user=self.user).role.key + self.assertEqual(user_role_key, Role.objects.TEACHER_KEY) + license = License.objects.get(licensee=self.user) + self.assertIsNotNone(license) + + school_class = SchoolClass.objects.get(users__in=[self.user]) + self.assertIsNotNone(school_class) + + self.assertTrue(result.get('data').get('coupon').get('success')) + self.assertTrue(self.user.is_authenticated) + + @patch.object(requests, 'put', return_value=MockResponse(200, data=['201', 'Invalid Coupon'])) + def test_user_has_invalid_coupon(self, response_mock): + result = self.make_coupon_mutation('COUPON--1234', self.client) + + self.assertEqual(result.get('errors')[0].get('message'), 'invalid_coupon') + + @patch.object(requests, 'put', return_value=MockResponse(200, data=['201', 'Invalid Coupon'])) + def test_unauthenticated_user_cannot_redeem(self, response_mock): + + request = RequestFactory().post('/') + middleware = SessionMiddleware() + middleware.process_request(request) + request.session.save() + client = Client(schema=schema, context_value=request) + + result = self.make_coupon_mutation('COUPON--1234', client) + + self.assertEqual(result.get('errors')[0].get('message'), 'not_authenticated') diff --git a/server/core/tests/test_hep_client.py b/server/core/tests/test_hep_client.py new file mode 100644 index 00000000..2d584773 --- /dev/null +++ b/server/core/tests/test_hep_client.py @@ -0,0 +1,148 @@ +import json +from datetime import datetime, timedelta + +from django.test import TestCase +from core.hep_client import HepClient, TEACHER_EDITION_DURATION + + +class HepClientTestCases(TestCase): + def setUp(self): + self.hep_client = HepClient() + self.now = datetime.now() + + def test_has_no_valid_product(self): + products = [ + { + 'edition': 'teacher', + 'raw': {}, + 'activated': self.now - timedelta(2*TEACHER_EDITION_DURATION), + 'status': 'complete' + }, + { + 'edition': 'teacher', + 'raw': {}, + 'activated': self.now - timedelta(3 * TEACHER_EDITION_DURATION), + 'status': 'complete' + }, + { + 'edition': 'teacher', + 'raw': {}, + 'activated': self.now - timedelta(4 * TEACHER_EDITION_DURATION), + 'status': 'complete' + } + ] + + relevant_product = self.hep_client._get_relevant_product(products) + self.assertIsNone(relevant_product) + + def test_has_no_not_completed_product(self): + products = [ + { + 'edition': 'teacher', + 'raw': {}, + 'activated': self.now - timedelta(7), + 'status': 'not' + } + ] + + relevant_product = self.hep_client._get_relevant_product(products) + self.assertIsNone(relevant_product) + + def test_has_valid_product(self): + products = [ + { + 'edition': 'teacher', + 'raw': { + 'id': 0 + }, + 'activated': self.now - timedelta(7), + 'status': 'complete' + }, + { + 'edition': 'teacher', + 'raw': { + 'id': 1 + }, + 'activated': self.now - timedelta(3 * TEACHER_EDITION_DURATION), + 'status': 'complete' + }, + { + 'edition': 'teacher', + 'raw': { + 'id': 2 + }, + 'activated': self.now - timedelta(4 * TEACHER_EDITION_DURATION), + 'status': 'complete' + } + ] + + relevant_product = self.hep_client._get_relevant_product(products) + self.assertEqual(relevant_product['raw']['id'], 0) + + def test_has_multiple_valid_teacher_products_but_only_one_active(self): + products = [ + { + 'edition': 'teacher', + 'raw': { + 'id': 0 + }, + 'activated': self.now - timedelta(7), + 'status': 'complete' + }, + { + 'edition': 'teacher', + 'raw': { + 'id': 1 + }, + 'activated': self.now - timedelta(3 * TEACHER_EDITION_DURATION), + 'status': 'complete' + }, + { + 'edition': 'teacher', + 'raw': { + 'id': 2 + }, + 'activated': self.now - timedelta(4 * TEACHER_EDITION_DURATION), + 'status': 'complete' + } + ] + + relevant_product = self.hep_client._get_relevant_product(products) + self.assertEqual(relevant_product['raw']['id'], 0) + + def test_has_valid_student_and_teacher_edition(self): + products = [ + { + 'edition': 'student', + 'raw': { + 'id': 0 + }, + 'activated': self.now - timedelta(7), + 'status': 'complete' + }, + { + 'edition': 'teacher', + 'raw': { + 'id': 1 + }, + 'activated': self.now - timedelta(7), + 'status': 'complete' + } + ] + + relevant_product = self.hep_client._select_from_teacher_products(products) + self.assertEqual(relevant_product['raw']['id'], 1) + + def test_product_is_active(self): + + expiry_date = self.now + timedelta(3) + + is_active = HepClient.is_product_active(expiry_date, 'teacher') + self.assertTrue(is_active) + + def test_product_is_not_active(self): + + expiry_date = self.now - timedelta(3 * TEACHER_EDITION_DURATION) + + is_active = HepClient.is_product_active(expiry_date, 'teacher') + self.assertFalse(is_active) diff --git a/server/core/tests/test_import.py b/server/core/tests/test_import.py index c4c19f8a..05477d5d 100644 --- a/server/core/tests/test_import.py +++ b/server/core/tests/test_import.py @@ -1,4 +1,4 @@ -from django.test import TestCase, Client +from django.test import TestCase from django.core import management from users.models import User, Role diff --git a/server/core/tests/test_middleware.py b/server/core/tests/test_middleware.py new file mode 100644 index 00000000..19815734 --- /dev/null +++ b/server/core/tests/test_middleware.py @@ -0,0 +1,49 @@ +from datetime import timedelta + +from django.test import TestCase +from django.utils import timezone + +from core.factories import UserFactory +from core.utils import is_private_api_call_allowed + + +class MiddlewareTestCase(TestCase): + def test_user_with_license_can_see_private_api(self): + + tomorrow = timezone.now() + timedelta(1) + user = UserFactory(username='aschiman@ch.ch') + user.license_expiry_date = tomorrow + + body = b'"{mutation {\\n addRoom}"' + + self.assertTrue(is_private_api_call_allowed(user, body)) + + def test_user_without_valid_license_cannot_see_private_api(self): + + yesterday = timezone.now() - timedelta(1) + user = UserFactory(username='aschiman@ch.ch', hep_id=23) + user.license_expiry_date = yesterday + + body = b'"{mutation {\\n addRoom}"' + + self.assertFalse(is_private_api_call_allowed(user, body)) + + def test_logout_is_allowed_without_valid_license(self): + + yesterday = timezone.now() - timedelta(1) + user = UserFactory(username='aschiman@ch.ch') + user.license_expiry_date = yesterday + + body = b'"{mutation { logout {"' + + self.assertTrue(is_private_api_call_allowed(user, body)) + + def test_me_query_is_allowed_without_valid_license(self): + + yesterday = timezone.now() - timedelta(1) + user = UserFactory(username='aschiman@ch.ch') + user.license_expiry_date = yesterday + + body = b'"{query { me {"' + + self.assertTrue(is_private_api_call_allowed(user, body)) diff --git a/server/core/urls.py b/server/core/urls.py index 8b21342d..6a95b795 100644 --- a/server/core/urls.py +++ b/server/core/urls.py @@ -2,41 +2,19 @@ from django.conf import settings from django.conf.urls import url, include from django.conf.urls.static import static from django.contrib import admin -from django.contrib.auth.views import PasswordResetView -from django.urls import re_path, path +from django.urls import re_path from django.views.generic import RedirectView from wagtail.admin import urls as wagtailadmin_urls from wagtail.core import urls as wagtail_urls from core import views -from core.views import LegacySetPasswordView, LegacySetPasswordDoneView, LegacySetPasswordConfirmView,\ - LegacySetPasswordCompleteView, SetPasswordView, SetPasswordDoneView, SetPasswordConfirmView, SetPasswordCompleteView + urlpatterns = [ # django admin url(r'^guru/', admin.site.urls), url(r'^statistics/', include('statistics.urls', namespace='statistics')), - # legacy - will be removed - # forgot password - path('accounts/password_reset/', - PasswordResetView.as_view(html_email_template_name='registration/password_reset_email.html')), - path(r'accounts/', include('django.contrib.auth.urls')), - - # set password - path('welcome/', LegacySetPasswordView.as_view(), name='set_password'), - path('set-password/done/', LegacySetPasswordDoneView.as_view(), name='set_password_done'), - path('set-password///', LegacySetPasswordConfirmView.as_view(), name='set_password_confirm'), - path('set-password/complete/', LegacySetPasswordCompleteView.as_view(), name='set_password_complete'), - - # set password upon registration - path('registration/welcome/', SetPasswordView.as_view(), name='registration_set_password'), - path('registration/set-password/done/', SetPasswordDoneView.as_view(), name='registration_set_password_done'), - path('registration/set-password///', SetPasswordConfirmView.as_view(), - name='registration_set_password_confirm'), - path('registration/set-password/complete/', SetPasswordCompleteView.as_view(), - name='registration_set_password_complete'), - # wagtail url(r'^cms/', include(wagtailadmin_urls)), diff --git a/server/core/utils.py b/server/core/utils.py index f192977c..28bb4185 100644 --- a/server/core/utils.py +++ b/server/core/utils.py @@ -1,3 +1,7 @@ +import re + +from django.utils import timezone + from api.utils import get_object from users.models import SchoolClass @@ -18,3 +22,29 @@ def set_visible_for(block, visibility_list): block.visible_for.remove(school_class) else: block.visible_for.add(school_class) + + +def is_private_api_call_allowed(user, body): + # logged in users should only be able to access all resources if they have a valid license + # logged in users without valid license have only access to logout, me & coupon mutations + + body_unicode = body.decode('utf-8') + + try: + if not user.hep_id: + return True + except AttributeError: + return True + + # logout, me and coupon resources are always allowed. Even if the user has no valid license + if re.search(r"mutation\s*.*\s*logout\s*{", body_unicode) or re.search(r"query\s*.*\s*me\s*{", body_unicode)\ + or re.search(r"mutation\s*Coupon", body_unicode): + return True + + license_expiry = user.license_expiry_date + + # all other resources are denied if the license is not valid + if license_expiry is None or license_expiry < timezone.now(): + return False + + return True diff --git a/server/core/views.py b/server/core/views.py index 7a00faf5..5a47cb2a 100644 --- a/server/core/views.py +++ b/server/core/views.py @@ -7,9 +7,13 @@ from django.http.response import HttpResponse from django.shortcuts import render from django.urls import reverse_lazy from django.views.decorators.csrf import ensure_csrf_cookie +from django.views.generic import TemplateView from graphene_django.views import GraphQLView from django.utils.translation import gettext_lazy as _ +from core.hep_client import HepClient +from core.models import AdminData + class PrivateGraphQLView(LoginRequiredMixin, GraphQLView): pass @@ -26,50 +30,18 @@ def home(request): return render(request, 'index.html', {}) -class SetPasswordView(PasswordResetView): - html_email_template_name = 'registration/registration_set_password_email.html' - subject_template_name = 'registration/registration_set_password_subject.txt' - success_url = reverse_lazy('registration_set_password_done') - template_name = 'registration/registration_set_password_form.html' - title = _('Password setzen') +class ConfirmationKeyDisplayView(TemplateView): + template_name = 'confirmation_key.html' + def get_context_data(self, *args, **kwargs): -class SetPasswordDoneView(PasswordResetDoneView): - template_name = 'registration/registration_set_password_done.html' - title = _('Password setzen versandt') + email = self.request.GET.get('email', '') + hep_client = HepClient() + admin_token = AdminData.objects.get_admin_token() + hep_user = hep_client.customers_search(admin_token, email) -class SetPasswordConfirmView(PasswordResetConfirmView): - success_url = reverse_lazy('registration_set_password_complete') - template_name = 'registration/registration_set_password_confirm.html' - title = _('Gib ein Passwort ein') - - -class SetPasswordCompleteView(PasswordResetCompleteView): - template_name = 'registration/registration_set_password_complete.html' - title = _('Passwort setzen erfolgreich') - - -# legacy -class LegacySetPasswordView(PasswordResetView): - html_email_template_name = 'registration/set_password_email.html' - subject_template_name = 'registration/set_password_subject.txt' - success_url = reverse_lazy('set_password_done') - template_name = 'registration/set_password_form.html' - title = _('Password setzen') - - -class LegacySetPasswordDoneView(PasswordResetDoneView): - template_name = 'registration/set_password_done.html' - title = _('Password setzen versandt') - - -class LegacySetPasswordConfirmView(PasswordResetConfirmView): - success_url = reverse_lazy('set_password_complete') - template_name = 'registration/set_password_confirm.html' - title = _('Gib ein Passwort ein') - - -class LegacySetPasswordCompleteView(PasswordResetCompleteView): - template_name = 'registration/set_password_complete.html' - title = _('Passwort setzen erfolgreich') + context = super().get_context_data(**kwargs) + context['confirmation_key'] = hep_user['confirmation'] + context['hep_id'] = hep_user['id'] + return context diff --git a/server/registration/admin.py b/server/registration/admin.py deleted file mode 100644 index 64370f36..00000000 --- a/server/registration/admin.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# -# ITerativ GmbH -# http://www.iterativ.ch/ -# -# Copyright (c) 2019 ITerativ GmbH. All rights reserved. -# -# Created on 2019-10-10 -# @author: chrigu -from django.contrib import admin - -from registration.models import LicenseType, License - - -@admin.register(LicenseType) -class LicenseTypeAdmin(admin.ModelAdmin): - list_display = ('id', 'name', 'key', 'for_role', 'active') - list_filter = ('for_role', 'active') - - -@admin.register(License) -class LicenseAdmin(admin.ModelAdmin): - list_display = ('license_type', 'licensee') - list_filter = ('license_type', 'licensee') - raw_id_fields = ('licensee',) diff --git a/server/registration/factories.py b/server/registration/factories.py deleted file mode 100644 index 50c493de..00000000 --- a/server/registration/factories.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -# -# ITerativ GmbH -# http://www.iterativ.ch/ -# -# Copyright (c) 2019 ITerativ GmbH. All rights reserved. -# -# Created on 2019-10-08 -# @author: chrigu -import random - -import factory - -from registration.models import LicenseType, License - - -class LicenseTypeFactory(factory.django.DjangoModelFactory): - class Meta: - model = LicenseType - - name = factory.Sequence(lambda n: 'license-{}'.format(n)) - active = True - key = factory.Sequence(lambda n: "license-key-%03d" % n) - description = factory.Sequence(lambda n: "Some description %03d" % n) - - -class LicenseFactory(factory.django.DjangoModelFactory): - class Meta: - model = License - diff --git a/server/registration/management/__init__.py b/server/registration/management/__init__.py deleted file mode 100644 index 7e9d57d8..00000000 --- a/server/registration/management/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# -# ITerativ GmbH -# http://www.iterativ.ch/ -# -# Copyright (c) 2019 ITerativ GmbH. All rights reserved. -# -# Created on 2019-10-23 -# @author: chrigu -from django.conf import settings diff --git a/server/registration/management/commands/__init__.py b/server/registration/management/commands/__init__.py deleted file mode 100644 index 7e9d57d8..00000000 --- a/server/registration/management/commands/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -# -# ITerativ GmbH -# http://www.iterativ.ch/ -# -# Copyright (c) 2019 ITerativ GmbH. All rights reserved. -# -# Created on 2019-10-23 -# @author: chrigu -from django.conf import settings diff --git a/server/registration/management/commands/create_dummy_license.py b/server/registration/management/commands/create_dummy_license.py deleted file mode 100644 index 8ae4c88e..00000000 --- a/server/registration/management/commands/create_dummy_license.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -# -# ITerativ GmbH -# http://www.iterativ.ch/ -# -# Copyright (c) 2019 ITerativ GmbH. All rights reserved. -# -# Created on 2019-10-23 -# @author: chrigu -from django.conf import settings -from django.core.management import BaseCommand - -from registration.models import LicenseType -from users.models import Role - - -class Command(BaseCommand): - - def handle(self, *args, **options): - - try: - role = Role.objects.get(key=Role.objects.TEACHER_KEY) - except Role.DoesNotExist: - print("LicenseType requires that a Teacher Role exsits") - - LicenseType.objects.create(name='dummy_license', - for_role=role, - active=True, - key='c1fa2e2a-2e27-480d-8469-2e88414c4ad8', - description='dummy license') diff --git a/server/registration/migrations/0003_auto_20200204_1331.py b/server/registration/migrations/0003_auto_20200204_1331.py new file mode 100644 index 00000000..0d63ddf9 --- /dev/null +++ b/server/registration/migrations/0003_auto_20200204_1331.py @@ -0,0 +1,41 @@ +# Generated by Django 2.0.6 on 2020-02-04 13:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0010_schoolclass_code'), + ('registration', '0002_auto_20191010_0905'), + ] + + operations = [ + migrations.RemoveField( + model_name='licensetype', + name='for_role', + ), + migrations.RemoveField( + model_name='license', + name='license_type', + ), + migrations.AddField( + model_name='license', + name='expire_date', + field=models.DateField(null=True), + ), + migrations.AddField( + model_name='license', + name='for_role', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.Role'), + ), + migrations.AddField( + model_name='license', + name='raw', + field=models.TextField(default=''), + ), + migrations.DeleteModel( + name='LicenseType', + ), + ] diff --git a/server/registration/migrations/0004_auto_20200220_1039.py b/server/registration/migrations/0004_auto_20200220_1039.py new file mode 100644 index 00000000..6891b40d --- /dev/null +++ b/server/registration/migrations/0004_auto_20200220_1039.py @@ -0,0 +1,24 @@ +# Generated by Django 2.1.15 on 2020-02-20 10:39 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('registration', '0003_auto_20200204_1331'), + ] + + operations = [ + migrations.RemoveField( + model_name='license', + name='for_role', + ), + migrations.RemoveField( + model_name='license', + name='licensee', + ), + migrations.DeleteModel( + name='License', + ), + ] diff --git a/server/registration/models.py b/server/registration/models.py deleted file mode 100644 index fb3e60a3..00000000 --- a/server/registration/models.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- -# -# ITerativ GmbH -# http://www.iterativ.ch/ -# -# Copyright (c) 2019 ITerativ GmbH. All rights reserved. -# -# Created on 2019-10-08 -# @author: chrigu -from django.utils.translation import ugettext_lazy as _ -from django.db import models - -from users.managers import RoleManager -from users.models import Role, User - - -class LicenseType(models.Model): - - name = models.CharField(_('License name'), max_length=255, blank=False, null=False) - for_role = models.ForeignKey(Role, blank=False, null=False, on_delete=models.CASCADE) - key = models.CharField(max_length=128, blank=False, null=False, unique=True) - active = models.BooleanField(_('License active'), default=False) - description = models.TextField(_('Description'), default="") - - def is_teacher_license(self): - return self.for_role.key == RoleManager.TEACHER_KEY - - def __str__(self): - return '%s - role: %s' % (self.name, self.for_role) - - -class License(models.Model): - license_type = models.ForeignKey(LicenseType, blank=False, null=False, on_delete=models.CASCADE) - licensee = models.ForeignKey(User, blank=False, null=True, on_delete=models.CASCADE) diff --git a/server/registration/mutations_public.py b/server/registration/mutations_public.py index 6a3a007b..e6c9b28d 100644 --- a/server/registration/mutations_public.py +++ b/server/registration/mutations_public.py @@ -8,87 +8,60 @@ # Created on 2019-10-08 # @author: chrigu import graphene +from django.contrib.auth import login from graphene import relay -from core.views import SetPasswordView -from registration.models import License -from registration.serializers import RegistrationSerializer -from users.models import User, Role, UserRole, SchoolClass, SchoolClassMember - - -class PublicFieldError(graphene.ObjectType): - code = graphene.String() - - -class MutationError(graphene.ObjectType): - field = graphene.String() - errors = graphene.List(PublicFieldError) +from core.hep_client import HepClient, HepClientException +from core.models import AdminData +from users.user_signup_login_handler import handle_user_and_verify_products, UNKNOWN_ERROR, NO_VALID_LICENSE class Registration(relay.ClientIDMutation): class Input: - firstname_input = graphene.String() - lastname_input = graphene.String() - email_input = graphene.String() - license_key_input = graphene.String() + confirmation_key = graphene.String() + user_id = graphene.Int() success = graphene.Boolean() - errors = graphene.List(MutationError) # todo: change for consistency + message = graphene.String() + @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): - first_name = kwargs.get('firstname_input') - last_name = kwargs.get('lastname_input') - email = kwargs.get('email_input') - license_key = kwargs.get('license_key_input') - registration_data = { - 'first_name': first_name, - 'last_name': last_name, - 'email': email, - 'license_key': license_key, - } + confirmation_key = kwargs.get('confirmation_key') + user_id = kwargs.get('user_id') - serializer = RegistrationSerializer(data=registration_data) + hep_client = HepClient() + admin_token = AdminData.objects.get_admin_token() - if serializer.is_valid(): - user = User.objects.create_user_with_random_password(serializer.data['first_name'], - serializer.data['last_name'], - serializer.data['email']) - sb_license = License.objects.create(licensee=user, license_type=serializer.context['license_type']) + try: + hep_client.customer_activate(confirmation_key, user_id) + user_data = hep_client.customers_by_id(admin_token, user_id) + # double check if user has verified his email. If the "confirmation" field is present, the email address + # is not verified. + if 'confirmation' in user_data: + return cls.return_fail_registration_msg('invalid_key') + except HepClientException: + return cls.return_fail_registration_msg('unknown_error') - if sb_license.license_type.is_teacher_license(): - teacher_role = Role.objects.get(key=Role.objects.TEACHER_KEY) - UserRole.objects.get_or_create(user=user, role=teacher_role) - default_class_name = SchoolClass.generate_default_group_name(user=user) - default_class = SchoolClass.objects.create(name=default_class_name) - SchoolClassMember.objects.create( - user=user, - school_class=default_class - ) + user, status_msg = handle_user_and_verify_products(user_data) + + if user: + login(info.context, user) + + if status_msg: + if status_msg == NO_VALID_LICENSE: + return cls(success=True, message=NO_VALID_LICENSE) else: - student_role = Role.objects.get(key=Role.objects.STUDENT_KEY) - UserRole.objects.get_or_create(user=user, role=student_role) + return cls.return_fail_registration_msg(status_msg) - password_reset_view = SetPasswordView() - password_reset_view.request = info.context - form = password_reset_view.form_class({'email': user.email}) + return cls(success=True, message='success') - if not form.is_valid(): - return cls(success=False, errors=form.errors) + @classmethod + def return_fail_registration_msg(cls, message): + if message == UNKNOWN_ERROR: + raise Exception(message) - password_reset_view.form_valid(form) - - return cls(success=True) - - errors = [] - for key, value in serializer.errors.items(): - error = MutationError(field=key, errors=[]) - for field_error in serializer.errors[key]: - error.errors.append(PublicFieldError(code=field_error.code)) - - errors.append(error) - - return cls(success=False, errors=errors) + return cls(success=False, message=message) class RegistrationMutations: diff --git a/server/registration/serializers.py b/server/registration/serializers.py deleted file mode 100644 index 887fbbe1..00000000 --- a/server/registration/serializers.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -# -# ITerativ GmbH -# http://www.iterativ.ch/ -# -# Copyright (c) 2019 ITerativ GmbH. All rights reserved. -# -# Created on 2019-10-08 -# @author: chrigu -from django.contrib.auth import get_user_model -from rest_framework import serializers -from rest_framework.fields import CharField, EmailField -from django.utils.translation import ugettext_lazy as _ -from registration.models import License, LicenseType - - -class RegistrationSerializer(serializers.Serializer): - first_name = CharField(allow_blank=False) - last_name = CharField(allow_blank=False) - email = EmailField(allow_blank=False) - license_key = CharField(allow_blank=False) - skillbox_license = None - - def validate_email(self, value): - lower_email = value.lower() - # the email is used as username - if len(get_user_model().objects.filter(username=lower_email)) > 0: - raise serializers.ValidationError(_(u'Diese E-Mail ist bereits registriert')) - elif len(get_user_model().objects.filter(email=lower_email)) > 0: - raise serializers.ValidationError(_(u'Dieser E-Mail ist bereits registriert')) - else: - return lower_email - - def validate_license_key(self, value): - license_types = LicenseType.objects.filter(key=value, active=True) - if len(license_types) == 0: - raise serializers.ValidationError(_(u'Die Lizenznummer ist ungültig')) - - self.context['license_type'] = license_types[0] # Assuming there is just ONE license per key - return value diff --git a/server/registration/tests/test_registration.py b/server/registration/tests/test_registration.py index 15779a98..4baf4f2b 100644 --- a/server/registration/tests/test_registration.py +++ b/server/registration/tests/test_registration.py @@ -7,32 +7,29 @@ # # Created on 2019-10-08 # @author: chrigu -from django.core import mail +from unittest.mock import patch + from django.contrib.sessions.middleware import SessionMiddleware from django.test import TestCase, RequestFactory from graphene.test import Client from api.schema import schema -from registration.factories import LicenseTypeFactory, LicenseFactory -from registration.models import License -from users.managers import RoleManager -from users.models import Role, User, UserRole, SchoolClass +from core.hep_client import HepClient +from core.tests.mock_hep_data_factory import ME_DATA, VALID_TEACHERS_ORDERS +from users.models import License +from users.models import User, Role, SchoolClass + +INVALID_KEY_ME = dict(ME_DATA) + +INVALID_KEY_ME['confirmation'] = 'abddddddd' class RegistrationTests(TestCase): def setUp(self): - - self.teacher_role = Role.objects.create(key=Role.objects.TEACHER_KEY, name="Teacher Role") - self.student_role = Role.objects.create(key=Role.objects.STUDENT_KEY, name="Student Role") - - self.teacher_license_type = LicenseTypeFactory(for_role=self.teacher_role) - self.student_license_type = LicenseTypeFactory(for_role=self.student_role) - - self.teacher_license = LicenseFactory(license_type=self.teacher_license_type) - self.student_license = LicenseFactory(license_type=self.student_license_type) - request = RequestFactory().post('/') + Role.objects.create_default_roles() + self.email = 'sepp@skillbox.iterativ.ch' self.first_name = 'Sepp' self.last_name = 'Feuz' @@ -43,78 +40,62 @@ class RegistrationTests(TestCase): request.session.save() self.client = Client(schema=schema, context_value=request) - def make_register_mutation(self, first_name, last_name, email, license_key): + def make_register_mutation(self, confirmation_key, user_id): mutation = ''' mutation Registration($input: RegistrationInput!){ registration(input: $input) { success - errors { - field - } + message } } ''' return self.client.execute(mutation, variables={ 'input': { - 'firstnameInput': first_name, - 'lastnameInput': last_name, - 'emailInput': email, - 'licenseKeyInput': license_key, + 'confirmationKey': confirmation_key, + 'userId': user_id } }) - def _assert_user_registration(self, count, email, role_key): - users = User.objects.filter(username=self.email) - self.assertEqual(len(users), count) - user_roles = UserRole.objects.filter(user__email=email, role__key=role_key) - self.assertEqual(len(user_roles), count) - licenses = License.objects.filter(licensee__email=email, license_type__for_role__key=role_key) - self.assertEqual(len(licenses), count) + @patch.object(HepClient, 'customer_activate', return_value="Response") + @patch.object(HepClient, 'customers_by_id', return_value=ME_DATA) + @patch.object(HepClient, 'myskillbox_product_for_customer', return_value=None) + @patch.object(HepClient, 'fetch_admin_token', return_value=b'"AABBCCDDEE**44566"') + def test_user_can_register_with_valid_confirmation_key_and_no_license(self, admin_mock, customer_by_id_mock, + product_mock, customer_mock): + + result = self.make_register_mutation('CONFIRMATION_KEY', 1) - def test_user_can_register_as_teacher(self): - self._assert_user_registration(0, self.email, RoleManager.TEACHER_KEY) - school_classes = SchoolClass.objects.filter(name__startswith='Meine Klasse') - self.assertEqual(len(school_classes), 0) - result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.teacher_license_type.key) self.assertTrue(result.get('data').get('registration').get('success')) - self._assert_user_registration(1, self.email, RoleManager.TEACHER_KEY) - school_classes = SchoolClass.objects.filter(name__startswith='Meine Klasse') - self.assertEqual(len(school_classes), 1) - user = User.objects.get(email=self.email) - self.assertTrue(school_classes[0].is_user_in_schoolclass(user)) - self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].subject, 'Myskillbox: E-Mail bestätigen und Passwort setzen') + self.assertEqual(result.get('data').get('registration').get('message'), 'no_valid_license') + + @patch.object(HepClient, 'customer_activate', return_value="Response") + @patch.object(HepClient, 'customers_by_id', return_value=INVALID_KEY_ME) + @patch.object(HepClient, 'fetch_admin_token', return_value=b'"AABBCCDDEE**44566"') + def test_user_cannot_register_with_invalid_key(self, admin_mock, confirmation_mock, id_mock): + + result = self.make_register_mutation('CONFIRMATION_KEY', 1) + + self.assertFalse(result.get('data').get('registration').get('success')) + self.assertEqual(result.get('data').get('registration').get('message'), 'invalid_key') + + @patch.object(HepClient, '_customer_orders', return_value=VALID_TEACHERS_ORDERS) + @patch.object(HepClient, 'customer_activate', return_value="Response") + @patch.object(HepClient, 'customers_by_id', return_value=ME_DATA) + @patch.object(HepClient, 'fetch_admin_token', return_value=b'"AABBCCDDEE**44566"') + def test_teacher_can_register_with_remote_license(self, admin_mock, id_mock, activate_mock, orders_mock): + result = self.make_register_mutation('CONFIRMATION_KEY', 1) + + user = User.objects.get(email=ME_DATA['email']) + + user_role_key = user.user_roles.get(user=user).role.key + self.assertEqual(user_role_key, Role.objects.TEACHER_KEY) + + license = License.objects.get(licensee=user) + self.assertEqual(license.for_role.key, Role.objects.TEACHER_KEY) + + school_class = SchoolClass.objects.get(users__in=[user]) + self.assertIsNotNone(school_class) - def test_user_can_register_as_student(self): - self._assert_user_registration(0, self.email, RoleManager.STUDENT_KEY) - result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.student_license_type.key) self.assertTrue(result.get('data').get('registration').get('success')) - self._assert_user_registration(1, self.email, RoleManager.STUDENT_KEY) - - def test_existing_user_cannot_register(self): - self._assert_user_registration(0, self.email, RoleManager.STUDENT_KEY) - self.make_register_mutation(self.first_name, self.last_name, self.email, self.student_license_type.key) - result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.student_license_type.key) - self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'email') - - def test_existing_user_cannot_register_with_uppercase_email(self): - self._assert_user_registration(0, self.email, RoleManager.STUDENT_KEY) - self.make_register_mutation(self.first_name, self.last_name, self.email.upper(), self.student_license_type.key) - result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.student_license_type.key) - self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'email') - - def test_user_cannot_register_if_firstname_is_missing(self): - result = self.make_register_mutation('', self.last_name, self.email, self.teacher_license_type.key) - self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'first_name') - self.assertFalse(result.get('data').get('registration').get('success')) - - def test_user_cannot_register_if_lastname_is_missing(self): - result = self.make_register_mutation(self.first_name, '', self.email, self.teacher_license_type.key) - self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'last_name') - self.assertFalse(result.get('data').get('registration').get('success')) - - def test_user_cannot_register_if_email_is_missing(self): - result = self.make_register_mutation(self.first_name, self.last_name, '', self.teacher_license_type.key) - self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'email') - self.assertFalse(result.get('data').get('registration').get('success')) + self.assertTrue(user.is_authenticated) diff --git a/server/registration/tests/test_registration_proxy.py b/server/registration/tests/test_registration_proxy.py new file mode 100644 index 00000000..36e1ca8c --- /dev/null +++ b/server/registration/tests/test_registration_proxy.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# +# ITerativ GmbH +# http://www.iterativ.ch/ +# +# Copyright (c) 2020 ITerativ GmbH. All rights reserved. +# +# Created on 25.02.20 +# @author: chrigu +import json + +from unittest.mock import patch + +import requests +from django.test import TestCase, Client +from django.urls import reverse + +from core.hep_client import HepClient +from core.tests.mock_hep_data_factory import MockResponse + +RESPONSE = { + 'id': 1234, + 'confirmation': 'abdc1234', + 'firstname': 'Pesche', + 'lastname': 'Zubrüti', + 'email': 'aschima@ch.ch', + 'prefix': 'Herr', + 'gender': 1, + 'addresses': [ + { + 'country_id': 'CH', + 'street': ['Weg 1'], + 'postcode': '1234', + 'city': 'Äussere Einöde', + 'firstname': 'Pesche', + 'lastname': 'Zubrüti', + 'prefix': 'Herr', + 'default_shipping': True, + 'default_billing': True, + } + ], +} + +DATA = { + 'customer': { + 'firstname': 'Pesche', + 'lastname': 'Zubrüti', + 'email': 'aschima@ch.ch', + 'prefix': 'Herr', + 'gender': 1, + 'addresses': [ + { + 'country_id': 'CH', + 'street': ['Weg 1'], + 'postcode': '1234', + 'city': 'Äussere Einöde', + 'firstname': 'Pesche', + 'lastname': 'Zubrüti', + 'prefix': 'Herr', + 'default_shipping': True, + 'default_billing': True, + } + ], + 'password': '123454abasfd' + } +} + + +class ProxyTest(TestCase): + + def setUp(self): + self.client = Client() + + @patch.object(HepClient, 'customer_create', return_value=RESPONSE) + def test_proxy_filters_confirmation_key(self, create_mock): + + response = self.client.post(reverse('api:registration:proxy'), json.dumps(DATA), content_type="application/json") + found = 'confirmation' in response.json().keys() + self.assertFalse(found) + + @patch.object(requests, 'post', return_value=MockResponse(400, + data={'message': 'Ein Kunde mit der gleichen E-Mail-Adresse existiert bereits in einer zugeordneten Website.'})) + def test_handles_400(self, create_mock): + + response = self.client.post(reverse('api:registration:proxy'), json.dumps(DATA), content_type="application/json") + self.assertEquals(response.json()['message'], 'Ein Kunde mit der gleichen E-Mail-Adresse existiert bereits in einer zugeordneten Website.') diff --git a/server/registration/urls.py b/server/registration/urls.py new file mode 100644 index 00000000..ba99ab28 --- /dev/null +++ b/server/registration/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls import url +from django.views.decorators.csrf import csrf_exempt + +from registration.view import RegistrationProxyView + +app_name = 'registration' +urlpatterns = [ + url(r'^registration/', csrf_exempt(RegistrationProxyView.as_view()), name="proxy"), +] diff --git a/server/registration/view.py b/server/registration/view.py new file mode 100644 index 00000000..f9eb6712 --- /dev/null +++ b/server/registration/view.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# +# ITerativ GmbH +# http://www.iterativ.ch/ +# +# Copyright (c) 2020 ITerativ GmbH. All rights reserved. +# +# Created on 25.02.20 +# @author: chrigu +import json + +from django.http import JsonResponse +from django.views import View + +from core.hep_client import HepClient, HepClientException + + +class RegistrationProxyView(View): + + def post(self, request, *args, **kwargs): + hep_client = HepClient() + data = json.loads(request.body) + data['customer']['group_id'] = 5 + + try: + hep_data = hep_client.customer_create(data) + except HepClientException as e: + return JsonResponse(e.args[1], status=e.args[0]) + + response_data = hep_data.copy() + del response_data['confirmation'] + + return JsonResponse(response_data) + diff --git a/server/users/admin.py b/server/users/admin.py index 23971f94..f36af2aa 100644 --- a/server/users/admin.py +++ b/server/users/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin from users.forms import CustomUserCreationForm, CustomUserChangeForm -from .models import User, SchoolClass, Role, UserRole, UserSetting +from .models import User, SchoolClass, Role, UserRole, UserSetting, License class SchoolClassInline(admin.TabularInline): @@ -68,3 +68,10 @@ admin.site.register(User, CustomUserAdmin) class UserSettingAdmin(admin.ModelAdmin): list_display = ('user', 'selected_class') raw_id_fields = ('user', 'selected_class') + + +@admin.register(License) +class LicenseAdmin(admin.ModelAdmin): + list_display = ('licensee',) + list_filter = ('licensee',) + raw_id_fields = ('licensee',) diff --git a/server/users/factories.py b/server/users/factories.py index 4ac1e5dc..56e990d6 100644 --- a/server/users/factories.py +++ b/server/users/factories.py @@ -1,8 +1,7 @@ import random import factory - -from users.models import SchoolClass, SchoolClassMember +from users.models import SchoolClass, SchoolClassMember, License class_types = ['DA', 'KV', 'INF', 'EE'] class_suffix = ['A', 'B', 'C', 'D', 'E'] @@ -30,3 +29,8 @@ class SchoolClassFactory(factory.django.DjangoModelFactory): # A list of groups were passed in, use them for user in extracted: SchoolClassMember.objects.create(user=user, school_class=self, active=True) + + +class LicenseFactory(factory.django.DjangoModelFactory): + class Meta: + model = License diff --git a/server/users/management/__init__.py b/server/users/management/__init__.py new file mode 100644 index 00000000..00719086 --- /dev/null +++ b/server/users/management/__init__.py @@ -0,0 +1 @@ +from django.conf import settings diff --git a/server/users/management/commands/__init__.py b/server/users/management/commands/__init__.py new file mode 100644 index 00000000..00719086 --- /dev/null +++ b/server/users/management/commands/__init__.py @@ -0,0 +1 @@ +from django.conf import settings diff --git a/server/users/management/commands/sync_licenses.py b/server/users/management/commands/sync_licenses.py new file mode 100644 index 00000000..5ae78e68 --- /dev/null +++ b/server/users/management/commands/sync_licenses.py @@ -0,0 +1,31 @@ +import os +import shutil + +from django.conf import settings +from django.core.management import BaseCommand + +from core.hep_client import HepClient +from core.models import AdminData +from users.models import User, License + + +class Command(BaseCommand): + + def handle(self, *args, **options): + "Update licenses via cronjob" + + hep_client = HepClient() + + admin_token = AdminData.objects.get_admin_token() + hep_users = User.objects.filter(hep_id__isnull=False) + + for hep_user in hep_users: + product = hep_client.myskillbox_product_for_customer(admin_token, hep_user.hep_id) + + if product and License.objects.filter(licensee=hep_user, order_id=product['order_id']).count() == 0: + license = License.objects.create_license_for_role(hep_user, product['activated'], product['raw'], + product['edition'], product['order_id']) + + if license.is_valid(): + hep_user.license_expiry_date = license.expire_date + hep_user.save() diff --git a/server/users/managers.py b/server/users/managers.py index e20312cf..fc33bc20 100644 --- a/server/users/managers.py +++ b/server/users/managers.py @@ -1,9 +1,15 @@ +from datetime import timedelta + +from django.apps import apps from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType +from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.db import models from django.contrib.auth.models import UserManager as DjangoUserManager +from core.hep_client import TEACHER_EDITION_DURATION, STUDENT_EDITION_DURATION + class RoleManager(models.Manager): use_in_migrations = True @@ -66,14 +72,18 @@ class RoleManager(models.Manager): class UserRoleManager(models.Manager): - def create_role_for_user(self, user, role_key): + def get_or_create_role_for_user(self, user, role_key): from users.models import Role try: role = Role.objects.get(key=role_key) except Role.DoesNotExist: return None - return self._create_user_role(user, role) + try: + user_role = self.model.objects.get(role=role, user=user) + return user_role + except self.model.DoesNotExist: + return self._create_user_role(user, role) def _create_user_role(self, user, role): user_role = self.model(user=user, role=role) @@ -82,10 +92,66 @@ class UserRoleManager(models.Manager): class UserManager(DjangoUserManager): - def create_user_with_random_password(self, first_name, last_name, email): + + def _create_user_with_random_password_no_save(self, first_name, last_name, email): user, created = self.model.objects.get_or_create(email=email, username=email) user.first_name = first_name user.last_name = last_name - user.set_password(self.model.objects.make_random_password()) + # Todo: remove if not used + # user.set_password(self.model.objects.make_random_password()) + user.set_unusable_password() + return user + + def create_user_with_random_password(self, first_name, last_name, email): + user = self._create_user_with_random_password_no_save(first_name, last_name, email) user.save() return user + + def create_user_from_hep(self, user_data): + try: + user = self.model.objects.get(email=user_data['email']) + user.set_unusable_password() + except self.model.DoesNotExist: + user = self._create_user_with_random_password_no_save( user_data['firstname'], + user_data['lastname'], + user_data['email']) + + user.hep_id = user_data['id'] + user.hep_group_id = user_data['group_id'] + user.save() + return user + + +class LicenseManager(models.Manager): + + def create_license_for_role(self, licensee, activation_date, raw, role, order_id): + Role = apps.get_model('users', 'Role') + if role == 'teacher': + user_role = Role.objects.get_default_teacher_role() + expiry_date = activation_date + timedelta(TEACHER_EDITION_DURATION) + else: + user_role = Role.objects.get_default_student_role() + expiry_date = activation_date + timedelta(STUDENT_EDITION_DURATION) + + new_license = self._create_license_for_role(licensee, expiry_date, raw, user_role, order_id) + new_license.licensee.license_expiry_date = new_license.expire_date + new_license.licensee.save() + + return new_license + + def _create_license_for_role(self, licensee, expiry_date, raw, role, order_id): + return self.create(licensee=licensee, expire_date=expiry_date, raw=raw, for_role=role, order_id=order_id) + + def get_active_license_for_user(self, user): + licenses = self.filter(licensee=user, expire_date__gte=timezone.now()).order_by('-expire_date') + if len(licenses) == 0: + return None + + license = licenses[0] + + # update license on user + user.license_expiry_date = license.expire_date + user.save() + + return license + diff --git a/server/users/migrations/0017_auto_20200430_1251.py b/server/users/migrations/0017_auto_20200430_1251.py new file mode 100644 index 00000000..430e9d47 --- /dev/null +++ b/server/users/migrations/0017_auto_20200430_1251.py @@ -0,0 +1,45 @@ +# Generated by Django 2.1.15 on 2020-04-30 12:51 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0016_auto_20200304_1250'), + ] + + operations = [ + migrations.CreateModel( + name='License', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('expire_date', models.DateField(null=True)), + ('order_id', models.IntegerField(default=-1)), + ('raw', models.TextField(default='')), + ('for_role', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.Role')), + ], + ), + migrations.AddField( + model_name='user', + name='hep_group_id', + field=models.PositiveIntegerField(null=True), + ), + migrations.AddField( + model_name='user', + name='hep_id', + field=models.PositiveIntegerField(null=True), + ), + migrations.AddField( + model_name='user', + name='license_expiry_date', + field=models.DateField(default=None, null=True), + ), + migrations.AddField( + model_name='license', + name='licensee', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/server/users/models.py b/server/users/models.py index 6b8659e2..99fd867b 100644 --- a/server/users/models.py +++ b/server/users/models.py @@ -1,4 +1,5 @@ import re +from datetime import datetime import string import random @@ -8,7 +9,8 @@ from django.core.exceptions import ObjectDoesNotExist from django.db import models from django.utils.translation import ugettext_lazy as _ -from users.managers import RoleManager, UserRoleManager, UserManager +from core.hep_client import HepClient +from users.managers import RoleManager, UserRoleManager, UserManager, LicenseManager DEFAULT_SCHOOL_ID = 1 @@ -17,6 +19,9 @@ class User(AbstractUser): last_module = models.ForeignKey('books.Module', related_name='+', on_delete=models.SET_NULL, null=True) avatar_url = models.CharField(max_length=254, blank=True, default='') email = models.EmailField(_('email address'), unique=True) + hep_id = models.PositiveIntegerField(null=True, blank=False) + hep_group_id = models.PositiveIntegerField(null=True, blank=False) + license_expiry_date = models.DateField(blank=False, null=True, default=None) objects = UserManager() @@ -66,11 +71,32 @@ class User(AbstractUser): else: return None + def sync_with_hep_data(self, hep_data): + + data_has_changed = False + + if self.email != hep_data['email']: + self.email = hep_data['email'] + self.username = hep_data['email'] + data_has_changed = True + + if self.first_name != hep_data['firstname']: + self.first_name = hep_data['firstname'] + data_has_changed = True + + if self.last_name != hep_data['lastname']: + self.last_name = hep_data['lastname'] + data_has_changed = True + + if data_has_changed: + self.save() + def set_selected_class(self, school_class): user_settings, created = UserSetting.objects.get_or_create(user=self) user_settings.selected_class = school_class user_settings.save() + @property def full_name(self): return self.get_full_name() @@ -111,6 +137,15 @@ class SchoolClass(models.Model): return '{} {}'.format(prefix, index + 1) + @classmethod + def create_default_group_for_teacher(cls, user): + default_class_name = cls.generate_default_group_name() + default_class = cls.objects.create(name=default_class_name) + SchoolClassMember.objects.create( + user=user, + school_class=default_class + ) + def is_user_in_schoolclass(self, user): return user.is_superuser or user.school_classes.filter(pk=self.id).count() > 0 @@ -201,7 +236,28 @@ class UserSetting(models.Model): selected_class = models.ForeignKey(SchoolClass, blank=True, null=True, on_delete=models.CASCADE) +class License(models.Model): + for_role = models.ForeignKey(Role, blank=False, null=True, on_delete=models.CASCADE) + licensee = models.ForeignKey(User, blank=False, null=True, on_delete=models.CASCADE) + expire_date = models.DateField(blank=False, null=True,) + order_id = models.IntegerField(blank=False, null=False, default=-1) + raw = models.TextField(default='') + + objects = LicenseManager() + + def is_teacher_license(self): + return self.for_role.key == RoleManager.TEACHER_KEY + + def is_valid(self): + return HepClient.is_product_active(datetime(self.expire_date.year, self.expire_date.month, self.expire_date.day), + self.for_role.key) + + def __str__(self): + return f'License for role: {self.for_role}' + + class SchoolClassMember(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE) active = models.BooleanField(default=True) + diff --git a/server/users/mutations_public.py b/server/users/mutations_public.py index 565b9d84..4ed9a3ae 100644 --- a/server/users/mutations_public.py +++ b/server/users/mutations_public.py @@ -9,50 +9,78 @@ # @author: chrigu import graphene +from django.conf import settings from django.contrib.auth import authenticate, login from graphene import relay -from registration.models import License +from core.hep_client import HepClient, HepClientUnauthorizedException, HepClientException +from users.user_signup_login_handler import handle_user_and_verify_products, UNKNOWN_ERROR, EMAIL_NOT_VERIFIED -class LoginError(graphene.ObjectType): - field = graphene.String() - - -class Login(relay.ClientIDMutation): +class BetaLogin(relay.ClientIDMutation): class Input: username_input = graphene.String() password_input = graphene.String() success = graphene.Boolean() - errors = graphene.List(LoginError) # todo: change for consistency + message = graphene.String() + + @classmethod + def mutate_and_get_payload(cls, root, info, **kwargs): + if settings.ALLOW_BETA_LOGIN: + password = kwargs.get('password_input') + username = kwargs.get('username_input') + user = authenticate(username=username, password=password) + if user is None: + raise Exception('invalid_credentials') + login(info.context, user) + + return cls(success=True, message='') + + raise Exception('not_implemented') + + +class Login(relay.ClientIDMutation): + class Input: + token_input = graphene.String() + + success = graphene.Boolean() + message = graphene.String() @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): - user = authenticate(username=kwargs.get('username_input'), password=kwargs.get('password_input')) - if user is None: - error = LoginError(field='invalid_credentials') - return cls(success=False, errors=[error]) - - user_license = None + hep_client = HepClient() + token = kwargs.get('token_input') try: - user_license = License.objects.get(licensee=user) - except License.DoesNotExist: - # current users have no license, allow them to login - pass + user_data = hep_client.customer_me(token) + except HepClientUnauthorizedException: + return cls.return_login_message('invalid_credentials') + except HepClientException: + return cls.return_login_message(UNKNOWN_ERROR) - if user_license is not None and not user_license.license_type.active: - error = LoginError(field='license_inactive') - return cls(success=False, errors=[error]) + user, status_msg = handle_user_and_verify_products(user_data) + user.sync_with_hep_data(user_data) - login(info.context, user) - return cls(success=True, errors=[]) + if user and status_msg != EMAIL_NOT_VERIFIED: + login(info.context, user) + + if status_msg: + return cls.return_login_message(status_msg) + + return cls(success=True, message='success') + + @classmethod + def return_login_message(cls, message): + if message == EMAIL_NOT_VERIFIED or message == UNKNOWN_ERROR or message == 'invalid_credentials': + raise Exception(message) + return cls(success=True, message=message) class UserMutations: login = Login.Field() + beta_login = BetaLogin.Field() diff --git a/server/users/schema.py b/server/users/schema.py index e76162c7..b23434d9 100644 --- a/server/users/schema.py +++ b/server/users/schema.py @@ -1,9 +1,11 @@ +from datetime import datetime + import graphene -from django.db.models import Prefetch, Value, CharField, Q -from django.db.models.functions import Concat +from django.db.models import Q from graphene import relay, ObjectType from graphene_django import DjangoObjectType from graphene_django.filter import DjangoFilterConnectionField +from django.utils.dateformat import format from graphql_relay import to_global_id from basicknowledge.models import BasicKnowledge @@ -41,6 +43,7 @@ class UserNode(DjangoObjectType): pk = graphene.Int() permissions = graphene.List(graphene.String) selected_class = graphene.Field(SchoolClassNode) + expiry_date = graphene.String() is_teacher = graphene.Boolean() old_classes = DjangoFilterConnectionField(SchoolClassNode) @@ -48,7 +51,7 @@ class UserNode(DjangoObjectType): model = User filter_fields = ['username', 'email'] only_fields = ['username', 'email', 'first_name', 'last_name', 'school_classes', 'last_module', 'avatar_url', - 'selected_class'] + 'selected_class', 'expiry_date'] interfaces = (relay.Node,) def resolve_pk(self, info, **kwargs): @@ -60,6 +63,12 @@ class UserNode(DjangoObjectType): def resolve_selected_class(self, info): return self.selected_class() + def resolve_expiry_date(self, info): + if not self.hep_id: # concerns users that already have an (old) account + return format(datetime(2020, 7, 31), 'U') # just set some expiry date + else: + return self.license_expiry_date + def resolve_is_teacher(self, info): return self.is_teacher() diff --git a/server/users/tests/test_local_login.py b/server/users/tests/test_local_login.py new file mode 100644 index 00000000..a5e2089a --- /dev/null +++ b/server/users/tests/test_local_login.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# +# ITerativ GmbH +# http://www.iterativ.ch/ +# +# Copyright (c) 2019 ITerativ GmbH. All rights reserved. +# +# Created on 2019-10-02 +# @author: chrigu +from django.contrib.sessions.middleware import SessionMiddleware +from django.test import TestCase, RequestFactory +from graphene.test import Client + +from api.schema_public import schema +from core.factories import UserFactory +from users.models import Role + + +class BetaLoginTests(TestCase): + def setUp(self): + self.user = UserFactory(username='aschi@iterativ.ch', email='aschi@iterativ.ch') + self.teacher_role = Role.objects.create(key=Role.objects.TEACHER_KEY, name="Teacher Role") + + request = RequestFactory().post('/') + + # adding session + middleware = SessionMiddleware() + middleware.process_request(request) + request.session.save() + self.client = Client(schema=schema, context_value=request) + + def make_login_mutation(self, username, password): + mutation = ''' + mutation BetaLogin($input: BetaLoginInput!){ + betaLogin(input: $input) { + success + } + } + ''' + + return self.client.execute(mutation, variables={ + 'input': { + 'usernameInput': username, + 'passwordInput': password + } + }) + + def test_user_can_login(self): + password = 'test123' + self.user.set_password(password) + self.user.save() + + result = self.make_login_mutation(self.user.email, password) + self.assertTrue(result.get('data').get('betaLogin').get('success')) + self.assertTrue(self.user.is_authenticated) + + def test_user_cannot_login_with_invalid_password(self): + password = 'test123' + self.user.set_password(password) + self.user.save() + + result = self.make_login_mutation(self.user.email, 'test1234') + self.assertEqual(result.get('errors')[0].get('message'), 'invalid_credentials') + diff --git a/server/users/tests/test_login.py b/server/users/tests/test_login.py index 68433116..1ce8b9ed 100644 --- a/server/users/tests/test_login.py +++ b/server/users/tests/test_login.py @@ -7,21 +7,33 @@ # # Created on 2019-10-02 # @author: chrigu +import json +import os +from datetime import timedelta +from unittest.mock import patch + +import requests from django.contrib.sessions.middleware import SessionMiddleware from django.test import TestCase, RequestFactory +from django.utils import timezone from graphene.test import Client from api.schema_public import schema from core.factories import UserFactory -from registration.factories import LicenseTypeFactory, LicenseFactory -from users.models import Role +from core.hep_client import HepClient +from core.tests.mock_hep_data_factory import MockResponse, ME_DATA, VALID_STUDENT_ORDERS, VALID_TEACHERS_ORDERS, \ + NOT_CONFIRMED_ME +from users.factories import LicenseFactory +from users.models import Role, User, SchoolClass, License + +TOKEN = 'abcd12345!' -class PasswordResetTests(TestCase): +class LoginTests(TestCase): def setUp(self): - self.user = UserFactory(username='aschi@iterativ.ch', email='aschi@iterativ.ch') - self.teacher_role = Role.objects.create(key=Role.objects.TEACHER_KEY, name="Teacher Role") - self.teacher_license_type = LicenseTypeFactory(for_role=self.teacher_role) + self.user = UserFactory(username=ME_DATA['id'], email=ME_DATA['id']) + Role.objects.create_default_roles() + self.teacher_role = Role.objects.get_default_teacher_role() request = RequestFactory().post('/') @@ -31,60 +43,185 @@ class PasswordResetTests(TestCase): request.session.save() self.client = Client(schema=schema, context_value=request) - def make_login_mutation(self, username, password): + def make_login_mutation(self, token): mutation = ''' mutation Login($input: LoginInput!){ login(input: $input) { success - errors { - field - } + message } } ''' return self.client.execute(mutation, variables={ 'input': { - 'usernameInput': username, - 'passwordInput': password + 'tokenInput': token } }) - def test_user_can_login(self): - password = 'test123' - self.user.set_password(password) + @patch.object(HepClient, 'customer_me', return_value=ME_DATA) + def test_user_can_login_with_local_user_and_valid_local_license(self, me_mock): + + self.user.hep_id = ME_DATA['id'] self.user.save() - result = self.make_login_mutation(self.user.email, password) + now = timezone.now() + expiry_date = now + timedelta(100) + LicenseFactory(expire_date=expiry_date, licensee=self.user, for_role=self.teacher_role).save() + + result = self.make_login_mutation(TOKEN) + self.assertTrue(result.get('data').get('login').get('success')) self.assertTrue(self.user.is_authenticated) - def test_user_cannot_login_with_invalid_password(self): - password = 'test123' - self.user.set_password(password) + reloaded_user = User.objects.get(pk=self.user.id) + self.assertEqual(reloaded_user.license_expiry_date, expiry_date.date()) + + @patch.object(HepClient, 'customer_me', return_value=ME_DATA) + def test_user_can_login_with_local_user_and_valid_local_licenses(self, me_mock): + + self.user.hep_id = ME_DATA['id'] self.user.save() - result = self.make_login_mutation(self.user.email, 'test1234') - self.assertFalse(result.get('data').get('login').get('success')) + now = timezone.now() + expiry_date1 = now + timedelta(100) + expiry_date2 = now + timedelta(110) - def test_user_with_active_license_can_login(self): - password = 'test123' - self.user.set_password(password) - self.user.save() + LicenseFactory(expire_date=expiry_date1, licensee=self.user, for_role=self.teacher_role).save() + LicenseFactory(expire_date=expiry_date2, licensee=self.user, for_role=self.teacher_role).save() - LicenseFactory(license_type=self.teacher_license_type, licensee=self.user) + result = self.make_login_mutation(TOKEN) - result = self.make_login_mutation(self.user.email, password) self.assertTrue(result.get('data').get('login').get('success')) + self.assertTrue(self.user.is_authenticated) - def test_user_with_inactive_license_cannot_login(self): - password = 'test123' - self.user.set_password(password) + reloaded_user = User.objects.get(pk=self.user.id) + self.assertEqual(reloaded_user.license_expiry_date, expiry_date2.date()) + + @patch.object(HepClient, 'customer_me', return_value=ME_DATA) + def test_user_data_is_synced_on_login(self, me_mock): + + old_mail = 'aschi@iterativ.ch' + + self.user.hep_id = ME_DATA['id'] + self.user.email = old_mail + self.user.username = old_mail self.user.save() - self.teacher_license_type.active = False - self.teacher_license_type.save() - LicenseFactory(license_type=self.teacher_license_type, licensee=self.user) + now = timezone.now() + expiry_date = now + timedelta(365) + LicenseFactory(expire_date=expiry_date, licensee=self.user, for_role=self.teacher_role).save() - result = self.make_login_mutation(self.user.email, password) - self.assertFalse(result.get('data').get('login').get('success')) + result = self.make_login_mutation(TOKEN) + + user = User.objects.get(hep_id=self.user.hep_id) + + self.assertEqual(user.username, ME_DATA['email']) + self.assertEqual(user.email, ME_DATA['email']) + self.assertTrue(result.get('data').get('login').get('success')) + self.assertTrue(self.user.is_authenticated) + + @patch.object(HepClient, 'customer_me', return_value=ME_DATA) + def test_user_can_login_with_local_user_and_valid_local_licenses(self, me_mock): + + self.user.hep_id = ME_DATA['id'] + self.user.save() + + now = timezone.now() + expiry_date1 = now + timedelta(365) + expiry_date2 = now + timedelta(366) + + LicenseFactory(expire_date=expiry_date1, licensee=self.user, for_role=self.teacher_role).save() + LicenseFactory(expire_date=expiry_date2, licensee=self.user, for_role=self.teacher_role).save() + + result = self.make_login_mutation(TOKEN) + + self.assertTrue(result.get('data').get('login').get('success')) + self.assertTrue(self.user.is_authenticated) + + @patch.object(HepClient, '_customer_orders', return_value=VALID_TEACHERS_ORDERS) + @patch.object(HepClient, 'customer_me', return_value=ME_DATA) + @patch.object(HepClient, 'fetch_admin_token', return_value={'token': 'AABBCCDDEE**44566'}) + def test_teacher_can_login_with_remote_user_and_remote_license(self, order_mock, me_mock, admin_token_mock): + result = self.make_login_mutation(TOKEN) + + user = User.objects.get(email=ME_DATA['email']) + + user_role_key = user.user_roles.get(user=user).role.key + self.assertEqual(user_role_key, Role.objects.TEACHER_KEY) + + license = License.objects.get(licensee=user) + self.assertEqual(license.for_role.key, Role.objects.TEACHER_KEY) + + school_class = SchoolClass.objects.get(users__in=[user]) + self.assertIsNotNone(school_class) + + self.assertTrue(result.get('data').get('login').get('success')) + self.assertTrue(self.user.is_authenticated) + + @patch.object(HepClient, '_customer_orders', return_value=VALID_STUDENT_ORDERS) + @patch.object(HepClient, 'customer_me', return_value=ME_DATA) + @patch.object(HepClient, 'fetch_admin_token', return_value={'token': 'AABBCCDDEE**44566'}) + def test_student_can_login_with_remote_user_and_remote_license(self, order_mock, me_mock, admin_token_mock): + + result = self.make_login_mutation(TOKEN) + user = User.objects.get(email=ME_DATA['email']) + + user_role_key = user.user_roles.get(user=user).role.key + self.assertEqual(user_role_key, Role.objects.STUDENT_KEY) + + license = License.objects.get(licensee=user) + self.assertEqual(license.for_role.key, Role.objects.STUDENT_KEY) + + self.assertTrue(result.get('data').get('login').get('success')) + self.assertTrue(self.user.is_authenticated) + + @patch.object(requests, 'post', return_value=MockResponse(401)) + def test_user_with_no_login_cannot_login(self, post_mock): + result = self.make_login_mutation('some') + + self.assertEqual(result.get('errors')[0].get('message'), 'invalid_credentials') + + @patch.object(HepClient, 'is_email_verified', return_value=False) + @patch.object(HepClient, 'customer_me', return_value=ME_DATA) + def test_user_with_unconfirmed_email_cannot_login(self, me_mock, post_mock): + result = self.make_login_mutation(TOKEN) + + User.objects.get(email=ME_DATA['email']) + self.assertEqual(result.get('errors')[0].get('message'), 'email_not_verified') + + @patch.object(HepClient, 'myskillbox_product_for_customer', return_value=None) + @patch.object(HepClient, 'customer_me', return_value=ME_DATA) + @patch.object(HepClient, 'fetch_admin_token', return_value={'token': 'AABBCCDDEE**44566'}) + def test_user_can_login_without_license(self, me_mock, product_mock, admin_token_mock): + result = self.make_login_mutation(TOKEN) + + self.assertTrue(result.get('data').get('login').get('success')) + self.assertEqual(result.get('data').get('login').get('message'), 'no_valid_license') + self.assertTrue(self.user.is_authenticated) + + @patch.object(HepClient, 'myskillbox_product_for_customer', return_value=None) + @patch.object(HepClient, 'customer_me', return_value=ME_DATA) + @patch.object(HepClient, 'fetch_admin_token', return_value={'token': 'AABBCCDDEE**44566'}) + def test_user_can_login_local_license_invalid(self, product_mock, me_mock, admin_token_mock): + now = timezone.now() + expiry_date = now - timedelta(1) + LicenseFactory(expire_date=expiry_date, licensee=self.user, for_role=self.teacher_role).save() + + result = self.make_login_mutation(TOKEN) + + self.assertTrue(result.get('data').get('login').get('success')) + self.assertEqual(result.get('data').get('login').get('message'), 'no_valid_license') + self.assertTrue(self.user.is_authenticated) + + @patch.object(HepClient, 'customer_me', return_value=NOT_CONFIRMED_ME) + def test_user_can_login_with_unconfirmed_email(self, me_mock): + result = self.make_login_mutation(TOKEN) + + self.assertEqual(result.get('errors')[0].get('message'), 'email_not_verified') + + @patch.object(requests, 'get', return_value=MockResponse(500)) + def test_user_gets_notified_if_server_error(self, post_mock): + result = self.make_login_mutation(TOKEN) + + self.assertEqual(result.get('errors')[0].get('message'), 'unknown_error') diff --git a/server/users/user_signup_login_handler.py b/server/users/user_signup_login_handler.py new file mode 100644 index 00000000..4247ed71 --- /dev/null +++ b/server/users/user_signup_login_handler.py @@ -0,0 +1,67 @@ +from core.hep_client import HepClient, HepClientException +from core.models import AdminData +from users.models import License +from users.models import User, UserRole, Role, SchoolClass + + +EMAIL_NOT_VERIFIED = 'email_not_verified' +UNKNOWN_ERROR = 'unknown_error' +NO_VALID_LICENSE = 'no_valid_license' + + +def handle_user_and_verify_products(user_data): + hep_client = HepClient() + + try: + user = User.objects.get(hep_id=user_data['id']) + except User.DoesNotExist: + user = User.objects.create_user_from_hep(user_data) + + try: + if not hep_client.is_email_verified(user_data): + return user, EMAIL_NOT_VERIFIED + except HepClientException: + return user, UNKNOWN_ERROR + + license = License.objects.get_active_license_for_user(user) + + if not license: + license, error_msg = check_and_create_licenses(hep_client, user) + + if error_msg: + return user, error_msg + + create_role_for_user(user, license.for_role.key) + + if not license.is_valid(): + return user, NO_VALID_LICENSE + + return user, None + + +def check_and_create_licenses(hep_client, user): + try: + admin_token = AdminData.objects.get_admin_token() + product = hep_client.myskillbox_product_for_customer(admin_token, user.hep_id) + except HepClientException: + return None, UNKNOWN_ERROR + + if product: + license = License.objects.create_license_for_role(user, product['activated'], product['raw'], + product['edition'], product['order_id']) + # todo handle no license case + else: + return None, NO_VALID_LICENSE + + return license, None + + +def create_role_for_user(user, role_key): + UserRole.objects.get_or_create_role_for_user(user, role_key) + + if role_key == Role.objects.STUDENT_KEY: + return + + if SchoolClass.objects.filter(users__in=[user]).count() == 0: + SchoolClass.create_default_group_for_teacher(user) +