Attach completion data to `Assignment` in GraphQL schema

This commit is contained in:
Daniel Egger 2023-09-05 14:06:07 +02:00
parent 4bc1ca636c
commit 21174d17db
5 changed files with 150 additions and 139 deletions

View File

@ -99,6 +99,7 @@ export type AssignmentObjectType = CoursePageInterface & {
__typename?: 'AssignmentObjectType';
assignment_type: AssignmentAssignmentAssignmentTypeChoices;
circle?: Maybe<CircleObjectType>;
completion?: Maybe<AssignmentCompletionObjectType>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
/** Zeitaufwand als Text */
@ -122,6 +123,13 @@ export type AssignmentObjectType = CoursePageInterface & {
translation_key?: Maybe<Scalars['String']['output']>;
};
export type AssignmentObjectTypeCompletionArgs = {
assignment_user_id?: InputMaybe<Scalars['UUID']['input']>;
course_session_id: Scalars['ID']['input'];
learning_content_page_id?: InputMaybe<Scalars['ID']['input']>;
};
export type AttendanceCourseUserMutation = {
__typename?: 'AttendanceCourseUserMutation';
course_session_attendance_course?: Maybe<CourseSessionAttendanceCourseType>;
@ -566,7 +574,6 @@ export type Query = {
__typename?: 'Query';
assignment?: Maybe<AssignmentObjectType>;
assignment_completion?: Maybe<AssignmentCompletionObjectType>;
assignment_completions?: Maybe<Array<Maybe<AssignmentCompletionObjectType>>>;
circle?: Maybe<CircleObjectType>;
competence_certificate?: Maybe<CompetenceCertificateObjectType>;
competence_certificate_list?: Maybe<CompetenceCertificateListObjectType>;
@ -600,13 +607,6 @@ export type QueryAssignmentCompletionArgs = {
};
export type QueryAssignmentCompletionsArgs = {
assignment_ids: Array<InputMaybe<Scalars['ID']['input']>>;
assignment_user_id?: InputMaybe<Scalars['UUID']['input']>;
course_session_id: Scalars['ID']['input'];
};
export type QueryCircleArgs = {
id?: InputMaybe<Scalars['ID']['input']>;
slug?: InputMaybe<Scalars['String']['input']>;

View File

@ -17,7 +17,6 @@ type Query {
competence_certificate_list(id: ID, slug: String, course_id: ID, course_slug: String): CompetenceCertificateListObjectType
assignment(id: ID, slug: String): AssignmentObjectType
assignment_completion(assignment_id: ID!, course_session_id: ID!, learning_content_page_id: ID, assignment_user_id: UUID): AssignmentCompletionObjectType
assignment_completions(assignment_ids: [ID]!, course_session_id: ID!, assignment_user_id: UUID): [AssignmentCompletionObjectType]
}
type LearningPathObjectType implements CoursePageInterface {
@ -253,6 +252,7 @@ type AssignmentObjectType implements CoursePageInterface {
performance_objectives: JSONStreamField
max_points: Int
learning_content: LearningContentInterface
completion(course_session_id: ID!, learning_content_page_id: ID, assignment_user_id: UUID): AssignmentCompletionObjectType
}
"""An enumeration."""
@ -275,6 +275,53 @@ enum AssignmentAssignmentAssignmentTypeChoices {
scalar JSONStreamField
type AssignmentCompletionObjectType {
id: UUID!
created_at: DateTime!
updated_at: DateTime!
submitted_at: DateTime
evaluation_submitted_at: DateTime
evaluation_user: UserType
evaluation_grade: Float
evaluation_points: Float
assignment_user: UserType!
assignment: AssignmentObjectType!
completion_status: AssignmentAssignmentCompletionCompletionStatusChoices!
completion_data: GenericScalar
additional_json_data: JSONString!
learning_content_page_id: ID
}
"""An enumeration."""
enum AssignmentAssignmentCompletionCompletionStatusChoices {
"""IN_PROGRESS"""
IN_PROGRESS
"""SUBMITTED"""
SUBMITTED
"""EVALUATION_IN_PROGRESS"""
EVALUATION_IN_PROGRESS
"""EVALUATION_SUBMITTED"""
EVALUATION_SUBMITTED
}
"""
The `GenericScalar` scalar type represents a generic
GraphQL scalar value that could be:
String, Boolean, Int, Float, List or Object.
"""
scalar GenericScalar
"""
Allows use of a JSON String for input / output from the GraphQL schema.
Use of this type is *not recommended* as you lose the benefits of having a defined, static
schema (one of the key benefits of GraphQL).
"""
scalar JSONString
"""An enumeration."""
enum LearnpathLearningContentAssignmentAssignmentTypeChoices {
"""CASEWORK"""
@ -497,53 +544,6 @@ type CompetenceCertificateListObjectType implements CoursePageInterface {
competence_certificates: [CompetenceCertificateObjectType]
}
type AssignmentCompletionObjectType {
id: UUID!
created_at: DateTime!
updated_at: DateTime!
submitted_at: DateTime
evaluation_submitted_at: DateTime
evaluation_user: UserType
evaluation_grade: Float
evaluation_points: Float
assignment_user: UserType!
assignment: AssignmentObjectType!
completion_status: AssignmentAssignmentCompletionCompletionStatusChoices!
completion_data: GenericScalar
additional_json_data: JSONString!
learning_content_page_id: ID
}
"""An enumeration."""
enum AssignmentAssignmentCompletionCompletionStatusChoices {
"""IN_PROGRESS"""
IN_PROGRESS
"""SUBMITTED"""
SUBMITTED
"""EVALUATION_IN_PROGRESS"""
EVALUATION_IN_PROGRESS
"""EVALUATION_SUBMITTED"""
EVALUATION_SUBMITTED
}
"""
The `GenericScalar` scalar type represents a generic
GraphQL scalar value that could be:
String, Boolean, Int, Float, List or Object.
"""
scalar GenericScalar
"""
Allows use of a JSON String for input / output from the GraphQL schema.
Use of this type is *not recommended* as you lose the benefits of having a defined, static
schema (one of the key benefits of GraphQL).
"""
scalar JSONString
type Mutation {
send_feedback(input: SendFeedbackInput!): SendFeedbackPayload
update_course_session_attendance_course_users(attendance_user_list: [AttendanceUserInputType]!, id: ID!): AttendanceCourseUserMutation

View File

@ -1,14 +1,11 @@
import graphene
from rest_framework.exceptions import PermissionDenied
from vbv_lernwelt.assignment.graphql.types import (
AssignmentCompletionObjectType,
AssignmentObjectType,
AssignmentObjectType, resolve_assignment_completion,
)
from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletion
from vbv_lernwelt.assignment.models import Assignment
from vbv_lernwelt.course.graphql.types import resolve_course_page
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.course.permissions import has_course_access, is_course_session_expert
class AssignmentQuery(object):
@ -36,55 +33,7 @@ class AssignmentQuery(object):
assignment_user_id=None,
**kwargs,
):
if assignment_user_id is None:
assignment_user_id = info.context.user.id
if str(assignment_user_id) == str(
info.context.user.id
) or is_course_session_expert(info.context.user, course_session_id):
course_id = CourseSession.objects.get(id=course_session_id).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(
assignment_user_id=assignment_user_id,
assignment_id=assignment_id,
learning_content_page_id=learning_content_page_id,
course_session_id=course_session_id,
).first()
raise PermissionDenied()
assignment_completions = graphene.List(
AssignmentCompletionObjectType,
assignment_ids=graphene.List(graphene.ID, required=True),
course_session_id=graphene.ID(required=True),
assignment_user_id=graphene.UUID(required=False),
)
def resolve_assignment_completions(
root,
info,
assignment_ids,
course_session_id,
assignment_user_id=None,
**kwargs,
):
if assignment_user_id is None:
assignment_user_id = info.context.user.id
if str(assignment_user_id) == str(
info.context.user.id
) or is_course_session_expert(info.context.user, course_session_id):
course_id = CourseSession.objects.get(id=course_session_id).course_id
if has_course_access(info.context.user, course_id):
return AssignmentCompletion.objects.filter(
assignment_user_id=assignment_user_id,
assignment_id__in=assignment_ids,
course_session_id=course_session_id,
)
raise PermissionDenied()
return resolve_assignment_completion(
info, assignment_id, course_session_id, learning_content_page_id,
assignment_user_id,
)

View File

@ -1,39 +1,16 @@
import graphene
from graphene.types.generic import GenericScalar
from graphene_django import DjangoObjectType
from rest_framework.exceptions import PermissionDenied
from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletion
from vbv_lernwelt.core.graphql.types import JSONStreamField
from vbv_lernwelt.course.graphql.interfaces import CoursePageInterface
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.course.permissions import is_course_session_expert, has_course_access
from vbv_lernwelt.learnpath.graphql.types import LearningContentInterface
class AssignmentObjectType(DjangoObjectType):
tasks = JSONStreamField()
evaluation_tasks = JSONStreamField()
performance_objectives = JSONStreamField()
max_points = graphene.Int()
learning_content = graphene.Field(LearningContentInterface)
class Meta:
model = Assignment
interfaces = (CoursePageInterface,)
fields = (
"assignment_type",
"intro_text",
"effort_required",
"evaluation_description",
"evaluation_document_url",
"learning_content",
)
def resolve_max_points(self, info):
return self.get_max_points()
def resolve_learning_content(self, info):
return self.find_attached_learning_content()
class AssignmentCompletionObjectType(DjangoObjectType):
completion_data = GenericScalar()
learning_content_page_id = graphene.ID(source="learning_content_page_id")
@ -57,3 +34,82 @@ class AssignmentCompletionObjectType(DjangoObjectType):
"evaluation_grade",
"evaluation_points",
)
class AssignmentObjectType(DjangoObjectType):
tasks = JSONStreamField()
evaluation_tasks = JSONStreamField()
performance_objectives = JSONStreamField()
max_points = graphene.Int()
learning_content = graphene.Field(LearningContentInterface)
completion = graphene.Field(
AssignmentCompletionObjectType,
course_session_id=graphene.ID(required=True),
learning_content_page_id=graphene.ID(required=False),
assignment_user_id=graphene.UUID(required=False),
)
class Meta:
model = Assignment
interfaces = (CoursePageInterface,)
fields = (
"assignment_type",
"intro_text",
"effort_required",
"evaluation_description",
"evaluation_document_url",
"learning_content",
)
def resolve_max_points(self, info):
return self.get_max_points()
def resolve_learning_content(self, info):
return self.find_attached_learning_content()
def resolve_completion(
self, info, course_session_id, learning_content_page_id=None,
assignment_user_id=None,
):
if learning_content_page_id is None:
lp = self.find_attached_learning_content()
if lp:
learning_content_page_id = lp.id
return resolve_assignment_completion(
info=info,
course_session_id=course_session_id,
learning_content_page_id=learning_content_page_id,
assignment_user_id=assignment_user_id,
assignment_id=self.id,
)
def resolve_assignment_completion(
info,
assignment_id,
course_session_id,
learning_content_page_id=None,
assignment_user_id=None,
):
if assignment_user_id is None:
assignment_user_id = info.context.user.id
if str(assignment_user_id) == str(
info.context.user.id
) or is_course_session_expert(info.context.user, course_session_id):
course_id = CourseSession.objects.get(id=course_session_id).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(
assignment_user_id=assignment_user_id,
assignment_id=assignment_id,
learning_content_page_id=learning_content_page_id,
course_session_id=course_session_id,
).first()
raise PermissionDenied()

View File

@ -265,6 +265,12 @@ class Assignment(CourseBasePage):
return page.specific
return None
def get_frontend_url(self):
lp = self.find_attached_learning_content()
if lp:
return lp.get_frontend_url()
return ""
class AssignmentCompletionStatus(Enum):
IN_PROGRESS = "IN_PROGRESS"