Merged in feature/VBV-438-reflection-per-circle (pull request #158)

Adapt AssignmentCompletion model to include page_id

Approved-by: Elia Bieri
This commit is contained in:
Daniel Egger 2023-07-14 11:28:05 +00:00
commit 5bd8192f05
29 changed files with 377 additions and 149 deletions

View File

@ -14,8 +14,8 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
*/ */
const documents = { const documents = {
"\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument, "\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument,
"\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $assignmentUserId: ID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n": types.UpsertAssignmentCompletionDocument, "\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: ID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n": types.UpsertAssignmentCompletionDocument,
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $assignmentUserId: ID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument, "\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: ID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
"\n query courseQuery($courseId: Int!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n": types.CourseQueryDocument, "\n query courseQuery($courseId: Int!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n": types.CourseQueryDocument,
}; };
@ -40,11 +40,11 @@ export function graphql(source: "\n mutation SendFeedbackMutation($input: SendF
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql(source: "\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $assignmentUserId: ID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"): (typeof documents)["\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $assignmentUserId: ID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"]; export function graphql(source: "\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: ID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"): (typeof documents)["\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: ID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */
export function graphql(source: "\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $assignmentUserId: ID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n"): (typeof documents)["\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $assignmentUserId: ID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n"]; export function graphql(source: "\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: ID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n"): (typeof documents)["\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: ID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n"];
/** /**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/ */

View File

@ -74,6 +74,7 @@ export type AssignmentCompletionObjectType = {
evaluation_submitted_at?: Maybe<Scalars['DateTime']['output']>; evaluation_submitted_at?: Maybe<Scalars['DateTime']['output']>;
evaluation_user?: Maybe<UserType>; evaluation_user?: Maybe<UserType>;
id: Scalars['ID']['output']; id: Scalars['ID']['output'];
learning_content_page_id?: Maybe<Scalars['ID']['output']>;
submitted_at?: Maybe<Scalars['DateTime']['output']>; submitted_at?: Maybe<Scalars['DateTime']['output']>;
updated_at: Scalars['DateTime']['output']; updated_at: Scalars['DateTime']['output'];
}; };
@ -247,6 +248,7 @@ export type MutationUpsertAssignmentCompletionArgs = {
course_session_id: Scalars['ID']['input']; course_session_id: Scalars['ID']['input'];
evaluation_grade?: InputMaybe<Scalars['Float']['input']>; evaluation_grade?: InputMaybe<Scalars['Float']['input']>;
evaluation_points?: InputMaybe<Scalars['Float']['input']>; evaluation_points?: InputMaybe<Scalars['Float']['input']>;
learning_content_page_id?: InputMaybe<Scalars['ID']['input']>;
}; };
/** An object with an ID */ /** An object with an ID */
@ -274,6 +276,7 @@ export type QueryAssignmentCompletionArgs = {
assignment_id: Scalars['ID']['input']; assignment_id: Scalars['ID']['input'];
assignment_user_id?: InputMaybe<Scalars['ID']['input']>; assignment_user_id?: InputMaybe<Scalars['ID']['input']>;
course_session_id: Scalars['ID']['input']; course_session_id: Scalars['ID']['input'];
learning_content_page_id?: InputMaybe<Scalars['ID']['input']>;
}; };
@ -324,6 +327,7 @@ export type SendFeedbackMutationMutation = { __typename?: 'Mutation', send_feedb
export type UpsertAssignmentCompletionMutationVariables = Exact<{ export type UpsertAssignmentCompletionMutationVariables = Exact<{
assignmentId: Scalars['ID']['input']; assignmentId: Scalars['ID']['input'];
courseSessionId: Scalars['ID']['input']; courseSessionId: Scalars['ID']['input'];
learningContentId?: InputMaybe<Scalars['ID']['input']>;
assignmentUserId?: InputMaybe<Scalars['ID']['input']>; assignmentUserId?: InputMaybe<Scalars['ID']['input']>;
completionStatus: AssignmentCompletionStatus; completionStatus: AssignmentCompletionStatus;
completionDataString: Scalars['String']['input']; completionDataString: Scalars['String']['input'];
@ -337,6 +341,7 @@ export type UpsertAssignmentCompletionMutation = { __typename?: 'Mutation', upse
export type AssignmentCompletionQueryQueryVariables = Exact<{ export type AssignmentCompletionQueryQueryVariables = Exact<{
assignmentId: Scalars['ID']['input']; assignmentId: Scalars['ID']['input'];
courseSessionId: Scalars['ID']['input']; courseSessionId: Scalars['ID']['input'];
learningContentId?: InputMaybe<Scalars['ID']['input']>;
assignmentUserId?: InputMaybe<Scalars['ID']['input']>; assignmentUserId?: InputMaybe<Scalars['ID']['input']>;
}>; }>;
@ -352,6 +357,6 @@ export type CourseQueryQuery = { __typename?: 'Query', course?: { __typename?: '
export const SendFeedbackMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendFeedbackMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SendFeedbackInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"send_feedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feedback_response"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"messages"}}]}}]}}]}}]} as unknown as DocumentNode<SendFeedbackMutationMutation, SendFeedbackMutationMutationVariables>; export const SendFeedbackMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendFeedbackMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SendFeedbackInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"send_feedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feedback_response"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"messages"}}]}}]}}]}}]} as unknown as DocumentNode<SendFeedbackMutationMutation, SendFeedbackMutationMutationVariables>;
export const UpsertAssignmentCompletionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpsertAssignmentCompletion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AssignmentCompletionStatus"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"upsert_assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_data_string"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_grade"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_points"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]}}]} as unknown as DocumentNode<UpsertAssignmentCompletionMutation, UpsertAssignmentCompletionMutationVariables>; export const UpsertAssignmentCompletionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpsertAssignmentCompletion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AssignmentCompletionStatus"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"upsert_assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_data_string"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_grade"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_points"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]}}]} as unknown as DocumentNode<UpsertAssignmentCompletionMutation, UpsertAssignmentCompletionMutationVariables>;
export const AssignmentCompletionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"assignmentCompletionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"effort_required"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_description"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_document_url"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_tasks"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"intro_text"}},{"kind":"Field","name":{"kind":"Name","value":"performance_objectives"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tasks"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"translation_key"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]} as unknown as DocumentNode<AssignmentCompletionQueryQuery, AssignmentCompletionQueryQueryVariables>; export const AssignmentCompletionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"assignmentCompletionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"effort_required"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_description"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_document_url"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_tasks"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"intro_text"}},{"kind":"Field","name":{"kind":"Name","value":"performance_objectives"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tasks"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"translation_key"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]} as unknown as DocumentNode<AssignmentCompletionQueryQuery, AssignmentCompletionQueryQueryVariables>;
export const CourseQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"courseQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"category_name"}},{"kind":"Field","name":{"kind":"Name","value":"learning_path"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<CourseQueryQuery, CourseQueryQueryVariables>; export const CourseQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"courseQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"category_name"}},{"kind":"Field","name":{"kind":"Name","value":"learning_path"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<CourseQueryQuery, CourseQueryQueryVariables>;

View File

@ -2,7 +2,7 @@ type Query {
course_session_attendance_course(id: ID!, assignment_user_id: ID): CourseSessionAttendanceCourseType course_session_attendance_course(id: ID!, assignment_user_id: ID): CourseSessionAttendanceCourseType
course(id: Int): CourseType course(id: Int): CourseType
assignment(id: ID, slug: String): AssignmentObjectType assignment(id: ID, slug: String): AssignmentObjectType
assignment_completion(assignment_id: ID!, course_session_id: ID!, assignment_user_id: ID): AssignmentCompletionObjectType assignment_completion(assignment_id: ID!, course_session_id: ID!, learning_content_page_id: ID, assignment_user_id: ID): AssignmentCompletionObjectType
} }
type CourseSessionAttendanceCourseType { type CourseSessionAttendanceCourseType {
@ -177,6 +177,7 @@ type AssignmentCompletionObjectType {
completion_status: AssignmentAssignmentCompletionCompletionStatusChoices! completion_status: AssignmentAssignmentCompletionCompletionStatusChoices!
completion_data: GenericScalar completion_data: GenericScalar
additional_json_data: JSONString! additional_json_data: JSONString!
learning_content_page_id: ID
} }
"""An enumeration.""" """An enumeration."""
@ -212,7 +213,7 @@ scalar JSONString
type Mutation { type Mutation {
send_feedback(input: SendFeedbackInput!): SendFeedbackPayload send_feedback(input: SendFeedbackInput!): SendFeedbackPayload
update_course_session_attendance_course_users(attendance_user_list: [AttendanceUserInputType]!, id: ID!): AttendanceCourseUserMutation update_course_session_attendance_course_users(attendance_user_list: [AttendanceUserInputType]!, id: ID!): AttendanceCourseUserMutation
upsert_assignment_completion(assignment_id: ID!, assignment_user_id: ID, completion_data_string: String, completion_status: AssignmentCompletionStatus, course_session_id: ID!, evaluation_grade: Float, evaluation_points: Float): AssignmentCompletionMutation upsert_assignment_completion(assignment_id: ID!, assignment_user_id: ID, completion_data_string: String, completion_status: AssignmentCompletionStatus, course_session_id: ID!, evaluation_grade: Float, evaluation_points: Float, learning_content_page_id: ID): AssignmentCompletionMutation
} }
type SendFeedbackPayload { type SendFeedbackPayload {

View File

@ -4,6 +4,7 @@ export const UPSERT_ASSIGNMENT_COMPLETION_MUTATION = graphql(`
mutation UpsertAssignmentCompletion( mutation UpsertAssignmentCompletion(
$assignmentId: ID! $assignmentId: ID!
$courseSessionId: ID! $courseSessionId: ID!
$learningContentId: ID
$assignmentUserId: ID $assignmentUserId: ID
$completionStatus: AssignmentCompletionStatus! $completionStatus: AssignmentCompletionStatus!
$completionDataString: String! $completionDataString: String!
@ -13,6 +14,7 @@ export const UPSERT_ASSIGNMENT_COMPLETION_MUTATION = graphql(`
upsert_assignment_completion( upsert_assignment_completion(
assignment_id: $assignmentId assignment_id: $assignmentId
course_session_id: $courseSessionId course_session_id: $courseSessionId
learning_content_page_id: $learningContentId
assignment_user_id: $assignmentUserId assignment_user_id: $assignmentUserId
completion_status: $completionStatus completion_status: $completionStatus
completion_data_string: $completionDataString completion_data_string: $completionDataString

View File

@ -4,6 +4,7 @@ export const ASSIGNMENT_COMPLETION_QUERY = graphql(`
query assignmentCompletionQuery( query assignmentCompletionQuery(
$assignmentId: ID! $assignmentId: ID!
$courseSessionId: ID! $courseSessionId: ID!
$learningContentId: ID
$assignmentUserId: ID $assignmentUserId: ID
) { ) {
assignment(id: $assignmentId) { assignment(id: $assignmentId) {
@ -25,6 +26,7 @@ export const ASSIGNMENT_COMPLETION_QUERY = graphql(`
assignment_id: $assignmentId assignment_id: $assignmentId
course_session_id: $courseSessionId course_session_id: $courseSessionId
assignment_user_id: $assignmentUserId assignment_user_id: $assignmentUserId
learning_content_page_id: $learningContentId
) { ) {
id id
completion_status completion_status

View File

@ -71,16 +71,15 @@ const assignment = computed(
<template> <template>
<div class="absolute bottom-0 top-0 z-10 w-full bg-white"> <div class="absolute bottom-0 top-0 z-10 w-full bg-white">
<div <div v-if="queryResult.fetching.value"></div>
v-if="assignment && assignmentCompletion && state.assignmentUser" <div v-else-if="queryResult.error.value">{{ queryResult.error.value }}</div>
class="relative" <div v-else>
>
<header <header
class="relative flex h-12 w-full items-center justify-between border-b border-b-gray-400 bg-white px-4 lg:h-16 lg:px-8" class="relative flex h-12 w-full items-center justify-between border-b border-b-gray-400 bg-white px-4 lg:h-16 lg:px-8"
> >
<div class="flex items-center text-gray-900"> <div class="flex items-center text-gray-900">
<it-icon-assignment class="h-6 w-6"></it-icon-assignment> <it-icon-assignment class="h-6 w-6"></it-icon-assignment>
<div class="ml-2">Geleitete Fallarbeit: {{ assignment.title }}</div> <div class="ml-2">Geleitete Fallarbeit: {{ assignment?.title }}</div>
</div> </div>
<button <button
type="button" type="button"
@ -91,39 +90,44 @@ const assignment = computed(
<it-icon-close></it-icon-close> <it-icon-close></it-icon-close>
</button> </button>
</header> </header>
<div
v-if="assignment && assignmentCompletion && state.assignmentUser"
class="relative"
>
<div class="h-content flex">
<div class="h-full w-1/2 overflow-y-auto bg-white">
<!-- Left part content goes here -->
<div class="p-10" data-cy="student-submission">
<h3>Ergebnisse</h3>
<div class="h-content flex"> <div class="my-6 flex items-center">
<div class="h-full w-1/2 overflow-y-auto bg-white"> <img
<!-- Left part content goes here --> :src="state.assignmentUser?.avatar_url"
<div class="p-10" data-cy="student-submission"> class="mr-4 h-11 w-11 rounded-full"
<h3>Ergebnisse</h3> />
<div class="font-bold">
<div class="my-6 flex items-center"> {{ state.assignmentUser?.first_name }}
<img {{ state.assignmentUser?.last_name }}
:src="state.assignmentUser?.avatar_url" </div>
class="mr-4 h-11 w-11 rounded-full"
/>
<div class="font-bold">
{{ state.assignmentUser?.first_name }}
{{ state.assignmentUser?.last_name }}
</div> </div>
<AssignmentSubmissionResponses
:assignment="assignment"
:assignment-completion-data="assignmentCompletion.completion_data"
:allow-edit="false"
></AssignmentSubmissionResponses>
</div> </div>
<AssignmentSubmissionResponses </div>
<div class="w-1/2 overflow-y-auto bg-gray-200">
<EvaluationContainer
:assignment-completion="assignmentCompletion"
:assignment-user="state.assignmentUser"
:assignment="assignment" :assignment="assignment"
:assignment-completion-data="assignmentCompletion.completion_data" @close="close()"
:allow-edit="false" ></EvaluationContainer>
></AssignmentSubmissionResponses>
</div> </div>
</div> </div>
<div class="w-1/2 overflow-y-auto bg-gray-200">
<EvaluationContainer
:assignment-completion="assignmentCompletion"
:assignment-user="state.assignmentUser"
:assignment="assignment"
@close="close()"
></EvaluationContainer>
</div>
</div> </div>
<div v-else>Could not load all data</div>
</div> </div>
</div> </div>
</template> </template>

View File

@ -26,13 +26,13 @@ const upsertAssignmentCompletionMutation = useMutation(
async function startEvaluation() { async function startEvaluation() {
log.debug("startEvaluation"); log.debug("startEvaluation");
if (props.assignmentCompletion.completion_status !== "EVALUATION_SUBMITTED") { if (props.assignmentCompletion.completion_status !== "EVALUATION_SUBMITTED") {
// noinspection TypeScriptValidateTypes
upsertAssignmentCompletionMutation.executeMutation({ upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id.toString(), assignmentId: props.assignment.id.toString(),
courseSessionId: courseSession.value.id.toString(), courseSessionId: courseSession.value.id.toString(),
assignmentUserId: props.assignmentUser.user_id.toString(), assignmentUserId: props.assignmentUser.user_id.toString(),
completionStatus: "EVALUATION_IN_PROGRESS", completionStatus: "EVALUATION_IN_PROGRESS",
completionDataString: JSON.stringify({}), completionDataString: JSON.stringify({}),
// next line used for urql
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
id: props.assignmentCompletion?.id, id: props.assignmentCompletion?.id,

View File

@ -41,7 +41,6 @@ const upsertAssignmentCompletionMutation = useMutation(
); );
async function submitEvaluation() { async function submitEvaluation() {
// noinspection TypeScriptValidateTypes
upsertAssignmentCompletionMutation.executeMutation({ upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id.toString(), assignmentId: props.assignment.id.toString(),
courseSessionId: courseSession.value.id.toString(), courseSessionId: courseSession.value.id.toString(),
@ -50,6 +49,7 @@ async function submitEvaluation() {
completionDataString: JSON.stringify({}), completionDataString: JSON.stringify({}),
evaluationGrade: grade.value ?? 1, evaluationGrade: grade.value ?? 1,
evaluationPoints: userPoints.value, evaluationPoints: userPoints.value,
// next line used for urql
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
id: props.assignmentCompletion?.id, id: props.assignmentCompletion?.id,

View File

@ -65,7 +65,6 @@ const upsertAssignmentCompletionMutation = useMutation(
async function evaluateAssignmentCompletion(completionData: AssignmentCompletionData) { async function evaluateAssignmentCompletion(completionData: AssignmentCompletionData) {
log.debug("evaluateAssignmentCompletion", completionData); log.debug("evaluateAssignmentCompletion", completionData);
// noinspection TypeScriptValidateTypes
upsertAssignmentCompletionMutation.executeMutation({ upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id.toString(), assignmentId: props.assignment.id.toString(),
courseSessionId: courseSession.value.id.toString(), courseSessionId: courseSession.value.id.toString(),

View File

@ -2,23 +2,29 @@
import ItPersonRow from "@/components/ui/ItPersonRow.vue"; import ItPersonRow from "@/components/ui/ItPersonRow.vue";
import type { StatusCount, StatusCountKey } from "@/components/ui/ItProgress.vue"; import type { StatusCount, StatusCountKey } from "@/components/ui/ItProgress.vue";
import AssignmentSubmissionProgress from "@/pages/cockpit/assignmentsPage/AssignmentSubmissionProgress.vue"; import AssignmentSubmissionProgress from "@/pages/cockpit/assignmentsPage/AssignmentSubmissionProgress.vue";
import type { AssignmentLearningContent } from "@/services/assignmentService";
import { import {
findAssignmentDetail, findAssignmentDetail,
loadAssignmentCompletionStatusData, loadAssignmentCompletionStatusData,
} from "@/services/assignmentService"; } from "@/services/assignmentService";
import { useCockpitStore } from "@/stores/cockpit"; import { useCockpitStore } from "@/stores/cockpit";
import type { AssignmentCompletionStatus, CourseSession } from "@/types"; import type {
AssignmentCompletionStatus,
CourseSession,
LearningContentAssignment,
} from "@/types";
import dayjs from "dayjs"; import dayjs from "dayjs";
import log from "loglevel"; import log from "loglevel";
import { computed, onMounted, reactive } from "vue"; import { computed, onMounted, reactive } from "vue";
const props = defineProps<{ const props = defineProps<{
courseSession: CourseSession; courseSession: CourseSession;
assignment: AssignmentLearningContent; learningContentAssignment: LearningContentAssignment;
}>(); }>();
log.debug("AssignmentDetails created", props.assignment.assignmentId); log.debug(
"AssignmentDetails created",
props.learningContentAssignment.content_assignment_id
);
const cockpitStore = useCockpitStore(); const cockpitStore = useCockpitStore();
@ -34,7 +40,7 @@ const state = reactive({
onMounted(async () => { onMounted(async () => {
state.statusByUser = await loadAssignmentCompletionStatusData( state.statusByUser = await loadAssignmentCompletionStatusData(
props.assignment.assignmentId, props.learningContentAssignment.content_assignment_id,
props.courseSession.id props.courseSession.id
); );
}); });
@ -44,14 +50,14 @@ function submissionStatusForUser(userId: number) {
} }
const assignmentDetail = computed(() => const assignmentDetail = computed(() =>
findAssignmentDetail(props.assignment.assignmentId) findAssignmentDetail(props.learningContentAssignment.content_assignment_id)
); );
</script> </script>
<template> <template>
<div v-if="state.statusByUser.length"> <div v-if="state.statusByUser.length">
<div class="text-large font-bold"> <div class="text-large font-bold">
{{ assignment.title }} {{ props.learningContentAssignment.title }}
</div> </div>
<div v-if="assignmentDetail"> <div v-if="assignmentDetail">
<span> <span>
@ -66,7 +72,11 @@ const assignmentDetail = computed(() =>
</div> </div>
<div> <div>
<a :href="props.assignment.frontend_url" class="link" target="_blank"> <a
:href="props.learningContentAssignment.frontend_url"
class="link"
target="_blank"
>
Im Circle anzeigen Im Circle anzeigen
</a> </a>
</div> </div>
@ -74,7 +84,7 @@ const assignmentDetail = computed(() =>
<div class="mt-4"> <div class="mt-4">
<AssignmentSubmissionProgress <AssignmentSubmissionProgress
:course-session="courseSession" :course-session="courseSession"
:assignment="assignment" :learning-content-assignment="learningContentAssignment"
:show-title="false" :show-title="false"
/> />
</div> </div>
@ -130,7 +140,7 @@ const assignmentDetail = computed(() =>
<template #link> <template #link>
<router-link <router-link
v-if="submissionStatusForUser(csu.user_id)?.progressStatus === 'SUCCESS'" v-if="submissionStatusForUser(csu.user_id)?.progressStatus === 'SUCCESS'"
:to="`/course/${props.courseSession.course.slug}/cockpit/assignment/${assignment.assignmentId}/${csu.user_id}`" :to="`/course/${props.courseSession.course.slug}/cockpit/assignment/${learningContentAssignment.content_assignment_id}/${csu.user_id}`"
class="w-full text-right underline" class="w-full text-right underline"
data-cy="show-results" data-cy="show-results"
> >

View File

@ -1,20 +1,26 @@
<script setup lang="ts"> <script setup lang="ts">
import type { StatusCount, StatusCountKey } from "@/components/ui/ItProgress.vue"; import type { StatusCount, StatusCountKey } from "@/components/ui/ItProgress.vue";
import ItProgress from "@/components/ui/ItProgress.vue"; import ItProgress from "@/components/ui/ItProgress.vue";
import type { AssignmentLearningContent } from "@/services/assignmentService";
import { loadAssignmentCompletionStatusData } from "@/services/assignmentService"; import { loadAssignmentCompletionStatusData } from "@/services/assignmentService";
import type { AssignmentCompletionStatus, CourseSession } from "@/types"; import type {
AssignmentCompletionStatus,
CourseSession,
LearningContentAssignment,
} from "@/types";
import { countBy } from "lodash"; import { countBy } from "lodash";
import log from "loglevel"; import log from "loglevel";
import { onMounted, reactive } from "vue"; import { onMounted, reactive } from "vue";
const props = defineProps<{ const props = defineProps<{
courseSession: CourseSession; courseSession: CourseSession;
assignment: AssignmentLearningContent; learningContentAssignment: LearningContentAssignment;
showTitle: boolean; showTitle: boolean;
}>(); }>();
log.debug("AssignmentSubmissionProgress created", props.assignment.assignmentId); log.debug(
"AssignmentSubmissionProgress created",
props.learningContentAssignment.content_assignment_id
);
const state = reactive({ const state = reactive({
statusByUser: [] as { statusByUser: [] as {
@ -27,7 +33,7 @@ const state = reactive({
onMounted(async () => { onMounted(async () => {
state.statusByUser = await loadAssignmentCompletionStatusData( state.statusByUser = await loadAssignmentCompletionStatusData(
props.assignment.assignmentId, props.learningContentAssignment.content_assignment_id,
props.courseSession.id props.courseSession.id
); );
@ -41,7 +47,7 @@ onMounted(async () => {
<template> <template>
<div v-if="state.statusByUser.length"> <div v-if="state.statusByUser.length">
<div v-if="showTitle"> <div v-if="showTitle">
{{ props.assignment.title }} {{ props.learningContentAssignment.title }}
</div> </div>
<div><ItProgress :status-count="state.progressStatusCount" /></div> <div><ItProgress :status-count="state.progressStatusCount" /></div>
<div class="text-gray-900" :class="{ 'text-gray-900': showTitle }"> <div class="text-gray-900" :class="{ 'text-gray-900': showTitle }">

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useCurrentCourseSession } from "@/composables"; import { useCurrentCourseSession } from "@/composables";
import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue"; import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue";
import { calcAssignmentLearningContents } from "@/services/assignmentService"; import { calcLearningContentAssignments } from "@/services/assignmentService";
import { useLearningPathStore } from "@/stores/learningPath"; import { useLearningPathStore } from "@/stores/learningPath";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import * as log from "loglevel"; import * as log from "loglevel";
@ -21,8 +21,8 @@ onMounted(async () => {
log.debug("AssignmentsPage mounted"); log.debug("AssignmentsPage mounted");
}); });
const assignments = computed(() => { const learningContentAssignments = computed(() => {
return calcAssignmentLearningContents( return calcLearningContentAssignments(
learningPathStore.learningPathForUser(courseSession.value.course.slug, userStore.id) learningPathStore.learningPathForUser(courseSession.value.course.slug, userStore.id)
); );
}); });
@ -47,11 +47,11 @@ const assignments = computed(() => {
</h2> </h2>
</header> </header>
<main> <main>
<div v-for="assignment in assignments" :key="assignment.id"> <div v-for="lca in learningContentAssignments" :key="lca.id">
<div class="bg-white p-6"> <div class="bg-white p-6">
<AssignmentDetails <AssignmentDetails
:course-session="courseSession" :course-session="courseSession"
:assignment="assignment" :learning-content-assignment="lca"
/> />
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import AssignmentSubmissionProgress from "@/pages/cockpit/assignmentsPage/AssignmentSubmissionProgress.vue"; import AssignmentSubmissionProgress from "@/pages/cockpit/assignmentsPage/AssignmentSubmissionProgress.vue";
import { calcAssignmentLearningContents } from "@/services/assignmentService"; import { calcLearningContentAssignments } from "@/services/assignmentService";
import { useCockpitStore } from "@/stores/cockpit"; import { useCockpitStore } from "@/stores/cockpit";
import { useLearningPathStore } from "@/stores/learningPath"; import { useLearningPathStore } from "@/stores/learningPath";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
@ -18,9 +18,9 @@ const userStore = useUserStore();
const cockpitStore = useCockpitStore(); const cockpitStore = useCockpitStore();
const learningPathStore = useLearningPathStore(); const learningPathStore = useLearningPathStore();
const assignments = computed(() => { const learningContentAssignments = computed(() => {
// TODO: filter by selected circle // TODO: filter by selected circle
return calcAssignmentLearningContents( return calcLearningContentAssignments(
learningPathStore.learningPathForUser(props.courseSession.course.slug, userStore.id) learningPathStore.learningPathForUser(props.courseSession.course.slug, userStore.id)
); );
}); });
@ -34,11 +34,11 @@ const assignments = computed(() => {
<div>Geleitete Fallarbeiten</div> <div>Geleitete Fallarbeiten</div>
</h3> </h3>
<div v-for="assignment in assignments" :key="assignment.id" class="mb-4"> <div v-for="lca in learningContentAssignments" :key="lca.id" class="mb-4">
<AssignmentSubmissionProgress <AssignmentSubmissionProgress
:show-title="true" :show-title="true"
:course-session="props.courseSession" :course-session="props.courseSession"
:assignment="assignment" :learning-content-assignment="lca"
/> />
</div> </div>

View File

@ -18,6 +18,7 @@ import { useTranslation } from "i18next-vue";
const props = defineProps<{ const props = defineProps<{
assignment: Assignment; assignment: Assignment;
learningContentId: number;
assignmentCompletion?: AssignmentCompletion; assignmentCompletion?: AssignmentCompletion;
courseSessionId: number; courseSessionId: number;
dueDate: Dayjs; dueDate: Dayjs;
@ -62,10 +63,10 @@ const onEditTask = (task: AssignmentTask) => {
const onSubmit = async () => { const onSubmit = async () => {
try { try {
// noinspection TypeScriptValidateTypes
await upsertAssignmentCompletionMutation.executeMutation({ await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id.toString(), assignmentId: props.assignment.id.toString(),
courseSessionId: courseSession.value.id.toString(), courseSessionId: courseSession.value.id.toString(),
learningContentId: props.learningContentId.toString(),
completionDataString: JSON.stringify({}), completionDataString: JSON.stringify({}),
completionStatus: "SUBMITTED", completionStatus: "SUBMITTED",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@ -17,6 +17,7 @@ import { computed, reactive } from "vue";
const props = defineProps<{ const props = defineProps<{
assignmentId: number; assignmentId: number;
learningContentId: number;
task: AssignmentTask; task: AssignmentTask;
assignmentCompletion?: AssignmentCompletion; assignmentCompletion?: AssignmentCompletion;
}>(); }>();
@ -31,10 +32,10 @@ const upsertAssignmentCompletionMutation = useMutation(
async function upsertAssignmentCompletion(completion_data: AssignmentCompletionData) { async function upsertAssignmentCompletion(completion_data: AssignmentCompletionData) {
try { try {
// noinspection TypeScriptValidateTypes
await upsertAssignmentCompletionMutation.executeMutation({ await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignmentId.toString(), assignmentId: props.assignmentId.toString(),
courseSessionId: courseSession.value.id.toString(), courseSessionId: courseSession.value.id.toString(),
learningContentId: props.learningContentId.toString(),
completionDataString: JSON.stringify(completion_data), completionDataString: JSON.stringify(completion_data),
completionStatus: "IN_PROGRESS", completionStatus: "IN_PROGRESS",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@ -40,12 +40,12 @@ const props = defineProps<{
learningContent: LearningContentAssignment; learningContent: LearningContentAssignment;
}>(); }>();
// noinspection TypeScriptValidateTypes TODO: because of IntelliJ
const queryResult = useQuery({ const queryResult = useQuery({
query: ASSIGNMENT_COMPLETION_QUERY, query: ASSIGNMENT_COMPLETION_QUERY,
variables: { variables: {
courseSessionId: courseSession.value.id.toString(), courseSessionId: courseSession.value.id.toString(),
assignmentId: props.learningContent.content_assignment_id.toString(), assignmentId: props.learningContent.content_assignment_id.toString(),
learningContentId: props.learningContent.id.toString(),
}, },
pause: true, pause: true,
}); });
@ -86,10 +86,10 @@ onMounted(async () => {
// create initial `AssignmentCompletion` first, so that it exists and we don't // create initial `AssignmentCompletion` first, so that it exists and we don't
// have reactivity problem accessing it. // have reactivity problem accessing it.
// noinspection TypeScriptValidateTypes
await upsertAssignmentCompletionMutation.executeMutation({ await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.learningContent.content_assignment_id.toString(), assignmentId: props.learningContent.content_assignment_id.toString(),
courseSessionId: courseSession.value.id.toString(), courseSessionId: courseSession.value.id.toString(),
learningContentId: props.learningContent.id.toString(),
completionDataString: JSON.stringify({}), completionDataString: JSON.stringify({}),
completionStatus: "IN_PROGRESS", completionStatus: "IN_PROGRESS",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@ -205,61 +205,68 @@ const endBadgeText = computed(() => {
</script> </script>
<template> <template>
<div v-if="assignment && assignmentCompletion"> <div v-if="queryResult.fetching.value"></div>
<div class="flex"> <div v-else-if="queryResult.error.value">{{ queryResult.error.value }}</div>
<LearningContentMultiLayout <div v-else>
:current-step="stepIndex" <div v-if="assignment && assignmentCompletion">
:sub-title="subTitle" <div class="flex">
:title="getTitle()" <LearningContentMultiLayout
:learning-content="props.learningContent" :current-step="stepIndex"
:steps-count="numPages" :sub-title="subTitle"
:show-next-button="showNextButton && stepIndex !== 0" :title="getTitle()"
:show-exit-button="showExitButton" :learning-content="props.learningContent"
:show-start-button="showNextButton && stepIndex === 0" :steps-count="numPages"
:show-previous-button="showPreviousButton" :show-next-button="showNextButton && stepIndex !== 0"
:base-url="props.learningContent.frontend_url" :show-exit-button="showExitButton"
step-query-param="step" :show-start-button="showNextButton && stepIndex === 0"
start-badge-text="Einleitung" :show-previous-button="showPreviousButton"
:end-badge-text="endBadgeText" :base-url="props.learningContent.frontend_url"
close-button-variant="close" step-query-param="step"
@previous="handleBack()" start-badge-text="Einleitung"
@next="handleContinue()" :end-badge-text="endBadgeText"
> close-button-variant="close"
<div class="flex"> @previous="handleBack()"
<div> @next="handleContinue()"
<AssignmentIntroductionView >
v-if="stepIndex === 0" <div class="flex">
:due-date="dueDate" <div>
:assignment="assignment" <AssignmentIntroductionView
></AssignmentIntroductionView> v-if="stepIndex === 0"
<AssignmentTaskView :due-date="dueDate"
v-else-if="currentTask" :assignment="assignment"
:task="currentTask" ></AssignmentIntroductionView>
:assignment-id="props.learningContent.content_assignment_id" <AssignmentTaskView
:assignment-completion="assignmentCompletion" v-else-if="currentTask"
></AssignmentTaskView> :task="currentTask"
<AssignmentSubmissionView :assignment-id="props.learningContent.content_assignment_id"
v-else-if="assignmentType === 'CASEWORK' && stepIndex + 1 === numPages" :assignment-completion="assignmentCompletion"
:due-date="dueDate" :learning-content-id="props.learningContent.id"
:assignment="assignment" ></AssignmentTaskView>
:assignment-completion="assignmentCompletion" <AssignmentSubmissionView
:course-session-id="courseSession.id" v-else-if="assignmentType === 'CASEWORK' && stepIndex + 1 === numPages"
@edit-task="jumpToTask($event)" :due-date="dueDate"
></AssignmentSubmissionView> :assignment="assignment"
:assignment-completion="assignmentCompletion"
:learning-content-id="props.learningContent.id"
:course-session-id="courseSession.id"
@edit-task="jumpToTask($event)"
></AssignmentSubmissionView>
</div>
</div> </div>
</LearningContentMultiLayout>
<div
v-if="assignmentCompletion?.completion_status === 'EVALUATION_SUBMITTED'"
class="min-w-2/5 mr-4 bg-gray-200 px-6 py-6"
>
<EvaluationSummary
:assignment-user="assignmentUser"
:assignment="assignment"
:assignment-completion="assignmentCompletion"
:show-evaluation-user="true"
></EvaluationSummary>
</div> </div>
</LearningContentMultiLayout>
<div
v-if="assignmentCompletion?.completion_status === 'EVALUATION_SUBMITTED'"
class="min-w-2/5 mr-4 bg-gray-200 px-6 py-6"
>
<EvaluationSummary
:assignment-user="assignmentUser"
:assignment="assignment"
:assignment-completion="assignmentCompletion"
:show-evaluation-user="true"
></EvaluationSummary>
</div> </div>
</div> </div>
<div v-else>Could not load all data</div>
</div> </div>
</template> </template>

View File

@ -140,7 +140,7 @@ const changeViewType = (viewType: ViewType) => {
class="p-6" class="p-6"
:class="useMobileLayout ? 'bg-gray-200' : ''" :class="useMobileLayout ? 'bg-gray-200' : ''"
> >
<LearningPathAppointmentsMock></LearningPathAppointmentsMock> <!--<LearningPathAppointmentsMock></LearningPathAppointmentsMock>-->
</div> </div>
</div> </div>
</div> </div>

View File

@ -11,33 +11,22 @@ import type {
AssignmentCompletionStatus, AssignmentCompletionStatus,
CourseSessionUser, CourseSessionUser,
LearningContentAssignment, LearningContentAssignment,
LearningContentInterface,
UserAssignmentCompletionStatus, UserAssignmentCompletionStatus,
} from "@/types"; } from "@/types";
import { sum } from "d3"; import { sum } from "d3";
import pick from "lodash/pick"; import pick from "lodash/pick";
export interface AssignmentLearningContent extends LearningContentInterface { export function calcLearningContentAssignments(learningPath?: LearningPath) {
assignmentId: number;
}
export function calcAssignmentLearningContents(learningPath?: LearningPath) {
// TODO: filter by circle // TODO: filter by circle
if (!learningPath) return []; if (!learningPath) return [];
return learningPath.circles.flatMap((circle) => { return learningPath.circles.flatMap((circle) => {
const learningContents = circle.flatLearningContents.filter( return circle.flatLearningContents.filter(
(lc) => (lc) =>
lc.content_type === "learnpath.LearningContentAssignment" && lc.content_type === "learnpath.LearningContentAssignment" &&
lc.assignment_type === "CASEWORK" lc.assignment_type === "CASEWORK"
) as LearningContentAssignment[]; ) as LearningContentAssignment[];
return learningContents.map((lc) => { });
return {
...lc,
assignmentId: lc.content_assignment_id,
};
});
}) as AssignmentLearningContent[];
} }
export async function loadAssignmentCompletionStatusData( export async function loadAssignmentCompletionStatusData(
@ -98,7 +87,7 @@ export function findAssignmentDetail(assignmentId: number) {
return undefined; return undefined;
} }
const learningContents = calcAssignmentLearningContents( const learningContents = calcLearningContentAssignments(
learningPathStore.learningPathForUser( learningPathStore.learningPathForUser(
courseSessionsStore.currentCourseSession.course.slug, courseSessionsStore.currentCourseSession.course.slug,
userStore.id userStore.id
@ -106,7 +95,7 @@ export function findAssignmentDetail(assignmentId: number) {
); );
const learningContent = learningContents.find( const learningContent = learningContents.find(
(lc) => lc.assignmentId === assignmentId (lc) => lc.content_assignment_id === assignmentId
); );
return courseSessionsStore.findCourseSessionAssignment(learningContent?.id); return courseSessionsStore.findCourseSessionAssignment(learningContent?.id);

View File

@ -2673,7 +2673,7 @@ def create_uk_basis_prep_assignment(course_id=COURSE_UK):
return assignment return assignment
def create_uk_reflection(course_id=COURSE_UK, circle_title="Fahrzeug"): def create_uk_reflection(course_id=COURSE_UK):
assignment_list_page = ( assignment_list_page = (
CoursePage.objects.get(course_id=course_id) CoursePage.objects.get(course_id=course_id)
.get_children() .get_children()

View File

@ -3,6 +3,7 @@ import json
import graphene import graphene
import structlog import structlog
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
from wagtail.models import Page
from vbv_lernwelt.assignment.graphql.types import AssignmentCompletionObjectType from vbv_lernwelt.assignment.graphql.types import AssignmentCompletionObjectType
from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletionStatus from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletionStatus
@ -20,6 +21,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
class Arguments: class Arguments:
assignment_id = graphene.ID(required=True) assignment_id = graphene.ID(required=True)
course_session_id = graphene.ID(required=True) course_session_id = graphene.ID(required=True)
learning_content_page_id = graphene.ID()
assignment_user_id = graphene.ID() assignment_user_id = graphene.ID()
completion_status = graphene.Argument( completion_status = graphene.Argument(
@ -37,6 +39,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
info, info,
assignment_id, assignment_id,
course_session_id, course_session_id,
learning_content_page_id=None,
assignment_user_id=None, assignment_user_id=None,
completion_status: AssignmentCompletionStatus = AssignmentCompletionStatus.IN_PROGRESS, completion_status: AssignmentCompletionStatus = AssignmentCompletionStatus.IN_PROGRESS,
completion_data_string="{}", completion_data_string="{}",
@ -56,12 +59,20 @@ class AssignmentCompletionMutation(graphene.Mutation):
raise PermissionDenied() raise PermissionDenied()
course_session = CourseSession.objects.get(id=course_session_id) course_session = CourseSession.objects.get(id=course_session_id)
learning_content_page = None
if learning_content_page_id:
learning_content_page = Page.objects.get(id=learning_content_page_id)
if learning_content_page is None:
learning_content_page = assignment.learningcontentassignment_set.first()
assignment_data = { assignment_data = {
"assignment_user": assignment_user, "assignment_user": assignment_user,
"assignment": assignment, "assignment": assignment,
"course_session": course_session, "course_session": course_session,
"completion_data": json.loads(completion_data_string), "completion_data": json.loads(completion_data_string),
"completion_status": completion_status, "completion_status": completion_status,
"learning_content_page": learning_content_page,
} }
if completion_status == AssignmentCompletionStatus.SUBMITTED: if completion_status == AssignmentCompletionStatus.SUBMITTED:

View File

@ -23,11 +23,18 @@ class AssignmentQuery(object):
AssignmentCompletionObjectType, AssignmentCompletionObjectType,
assignment_id=graphene.ID(required=True), assignment_id=graphene.ID(required=True),
course_session_id=graphene.ID(required=True), course_session_id=graphene.ID(required=True),
learning_content_page_id=graphene.ID(required=False),
assignment_user_id=graphene.ID(required=False), assignment_user_id=graphene.ID(required=False),
) )
def resolve_assignment_completion( def resolve_assignment_completion(
root, info, assignment_id, course_session_id, assignment_user_id=None, **kwargs root,
info,
assignment_id,
course_session_id,
learning_content_page_id=None,
assignment_user_id=None,
**kwargs,
): ):
if assignment_user_id is None: if assignment_user_id is None:
assignment_user_id = info.context.user.id assignment_user_id = info.context.user.id
@ -37,9 +44,17 @@ class AssignmentQuery(object):
) or is_course_session_expert(info.context.user, course_session_id): ) or is_course_session_expert(info.context.user, course_session_id):
course_id = CourseSession.objects.get(id=course_session_id).course_id course_id = CourseSession.objects.get(id=course_session_id).course_id
if has_course_access(info.context.user, course_id): if has_course_access(info.context.user, course_id):
if learning_content_page_id is None:
learning_content_page = Assignment.objects.get(
id=assignment_id
).learningcontentassignment_set.first()
if learning_content_page:
learning_content_page_id = learning_content_page.id
return AssignmentCompletion.objects.filter( return AssignmentCompletion.objects.filter(
assignment_user_id=assignment_user_id, assignment_user_id=assignment_user_id,
assignment_id=assignment_id, assignment_id=assignment_id,
learning_content_page_id=learning_content_page_id,
course_session_id=course_session_id, course_session_id=course_session_id,
).first() ).first()
raise PermissionDenied() raise PermissionDenied()

View File

@ -1,3 +1,4 @@
import graphene
from graphene.types.generic import GenericScalar from graphene.types.generic import GenericScalar
from graphene_django import DjangoObjectType from graphene_django import DjangoObjectType
@ -25,6 +26,7 @@ class AssignmentObjectType(DjangoObjectType):
class AssignmentCompletionObjectType(DjangoObjectType): class AssignmentCompletionObjectType(DjangoObjectType):
completion_data = GenericScalar() completion_data = GenericScalar()
learning_content_page_id = graphene.ID(source="learning_content_page_id")
class Meta: class Meta:
model = AssignmentCompletion model = AssignmentCompletion
@ -37,6 +39,7 @@ class AssignmentCompletionObjectType(DjangoObjectType):
"assignment_user", "assignment_user",
"assignment", "assignment",
"course_session", "course_session",
"learning_content_page_id",
"completion_status", "completion_status",
"completion_data", "completion_data",
"evaluation_user", "evaluation_user",

View File

@ -0,0 +1,48 @@
# Generated by Django 3.2.13 on 2023-07-12 14:49
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("wagtailcore", "0083_workflowcontenttype"),
("assignment", "0006_auto_20230628_1616"),
]
operations = [
migrations.RemoveConstraint(
model_name="assignmentcompletion",
name="assignment_completion_unique_user_assignment_course_session",
),
migrations.RemoveField(
model_name="assignmentcompletion",
name="circle",
),
migrations.AddField(
model_name="assignmentcompletion",
name="learning_content_page",
field=models.ForeignKey(
blank=True,
default=None,
help_text="Page reference mostly needed for 'REFLECTION' assignments",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to="wagtailcore.page",
),
),
migrations.AddConstraint(
model_name="assignmentcompletion",
constraint=models.UniqueConstraint(
fields=(
"assignment_user",
"assignment",
"course_session",
"learning_content_page",
),
name="assignment_completion_unique_user_assignment_course_session",
),
),
]

View File

@ -270,12 +270,15 @@ class AssignmentCompletion(models.Model):
assignment_user = models.ForeignKey(User, on_delete=models.CASCADE) assignment_user = models.ForeignKey(User, on_delete=models.CASCADE)
assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE) assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE)
course_session = models.ForeignKey("course.CourseSession", on_delete=models.CASCADE) course_session = models.ForeignKey("course.CourseSession", on_delete=models.CASCADE)
circle = models.ForeignKey(
"learnpath.Circle", learning_content_page = models.ForeignKey(
on_delete=models.CASCADE, Page,
on_delete=models.SET_NULL,
null=True, null=True,
blank=True, blank=True,
default=None, default=None,
related_name="+",
help_text="Page reference mostly needed for 'REFLECTION' assignments",
) )
completion_status = models.CharField( completion_status = models.CharField(
@ -290,7 +293,12 @@ class AssignmentCompletion(models.Model):
class Meta: class Meta:
constraints = [ constraints = [
UniqueConstraint( UniqueConstraint(
fields=["assignment_user", "assignment", "course_session", "circle"], fields=[
"assignment_user",
"assignment",
"course_session",
"learning_content_page",
],
name="assignment_completion_unique_user_assignment_course_session", name="assignment_completion_unique_user_assignment_course_session",
) )
] ]

View File

@ -3,6 +3,7 @@ from gettext import gettext
from django.utils import timezone from django.utils import timezone
from rest_framework import serializers from rest_framework import serializers
from wagtail.models import Page
from vbv_lernwelt.assignment.models import ( from vbv_lernwelt.assignment.models import (
Assignment, Assignment,
@ -22,6 +23,7 @@ def update_assignment_completion(
assignment_user: User, assignment_user: User,
assignment: Assignment, assignment: Assignment,
course_session: CourseSession, course_session: CourseSession,
learning_content_page: Page | None = None,
completion_data=None, completion_data=None,
completion_status: AssignmentCompletionStatus = AssignmentCompletionStatus.IN_PROGRESS, completion_status: AssignmentCompletionStatus = AssignmentCompletionStatus.IN_PROGRESS,
evaluation_user: User | None = None, evaluation_user: User | None = None,
@ -56,6 +58,9 @@ def update_assignment_completion(
assignment_user_id=assignment_user.id, assignment_user_id=assignment_user.id,
assignment_id=assignment.id, assignment_id=assignment.id,
course_session_id=course_session.id, course_session_id=course_session.id,
learning_content_page_id=learning_content_page.id
if learning_content_page
else None,
) )
if not is_valid_assignment_completion_status(completion_status): if not is_valid_assignment_completion_status(completion_status):

View File

@ -199,6 +199,7 @@ class AttendanceCourseUserMutationTestCase(GraphQLTestCase):
ac = AssignmentCompletion.objects.create( ac = AssignmentCompletion.objects.create(
assignment_user=self.student, assignment_user=self.student,
assignment=self.assignment, assignment=self.assignment,
learning_content_page=self.assignment.learningcontentassignment_set.first(),
course_session=self.course_session, course_session=self.course_session,
completion_status="SUBMITTED", completion_status="SUBMITTED",
submitted_at=timezone.now(), submitted_at=timezone.now(),
@ -366,3 +367,84 @@ class AttendanceCourseUserMutationTestCase(GraphQLTestCase):
}, },
}, },
) )
def test_student_can_upsert_reflection(self):
"""
when upserting a reflection, it will store also the page_id of the learning content
"""
reflection = Assignment.objects.get(slug="test-lehrgang-assignment-reflexion")
reflection_subtasks = reflection.filter_user_subtasks()
reflection_learning_content = reflection.learningcontentassignment_set.first()
self.client.force_login(self.student)
user_text_input = find_first(
reflection_subtasks, pred=lambda x: x["type"] == "user_text_input"
)
completion_data_string = json.dumps(
{
user_text_input["id"]: {
"user_data": {"text": "Hallo via Reflection API"}
},
}
).replace('"', '\\"')
query = f"""
mutation {{
upsert_assignment_completion(
assignment_id: {reflection.id}
course_session_id: {self.course_session.id}
learning_content_page_id: {reflection_learning_content.id}
completion_status: IN_PROGRESS
completion_data_string: "{completion_data_string}"
) {{
assignment_completion {{
id
completion_status
completion_data
assignment_user {{ id }}
assignment {{ id }}
learning_content_page_id
}}
}}
}}
"""
response = self.query(query)
self.assertResponseNoErrors(response)
data = json.loads(response.content)["data"]["upsert_assignment_completion"][
"assignment_completion"
]
print(data)
self.assertEqual(data["assignment_user"]["id"], str(self.student.id))
self.assertEqual(data["assignment"]["id"], str(reflection.id))
self.assertEqual(data["completion_status"], "IN_PROGRESS")
self.assertEqual(
data["learning_content_page_id"], str(reflection_learning_content.id)
)
self.assertDictEqual(
data["completion_data"],
{
user_text_input["id"]: {
"user_data": {"text": "Hallo via Reflection API"}
},
},
)
# check DB data
db_entry = AssignmentCompletion.objects.get(
assignment_user=self.student,
course_session_id=self.course_session.id,
assignment_id=reflection.id,
learning_content_page_id=reflection_learning_content.id,
)
self.assertEqual(db_entry.completion_status, "IN_PROGRESS")
self.assertDictEqual(
db_entry.completion_data,
{
user_text_input["id"]: {
"user_data": {"text": "Hallo via Reflection API"}
},
},
)

View File

@ -12,6 +12,7 @@ from wagtail.rich_text import RichText
from vbv_lernwelt.assignment.creators.create_assignments import ( from vbv_lernwelt.assignment.creators.create_assignments import (
create_uk_fahrzeug_casework, create_uk_fahrzeug_casework,
create_uk_fahrzeug_prep_assignment, create_uk_fahrzeug_prep_assignment,
create_uk_reflection,
) )
from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletionStatus from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletionStatus
from vbv_lernwelt.assignment.services import update_assignment_completion from vbv_lernwelt.assignment.services import update_assignment_completion
@ -85,6 +86,7 @@ def create_test_course(include_uk=True, include_vv=True, with_sessions=False):
) )
create_uk_fahrzeug_casework(course_id=COURSE_TEST_ID) create_uk_fahrzeug_casework(course_id=COURSE_TEST_ID)
create_uk_fahrzeug_prep_assignment(course_id=COURSE_TEST_ID) create_uk_fahrzeug_prep_assignment(course_id=COURSE_TEST_ID)
create_uk_reflection(course_id=COURSE_TEST_ID)
create_test_learning_path(include_uk=include_uk, include_vv=include_vv) create_test_learning_path(include_uk=include_uk, include_vv=include_vv)
create_test_media_library() create_test_media_library()
@ -182,6 +184,7 @@ def create_test_assignment_submitted_data(assignment, course_session, user):
assignment_user=user, assignment_user=user,
assignment=assignment, assignment=assignment,
course_session=course_session, course_session=course_session,
learning_content_page=assignment.learningcontentassignment_set.first(),
completion_data={ completion_data={
subtask["id"]: { subtask["id"]: {
"user_data": {"text": user_text}, "user_data": {"text": user_text},
@ -192,6 +195,7 @@ def create_test_assignment_submitted_data(assignment, course_session, user):
assignment_user=user, assignment_user=user,
assignment=assignment, assignment=assignment,
course_session=course_session, course_session=course_session,
learning_content_page=assignment.learningcontentassignment_set.first(),
completion_status=AssignmentCompletionStatus.SUBMITTED, completion_status=AssignmentCompletionStatus.SUBMITTED,
) )
@ -328,10 +332,14 @@ damit du erfolgreich mit deinem Lernpfad (durch-)starten kannst.
) )
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end") LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", parent=circle) LearningUnitFactory(title="Transfer", parent=circle)
LearningContentPlaceholderFactory( LearningContentAssignmentFactory(
title="Reflexion", title="Reflexion",
assignment_type="REFLECTION",
parent=circle, parent=circle,
) content_assignment=Assignment.objects.get(
slug__startswith=f"test-lehrgang-assignment-reflexion"
),
),
LearningContentAssignmentFactory( LearningContentAssignmentFactory(
title="Überprüfen einer Motorfahrzeug-Versicherungspolice", title="Überprüfen einer Motorfahrzeug-Versicherungspolice",
parent=circle, parent=circle,

View File

@ -458,6 +458,7 @@ def create_course_uk_de_assignment_completion_data(assignment, course_session, u
update_assignment_completion( update_assignment_completion(
assignment_user=user, assignment_user=user,
assignment=assignment, assignment=assignment,
learning_content_page=assignment.learningcontentassignment_set.first(),
course_session=course_session, course_session=course_session,
completion_data={ completion_data={
subtask["id"]: { subtask["id"]: {
@ -468,6 +469,7 @@ def create_course_uk_de_assignment_completion_data(assignment, course_session, u
update_assignment_completion( update_assignment_completion(
assignment_user=user, assignment_user=user,
assignment=assignment, assignment=assignment,
learning_content_page=assignment.learningcontentassignment_set.first(),
course_session=course_session, course_session=course_session,
completion_status=AssignmentCompletionStatus.SUBMITTED, completion_status=AssignmentCompletionStatus.SUBMITTED,
) )

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.13 on 2023-07-12 14:49
import django_jsonform.models.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("course_session", "0004_merge_20230711_1108"),
]
operations = [
migrations.AlterField(
model_name="coursesessionattendancecourse",
name="attendance_user_list",
field=django_jsonform.models.fields.JSONField(default=list),
),
]