Migrate form data to json field
This commit is contained in:
parent
f5c7ab77e1
commit
aa5b744285
|
|
@ -157,12 +157,9 @@ const MAX_STEPS = 12;
|
||||||
const sendFeedbackMutation = graphql(`
|
const sendFeedbackMutation = graphql(`
|
||||||
mutation SendFeedbackMutation($input: SendFeedbackInput!) {
|
mutation SendFeedbackMutation($input: SendFeedbackInput!) {
|
||||||
sendFeedback(input: $input) {
|
sendFeedback(input: $input) {
|
||||||
id
|
feedbackResponse {
|
||||||
satisfaction
|
id
|
||||||
goalAttainment
|
}
|
||||||
proficiency
|
|
||||||
receivedMaterials
|
|
||||||
materialsRating
|
|
||||||
errors {
|
errors {
|
||||||
field
|
field
|
||||||
messages
|
messages
|
||||||
|
|
@ -205,17 +202,19 @@ const sendFeedback = () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const input: SendFeedbackInput = reactive({
|
const input: SendFeedbackInput = reactive({
|
||||||
materialsRating,
|
data: {
|
||||||
courseNegativeFeedback,
|
materials_rating: materialsRating,
|
||||||
coursePositiveFeedback,
|
course_negative_feedback: courseNegativeFeedback,
|
||||||
goalAttainment,
|
course_positive_feedback: coursePositiveFeedback,
|
||||||
instructorCompetence,
|
goald_attainment: goalAttainment,
|
||||||
instructorRespect,
|
instructor_competence: instructorCompetence,
|
||||||
instructorOpenFeedback,
|
instructor_respect: instructorRespect,
|
||||||
satisfaction,
|
instructor_open_feedback: instructorOpenFeedback,
|
||||||
proficiency,
|
satisfaction,
|
||||||
receivedMaterials,
|
proficiency,
|
||||||
wouldRecommend,
|
received_materials: receivedMaterials,
|
||||||
|
would_recommend: wouldRecommend,
|
||||||
|
},
|
||||||
page: props.page.translation_key,
|
page: props.page.translation_key,
|
||||||
courseSession: courseSession.id,
|
courseSession: courseSession.id,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@ import type { TypedDocumentNode as DocumentNode } from "@graphql-typed-document-
|
||||||
import * as types from "./graphql";
|
import * as types from "./graphql";
|
||||||
|
|
||||||
const documents = {
|
const documents = {
|
||||||
"\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n sendFeedback(input: $input) {\n id\n satisfaction\n goalAttainment\n proficiency\n receivedMaterials\n materialsRating\n errors {\n field\n messages\n }\n }\n }\n":
|
"\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n sendFeedback(input: $input) {\n feedbackResponse {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n":
|
||||||
types.SendFeedbackMutationDocument,
|
types.SendFeedbackMutationDocument,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function graphql(
|
export function graphql(
|
||||||
source: "\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n sendFeedback(input: $input) {\n id\n satisfaction\n goalAttainment\n proficiency\n receivedMaterials\n materialsRating\n errors {\n field\n messages\n }\n }\n }\n"
|
source: "\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n sendFeedback(input: $input) {\n feedbackResponse {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n"
|
||||||
): typeof documents["\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n sendFeedback(input: $input) {\n id\n satisfaction\n goalAttainment\n proficiency\n receivedMaterials\n materialsRating\n errors {\n field\n messages\n }\n }\n }\n"];
|
): typeof documents["\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n sendFeedback(input: $input) {\n feedbackResponse {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n"];
|
||||||
|
|
||||||
export function graphql(source: string): unknown;
|
export function graphql(source: string): unknown;
|
||||||
export function graphql(source: string) {
|
export function graphql(source: string) {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ export type Scalars = {
|
||||||
Int: number;
|
Int: number;
|
||||||
Float: number;
|
Float: number;
|
||||||
DateTime: any;
|
DateTime: any;
|
||||||
|
GenericScalar: any;
|
||||||
JSONString: any;
|
JSONString: any;
|
||||||
PositiveInt: any;
|
PositiveInt: any;
|
||||||
UUID: any;
|
UUID: any;
|
||||||
|
|
@ -152,6 +153,11 @@ export type CircleSiblingsArgs = {
|
||||||
searchQuery?: InputMaybe<Scalars["String"]>;
|
searchQuery?: InputMaybe<Scalars["String"]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CircleDocument = {
|
||||||
|
__typename?: "CircleDocument";
|
||||||
|
id?: Maybe<Scalars["ID"]>;
|
||||||
|
};
|
||||||
|
|
||||||
export type CollectionObjectType = {
|
export type CollectionObjectType = {
|
||||||
__typename?: "CollectionObjectType";
|
__typename?: "CollectionObjectType";
|
||||||
ancestors: Array<Maybe<CollectionObjectType>>;
|
ancestors: Array<Maybe<CollectionObjectType>>;
|
||||||
|
|
@ -520,6 +526,14 @@ export type ErrorType = {
|
||||||
messages: Array<Scalars["String"]>;
|
messages: Array<Scalars["String"]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type FeedbackResponse = Node & {
|
||||||
|
__typename?: "FeedbackResponse";
|
||||||
|
circle: Circle;
|
||||||
|
courseSession: CourseSession;
|
||||||
|
data?: Maybe<Scalars["GenericScalar"]>;
|
||||||
|
id: Scalars["ID"];
|
||||||
|
};
|
||||||
|
|
||||||
export type FloatBlock = StreamFieldInterface & {
|
export type FloatBlock = StreamFieldInterface & {
|
||||||
__typename?: "FloatBlock";
|
__typename?: "FloatBlock";
|
||||||
blockType: Scalars["String"];
|
blockType: Scalars["String"];
|
||||||
|
|
@ -1170,6 +1184,10 @@ export type MutationSendFeedbackArgs = {
|
||||||
input: SendFeedbackInput;
|
input: SendFeedbackInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Node = {
|
||||||
|
id: Scalars["ID"];
|
||||||
|
};
|
||||||
|
|
||||||
export type Page = PageInterface & {
|
export type Page = PageInterface & {
|
||||||
__typename?: "Page";
|
__typename?: "Page";
|
||||||
aliasOf?: Maybe<Page>;
|
aliasOf?: Maybe<Page>;
|
||||||
|
|
@ -1581,6 +1599,7 @@ export type RichTextBlock = StreamFieldInterface & {
|
||||||
|
|
||||||
export type Search =
|
export type Search =
|
||||||
| Circle
|
| Circle
|
||||||
|
| CircleDocument
|
||||||
| CompetencePage
|
| CompetencePage
|
||||||
| CompetenceProfilePage
|
| CompetenceProfilePage
|
||||||
| Course
|
| Course
|
||||||
|
|
@ -1609,37 +1628,16 @@ export type SecurityRequestResponseLog = {
|
||||||
|
|
||||||
export type SendFeedbackInput = {
|
export type SendFeedbackInput = {
|
||||||
clientMutationId?: InputMaybe<Scalars["String"]>;
|
clientMutationId?: InputMaybe<Scalars["String"]>;
|
||||||
courseNegativeFeedback?: InputMaybe<Scalars["String"]>;
|
courseSession: Scalars["Int"];
|
||||||
coursePositiveFeedback?: InputMaybe<Scalars["String"]>;
|
data?: InputMaybe<Scalars["GenericScalar"]>;
|
||||||
goalAttainment?: InputMaybe<Scalars["Int"]>;
|
|
||||||
id?: InputMaybe<Scalars["Int"]>;
|
|
||||||
instructorCompetence?: InputMaybe<Scalars["Int"]>;
|
|
||||||
instructorOpenFeedback?: InputMaybe<Scalars["String"]>;
|
|
||||||
instructorRespect?: InputMaybe<Scalars["Int"]>;
|
|
||||||
materialsRating?: InputMaybe<Scalars["Int"]>;
|
|
||||||
page: Scalars["String"];
|
page: Scalars["String"];
|
||||||
proficiency?: InputMaybe<Scalars["Int"]>;
|
|
||||||
receivedMaterials?: InputMaybe<Scalars["Boolean"]>;
|
|
||||||
satisfaction?: InputMaybe<Scalars["Int"]>;
|
|
||||||
wouldRecommend?: InputMaybe<Scalars["Boolean"]>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SendFeedbackPayload = {
|
export type SendFeedbackPayload = {
|
||||||
__typename?: "SendFeedbackPayload";
|
__typename?: "SendFeedbackPayload";
|
||||||
clientMutationId?: Maybe<Scalars["String"]>;
|
clientMutationId?: Maybe<Scalars["String"]>;
|
||||||
courseNegativeFeedback?: Maybe<Scalars["String"]>;
|
|
||||||
coursePositiveFeedback?: Maybe<Scalars["String"]>;
|
|
||||||
errors?: Maybe<Array<Maybe<ErrorType>>>;
|
errors?: Maybe<Array<Maybe<ErrorType>>>;
|
||||||
goalAttainment?: Maybe<Scalars["Int"]>;
|
feedbackResponse?: Maybe<FeedbackResponse>;
|
||||||
id?: Maybe<Scalars["Int"]>;
|
|
||||||
instructorCompetence?: Maybe<Scalars["Int"]>;
|
|
||||||
instructorOpenFeedback?: Maybe<Scalars["String"]>;
|
|
||||||
instructorRespect?: Maybe<Scalars["Int"]>;
|
|
||||||
materialsRating?: Maybe<Scalars["Int"]>;
|
|
||||||
proficiency?: Maybe<Scalars["Int"]>;
|
|
||||||
receivedMaterials?: Maybe<Scalars["Boolean"]>;
|
|
||||||
satisfaction?: Maybe<Scalars["Int"]>;
|
|
||||||
wouldRecommend?: Maybe<Scalars["Boolean"]>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SiteObjectType = {
|
export type SiteObjectType = {
|
||||||
|
|
@ -1851,12 +1849,7 @@ export type SendFeedbackMutationMutation = {
|
||||||
__typename?: "Mutation";
|
__typename?: "Mutation";
|
||||||
sendFeedback?: {
|
sendFeedback?: {
|
||||||
__typename?: "SendFeedbackPayload";
|
__typename?: "SendFeedbackPayload";
|
||||||
id?: number | null;
|
feedbackResponse?: { __typename?: "FeedbackResponse"; id: string } | null;
|
||||||
satisfaction?: number | null;
|
|
||||||
goalAttainment?: number | null;
|
|
||||||
proficiency?: number | null;
|
|
||||||
receivedMaterials?: boolean | null;
|
|
||||||
materialsRating?: number | null;
|
|
||||||
errors?: Array<{
|
errors?: Array<{
|
||||||
__typename?: "ErrorType";
|
__typename?: "ErrorType";
|
||||||
field: string;
|
field: string;
|
||||||
|
|
@ -1901,12 +1894,16 @@ export const SendFeedbackMutationDocument = {
|
||||||
selectionSet: {
|
selectionSet: {
|
||||||
kind: "SelectionSet",
|
kind: "SelectionSet",
|
||||||
selections: [
|
selections: [
|
||||||
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
{
|
||||||
{ kind: "Field", name: { kind: "Name", value: "satisfaction" } },
|
kind: "Field",
|
||||||
{ kind: "Field", name: { kind: "Name", value: "goalAttainment" } },
|
name: { kind: "Name", value: "feedbackResponse" },
|
||||||
{ kind: "Field", name: { kind: "Name", value: "proficiency" } },
|
selectionSet: {
|
||||||
{ kind: "Field", name: { kind: "Name", value: "receivedMaterials" } },
|
kind: "SelectionSet",
|
||||||
{ kind: "Field", name: { kind: "Name", value: "materialsRating" } },
|
selections: [
|
||||||
|
{ kind: "Field", name: { kind: "Name", value: "id" } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
kind: "Field",
|
kind: "Field",
|
||||||
name: { kind: "Name", value: "errors" },
|
name: { kind: "Name", value: "errors" },
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,10 @@ type Circle implements PageInterface {
|
||||||
ancestors(limit: PositiveInt, offset: PositiveInt, order: String, searchQuery: String, id: ID): [PageInterface!]!
|
ancestors(limit: PositiveInt, offset: PositiveInt, order: String, searchQuery: String, id: ID): [PageInterface!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CircleDocument {
|
||||||
|
id: ID
|
||||||
|
}
|
||||||
|
|
||||||
type CollectionObjectType {
|
type CollectionObjectType {
|
||||||
id: ID!
|
id: ID!
|
||||||
path: String!
|
path: String!
|
||||||
|
|
@ -281,6 +285,13 @@ type ErrorType {
|
||||||
messages: [String!]!
|
messages: [String!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FeedbackResponse implements Node {
|
||||||
|
id: ID!
|
||||||
|
data: GenericScalar
|
||||||
|
circle: Circle!
|
||||||
|
courseSession: CourseSession!
|
||||||
|
}
|
||||||
|
|
||||||
type FloatBlock implements StreamFieldInterface {
|
type FloatBlock implements StreamFieldInterface {
|
||||||
id: String
|
id: String
|
||||||
blockType: String!
|
blockType: String!
|
||||||
|
|
@ -289,6 +300,8 @@ type FloatBlock implements StreamFieldInterface {
|
||||||
value: Float!
|
value: Float!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scalar GenericScalar
|
||||||
|
|
||||||
type ImageChooserBlock implements StreamFieldInterface {
|
type ImageChooserBlock implements StreamFieldInterface {
|
||||||
id: String
|
id: String
|
||||||
blockType: String!
|
blockType: String!
|
||||||
|
|
@ -608,6 +621,10 @@ type Mutation {
|
||||||
sendFeedback(input: SendFeedbackInput!): SendFeedbackPayload
|
sendFeedback(input: SendFeedbackInput!): SendFeedbackPayload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Node {
|
||||||
|
id: ID!
|
||||||
|
}
|
||||||
|
|
||||||
type Page implements PageInterface {
|
type Page implements PageInterface {
|
||||||
id: ID
|
id: ID
|
||||||
path: String!
|
path: String!
|
||||||
|
|
@ -783,42 +800,21 @@ type RichTextBlock implements StreamFieldInterface {
|
||||||
value: String!
|
value: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
union Search = CoursePage | LearningPath | Topic | Circle | LearningSequence | LearningUnit | LearningContent | CompetenceProfilePage | CompetencePage | PerformanceCriteria | MediaLibraryPage | MediaCategoryPage | Page | LibraryDocument | User | SecurityRequestResponseLog | Course | CourseCategory | CourseCompletion | CourseSession | CourseSessionUser
|
union Search = CoursePage | LearningPath | Topic | Circle | LearningSequence | LearningUnit | LearningContent | CompetenceProfilePage | CompetencePage | PerformanceCriteria | MediaLibraryPage | MediaCategoryPage | Page | LibraryDocument | User | SecurityRequestResponseLog | Course | CourseCategory | CourseCompletion | CourseSession | CourseSessionUser | CircleDocument
|
||||||
|
|
||||||
type SecurityRequestResponseLog {
|
type SecurityRequestResponseLog {
|
||||||
id: ID
|
id: ID
|
||||||
}
|
}
|
||||||
|
|
||||||
input SendFeedbackInput {
|
input SendFeedbackInput {
|
||||||
id: Int
|
|
||||||
page: String!
|
page: String!
|
||||||
satisfaction: Int
|
courseSession: Int!
|
||||||
goalAttainment: Int
|
data: GenericScalar
|
||||||
proficiency: Int
|
|
||||||
receivedMaterials: Boolean
|
|
||||||
materialsRating: Int
|
|
||||||
instructorCompetence: Int
|
|
||||||
instructorRespect: Int
|
|
||||||
instructorOpenFeedback: String
|
|
||||||
wouldRecommend: Boolean
|
|
||||||
coursePositiveFeedback: String
|
|
||||||
courseNegativeFeedback: String
|
|
||||||
clientMutationId: String
|
clientMutationId: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type SendFeedbackPayload {
|
type SendFeedbackPayload {
|
||||||
id: Int
|
feedbackResponse: FeedbackResponse
|
||||||
satisfaction: Int
|
|
||||||
goalAttainment: Int
|
|
||||||
proficiency: Int
|
|
||||||
receivedMaterials: Boolean
|
|
||||||
materialsRating: Int
|
|
||||||
instructorCompetence: Int
|
|
||||||
instructorRespect: Int
|
|
||||||
instructorOpenFeedback: String
|
|
||||||
wouldRecommend: Boolean
|
|
||||||
coursePositiveFeedback: String
|
|
||||||
courseNegativeFeedback: String
|
|
||||||
errors: [ErrorType]
|
errors: [ErrorType]
|
||||||
clientMutationId: String
|
clientMutationId: String
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
from factory import Dict
|
||||||
from factory.django import DjangoModelFactory
|
from factory.django import DjangoModelFactory
|
||||||
from factory.fuzzy import FuzzyChoice, FuzzyInteger
|
from factory.fuzzy import FuzzyChoice, FuzzyInteger
|
||||||
|
|
||||||
|
|
@ -5,33 +6,37 @@ from vbv_lernwelt.feedback.models import FeedbackResponse
|
||||||
|
|
||||||
|
|
||||||
class FeedbackFactory(DjangoModelFactory):
|
class FeedbackFactory(DjangoModelFactory):
|
||||||
|
data = Dict(
|
||||||
|
{
|
||||||
|
"satisfaction": FuzzyInteger(2, 4),
|
||||||
|
"goal_attainment": FuzzyInteger(3, 4),
|
||||||
|
"proficiency": FuzzyChoice([20, 40, 60, 80]),
|
||||||
|
"received_materials": FuzzyChoice([True, False]),
|
||||||
|
"materials_rating": FuzzyInteger(2, 4),
|
||||||
|
"instructor_competence": FuzzyInteger(3, 4),
|
||||||
|
"instructor_respect": FuzzyInteger(3, 4),
|
||||||
|
"instructor_open_feedback": FuzzyChoice(
|
||||||
|
[
|
||||||
|
"Alles gut, manchmal etwas langfädig",
|
||||||
|
"Super, bin begeistert",
|
||||||
|
"Ok, enspricht den Erwartungen",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
"would_recommend": FuzzyChoice([True, False]),
|
||||||
|
"course_positive_feedback": FuzzyChoice(
|
||||||
|
[
|
||||||
|
"Die Präsentation war super",
|
||||||
|
"Das Beispiel mit der Katze fand ich sehr gut veranschaulicht!",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
"course_negative_feedback": FuzzyChoice(
|
||||||
|
[
|
||||||
|
"Es wäre praktisch, Zugang zu einer FAQ zu haben.",
|
||||||
|
"Es wäre schön, mehr Videos hinzuzufügen.",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FeedbackResponse
|
model = FeedbackResponse
|
||||||
|
|
||||||
satisfaction = FuzzyInteger(2, 4)
|
|
||||||
goal_attainment = FuzzyInteger(3, 4)
|
|
||||||
proficiency = FuzzyChoice([20, 40, 60, 80])
|
|
||||||
received_materials = FuzzyChoice([True, False])
|
|
||||||
materials_rating = FuzzyInteger(2, 4)
|
|
||||||
instructor_competence = FuzzyInteger(3, 4)
|
|
||||||
instructor_respect = FuzzyInteger(3, 4)
|
|
||||||
instructor_open_feedback = FuzzyChoice(
|
|
||||||
[
|
|
||||||
"Alles gut, manchmal etwas langfädig",
|
|
||||||
"Super, bin begeistert",
|
|
||||||
"Ok, enspricht den Erwartungen",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
would_recommend = FuzzyChoice([True, False])
|
|
||||||
course_positive_feedback = FuzzyChoice(
|
|
||||||
[
|
|
||||||
"Die Präsentation war super",
|
|
||||||
"Das Beispiel mit der Katze fand ich sehr gut veranschaulicht!",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
course_negative_feedback = FuzzyChoice(
|
|
||||||
[
|
|
||||||
"Es wäre praktisch, Zugang zu einer FAQ zu haben.",
|
|
||||||
"Es wäre schön, mehr Videos hinzuzufügen.",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,56 @@
|
||||||
import graphene
|
import structlog
|
||||||
from graphene_django.rest_framework.mutation import SerializerMutation
|
from graphene import ClientIDMutation, Field, Int, List, String
|
||||||
|
from graphene.types.generic import GenericScalar
|
||||||
|
from graphene_django.types import ErrorType
|
||||||
|
|
||||||
from vbv_lernwelt.feedback.serializers import FeedbackResponseSerializer
|
from vbv_lernwelt.course.models import CourseSession
|
||||||
|
from vbv_lernwelt.feedback.graphql.types import FeedbackResponse as FeedbackResponseType
|
||||||
|
from vbv_lernwelt.feedback.models import FeedbackResponse
|
||||||
|
from vbv_lernwelt.feedback.serializers import CourseFeedbackSerializer
|
||||||
|
from wagtail.models import Page
|
||||||
|
|
||||||
|
logger = structlog.get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SendFeedback(SerializerMutation):
|
# https://medium.com/open-graphql/jsonfield-models-in-graphene-django-308ae43d14ee
|
||||||
class Meta:
|
class SendFeedback(ClientIDMutation):
|
||||||
serializer_class = FeedbackResponseSerializer
|
feedback_response = Field(FeedbackResponseType)
|
||||||
model_operations = ["create"]
|
errors = List(
|
||||||
|
ErrorType, description="May contain more than one error for same field."
|
||||||
|
)
|
||||||
|
|
||||||
|
class Input:
|
||||||
|
page = String(required=True)
|
||||||
|
course_session = Int(required=True)
|
||||||
|
data = GenericScalar()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def mutate_and_get_payload(cls, _, info, **input):
|
||||||
|
page_key = input["page"]
|
||||||
|
course_session_id = input["course_session"]
|
||||||
|
logger.info("creating feedback")
|
||||||
|
|
||||||
|
learning_content = Page.objects.get(
|
||||||
|
translation_key=page_key, locale__language_code="de-CH"
|
||||||
|
)
|
||||||
|
circle = learning_content.get_parent().specific
|
||||||
|
course_session = CourseSession.objects.get(id=course_session_id)
|
||||||
|
data = input.get("data", {})
|
||||||
|
|
||||||
|
serializer = CourseFeedbackSerializer(data=data)
|
||||||
|
|
||||||
|
if not serializer.is_valid():
|
||||||
|
logger.error(serializer.errors)
|
||||||
|
return SendFeedback(errors=serializer.errors)
|
||||||
|
|
||||||
|
feedback_response = FeedbackResponse.objects.create(
|
||||||
|
circle=circle,
|
||||||
|
course_session=course_session,
|
||||||
|
data=serializer.validated_data,
|
||||||
|
)
|
||||||
|
logger.info(feedback_response)
|
||||||
|
|
||||||
|
return SendFeedback(feedback_response=feedback_response)
|
||||||
|
|
||||||
|
|
||||||
class Mutation(object):
|
class Mutation(object):
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
|
from graphene.relay import Node
|
||||||
|
from graphene.types.generic import GenericScalar
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
|
|
||||||
from vbv_lernwelt.feedback.models import Feedback
|
from vbv_lernwelt.feedback.models import FeedbackResponse as FeedbackResponseModel
|
||||||
|
|
||||||
|
|
||||||
# class FeedbackType(DjangoObjectType):
|
class FeedbackResponse(DjangoObjectType):
|
||||||
# class Meta:
|
data = GenericScalar()
|
||||||
# model = Feedback
|
|
||||||
|
class Meta:
|
||||||
|
model = FeedbackResponseModel
|
||||||
|
interfaces = (Node,)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
# Generated by Django 3.2.13 on 2023-02-06 10:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("feedback", "0002_auto_20230111_1044"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="course_negative_feedback",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="course_positive_feedback",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="goal_attainment",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="instructor_competence",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="instructor_open_feedback",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="instructor_respect",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="materials_rating",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="proficiency",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="received_materials",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="satisfaction",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="would_recommend",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="data",
|
||||||
|
field=models.JSONField(default=dict),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="feedbackresponse",
|
||||||
|
name="created_at",
|
||||||
|
field=models.DateTimeField(auto_now_add=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -37,17 +37,20 @@ class FeedbackResponse(models.Model):
|
||||||
EIGHTY = 80, "80%"
|
EIGHTY = 80, "80%"
|
||||||
HUNDRED = 100, "100%"
|
HUNDRED = 100, "100%"
|
||||||
|
|
||||||
satisfaction = FeedbackIntegerField()
|
# satisfaction = FeedbackIntegerField()
|
||||||
goal_attainment = FeedbackIntegerField()
|
# goal_attainment = FeedbackIntegerField()
|
||||||
proficiency = models.IntegerField(null=True)
|
# proficiency = models.IntegerField(null=True)
|
||||||
received_materials = models.BooleanField(null=True)
|
# received_materials = models.BooleanField(null=True)
|
||||||
materials_rating = FeedbackIntegerField()
|
# materials_rating = FeedbackIntegerField()
|
||||||
instructor_competence = FeedbackIntegerField()
|
# instructor_competence = FeedbackIntegerField()
|
||||||
instructor_respect = FeedbackIntegerField()
|
# instructor_respect = FeedbackIntegerField()
|
||||||
instructor_open_feedback = models.TextField(blank=True)
|
# instructor_open_feedback = models.TextField(blank=True)
|
||||||
would_recommend = models.BooleanField(null=True)
|
# would_recommend = models.BooleanField(null=True)
|
||||||
course_positive_feedback = models.TextField(blank=True)
|
# course_positive_feedback = models.TextField(blank=True)
|
||||||
course_negative_feedback = models.TextField(blank=True)
|
# course_negative_feedback = models.TextField(blank=True)
|
||||||
|
|
||||||
|
data = models.JSONField(default=dict)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
circle = models.ForeignKey("learnpath.Circle", models.PROTECT)
|
circle = models.ForeignKey("learnpath.Circle", models.PROTECT)
|
||||||
course_session = models.ForeignKey("course.CourseSession", models.PROTECT)
|
course_session = models.ForeignKey("course.CourseSession", models.PROTECT)
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,31 @@
|
||||||
import structlog
|
import structlog
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from wagtail.models import Page
|
|
||||||
|
|
||||||
from vbv_lernwelt.course.models import CourseSession
|
|
||||||
from vbv_lernwelt.feedback.models import FeedbackResponse
|
|
||||||
|
|
||||||
logger = structlog.get_logger(__name__)
|
logger = structlog.get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class FeedbackResponseSerializer(serializers.ModelSerializer):
|
class FeedbackIntegerField(serializers.IntegerField):
|
||||||
page = serializers.CharField(write_only=True)
|
def __init__(self, **kwargs):
|
||||||
course_session = serializers.CharField(write_only=True)
|
super().__init__(
|
||||||
|
required=False, allow_null=True, min_value=1, max_value=5, **kwargs
|
||||||
class Meta:
|
|
||||||
model = FeedbackResponse
|
|
||||||
exclude = ["circle"]
|
|
||||||
# extra_kwargs = {"course", {"read_only": True}}
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
logger.info("creating feedback")
|
|
||||||
page_key = validated_data.pop("page")
|
|
||||||
course_session_id = validated_data.pop("course_session")
|
|
||||||
|
|
||||||
learning_content = Page.objects.get(
|
|
||||||
translation_key=page_key, locale__language_code="de-CH"
|
|
||||||
)
|
|
||||||
circle = learning_content.get_parent().specific
|
|
||||||
course_session = CourseSession.objects.get(id=course_session_id)
|
|
||||||
return FeedbackResponse.objects.create(
|
|
||||||
**validated_data, circle=circle, course_session=course_session
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CourseFeedbackSerializer(serializers.Serializer):
|
||||||
|
satisfaction = FeedbackIntegerField()
|
||||||
|
goal_attainment = FeedbackIntegerField()
|
||||||
|
proficiency = serializers.IntegerField(required=False, allow_null=True)
|
||||||
|
received_materials = serializers.BooleanField(required=False, allow_null=True)
|
||||||
|
materials_rating = FeedbackIntegerField()
|
||||||
|
instructor_competence = FeedbackIntegerField()
|
||||||
|
instructor_respect = FeedbackIntegerField()
|
||||||
|
instructor_open_feedback = serializers.CharField(
|
||||||
|
required=False, allow_null=True, allow_blank=True
|
||||||
|
)
|
||||||
|
would_recommend = serializers.BooleanField(required=False, allow_null=True)
|
||||||
|
course_positive_feedback = serializers.CharField(
|
||||||
|
required=False, allow_null=True, allow_blank=True
|
||||||
|
)
|
||||||
|
course_negative_feedback = serializers.CharField(
|
||||||
|
required=False, allow_null=True, allow_blank=True
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -159,17 +159,25 @@ class FeedbackDetailApiTestCase(FeedbackApiBaseTestCase):
|
||||||
FeedbackFactory(
|
FeedbackFactory(
|
||||||
circle=circle,
|
circle=circle,
|
||||||
course_session=csu.course_session,
|
course_session=csu.course_session,
|
||||||
satisfaction=feedback_data["satisfaction"][i],
|
data={
|
||||||
goal_attainment=feedback_data["goal_attainment"][i],
|
"satisfaction": feedback_data["satisfaction"][i],
|
||||||
proficiency=feedback_data["proficiency"][i],
|
"goal_attainment": feedback_data["goal_attainment"][i],
|
||||||
received_materials=feedback_data["received_materials"][i],
|
"proficiency": feedback_data["proficiency"][i],
|
||||||
materials_rating=feedback_data["materials_rating"][i],
|
"received_materials": feedback_data["received_materials"][i],
|
||||||
instructor_competence=feedback_data["instructor_competence"][i],
|
"materials_rating": feedback_data["materials_rating"][i],
|
||||||
instructor_open_feedback=feedback_data["instructor_open_feedback"][i],
|
"instructor_competence": feedback_data["instructor_competence"][i],
|
||||||
instructor_respect=feedback_data["instructor_respect"][i],
|
"instructor_open_feedback": feedback_data[
|
||||||
would_recommend=feedback_data["would_recommend"][i],
|
"instructor_open_feedback"
|
||||||
course_positive_feedback=feedback_data["course_positive_feedback"][i],
|
][i],
|
||||||
course_negative_feedback=feedback_data["course_negative_feedback"][i],
|
"instructor_respect": feedback_data["instructor_respect"][i],
|
||||||
|
"would_recommend": feedback_data["would_recommend"][i],
|
||||||
|
"course_positive_feedback": feedback_data[
|
||||||
|
"course_positive_feedback"
|
||||||
|
][i],
|
||||||
|
"course_negative_feedback": feedback_data[
|
||||||
|
"course_negative_feedback"
|
||||||
|
][i],
|
||||||
|
},
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ def get_feedback_for_circle(request, course_id, circle_id):
|
||||||
course_session__course_id=course_id,
|
course_session__course_id=course_id,
|
||||||
circle__expert__user=request.user,
|
circle__expert__user=request.user,
|
||||||
circle_id=circle_id,
|
circle_id=circle_id,
|
||||||
)
|
).order_by("created_at")
|
||||||
|
|
||||||
# I guess this is ok for the üK case
|
# I guess this is ok for the üK case
|
||||||
feedback_data = {"amount": len(feedbacks), "questions": {}}
|
feedback_data = {"amount": len(feedbacks), "questions": {}}
|
||||||
|
|
@ -62,6 +62,8 @@ def get_feedback_for_circle(request, course_id, circle_id):
|
||||||
|
|
||||||
for feedback in feedbacks:
|
for feedback in feedbacks:
|
||||||
for field in FEEDBACK_FIELDS:
|
for field in FEEDBACK_FIELDS:
|
||||||
feedback_data["questions"][field].append(getattr(feedback, field))
|
data = feedback.data.get(field, None)
|
||||||
|
if data is not None:
|
||||||
|
feedback_data["questions"][field].append(data)
|
||||||
|
|
||||||
return Response(status=200, data=feedback_data)
|
return Response(status=200, data=feedback_data)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue