@things-factory/learning 10.1.261 → 10.1.262
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/pages/learning-course-list.d.ts +0 -4
- package/dist-client/pages/learning-course-list.js +48 -14
- package/dist-client/pages/learning-course-list.js.map +1 -1
- package/dist-client/pages/learning-enrollment-status.d.ts +3 -0
- package/dist-client/pages/learning-enrollment-status.js +13 -9
- package/dist-client/pages/learning-enrollment-status.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/course/course-query.d.ts +1 -0
- package/dist-server/service/course/course-query.js +13 -0
- package/dist-server/service/course/course-query.js.map +1 -1
- package/dist-server/service/enrollment/enrollment-mutation.d.ts +1 -1
- package/dist-server/service/enrollment/enrollment-mutation.js +6 -6
- package/dist-server/service/enrollment/enrollment-mutation.js.map +1 -1
- package/dist-server/service/enrollment/enrollment-query.d.ts +4 -1
- package/dist-server/service/enrollment/enrollment-query.js +21 -1
- package/dist-server/service/enrollment/enrollment-query.js.map +1 -1
- package/dist-server/service/enrollment/enrollment-service.d.ts +4 -3
- package/dist-server/service/enrollment/enrollment-service.js +28 -15
- package/dist-server/service/enrollment/enrollment-service.js.map +1 -1
- package/dist-server/service/enrollment/enrollment-status.d.ts +11 -0
- package/dist-server/service/enrollment/enrollment-status.js +42 -0
- package/dist-server/service/enrollment/enrollment-status.js.map +1 -1
- package/dist-server/service/enrollment/enrollment-type.d.ts +7 -0
- package/dist-server/service/enrollment/enrollment-type.js +27 -1
- package/dist-server/service/enrollment/enrollment-type.js.map +1 -1
- package/dist-server/service/enrollment/index.d.ts +3 -3
- package/dist-server/service/enrollment/index.js +3 -3
- package/dist-server/service/enrollment/index.js.map +1 -1
- package/dist-server/service/enrollment/progress-rules.d.ts +4 -0
- package/dist-server/service/enrollment/progress-rules.js +7 -1
- package/dist-server/service/enrollment/progress-rules.js.map +1 -1
- package/dist-server/service/index.d.ts +2 -2
- package/dist-server/service/index.js +2 -2
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/translations/en.json +13 -3
- package/translations/es.json +13 -3
- package/translations/ja.json +13 -3
- package/translations/ko.json +13 -3
- package/translations/ms.json +13 -3
- package/translations/zh.json +13 -3
|
@@ -16,6 +16,7 @@ export declare class CourseQuery {
|
|
|
16
16
|
}
|
|
17
17
|
export declare class CourseVersionFields {
|
|
18
18
|
units(version: CourseVersion, context: ResolverContext): Promise<CourseUnit[]>;
|
|
19
|
+
expectedSeconds(version: CourseVersion, context: ResolverContext): Promise<number | null>;
|
|
19
20
|
questions(version: CourseVersion, context: ResolverContext): Promise<CourseQuestion[]>;
|
|
20
21
|
}
|
|
21
22
|
export declare class CourseUnitFields {
|
|
@@ -105,6 +105,11 @@ let CourseVersionFields = class CourseVersionFields {
|
|
|
105
105
|
return [];
|
|
106
106
|
return await (0, course_service_1.unitsOf)((0, course_service_1.learningManagerOf)(context), version.id);
|
|
107
107
|
}
|
|
108
|
+
async expectedSeconds(version, context) {
|
|
109
|
+
if (!(await (0, course_service_1.mayReadVersion)(context, version)))
|
|
110
|
+
return null;
|
|
111
|
+
return (0, progress_rules_1.expectedSecondsOf)(await (0, course_service_1.unitsOf)((0, course_service_1.learningManagerOf)(context), version.id), version.minSeconds);
|
|
112
|
+
}
|
|
108
113
|
async questions(version, context) {
|
|
109
114
|
if (!(await (0, auth_base_1.requestHolds)(context, 'course', 'query')))
|
|
110
115
|
return [];
|
|
@@ -120,6 +125,14 @@ tslib_1.__decorate([
|
|
|
120
125
|
tslib_1.__metadata("design:paramtypes", [course_version_1.CourseVersion, Object]),
|
|
121
126
|
tslib_1.__metadata("design:returntype", Promise)
|
|
122
127
|
], CourseVersionFields.prototype, "units", null);
|
|
128
|
+
tslib_1.__decorate([
|
|
129
|
+
(0, type_graphql_1.FieldResolver)(type => type_graphql_1.Int, { nullable: true, description: 'The seconds it takes at least - every unit done (a video its length, a PDF or text its least time) and its least time, the longer. Empty for whoever may not read it.' }),
|
|
130
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
131
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
132
|
+
tslib_1.__metadata("design:type", Function),
|
|
133
|
+
tslib_1.__metadata("design:paramtypes", [course_version_1.CourseVersion, Object]),
|
|
134
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
135
|
+
], CourseVersionFields.prototype, "expectedSeconds", null);
|
|
123
136
|
tslib_1.__decorate([
|
|
124
137
|
(0, type_graphql_1.FieldResolver)(type => [course_question_1.CourseQuestion], { description: 'Its questions, in order - for a manager; nothing for anyone else.' }),
|
|
125
138
|
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"course-query.js","sourceRoot":"","sources":["../../../server/service/course/course-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Int, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\n\nimport { Attachment } from '@things-factory/attachment-base'\nimport { requestHolds, User } from '@things-factory/auth-base'\nimport { getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\n\nimport { secondsPerPage } from '../enrollment/progress-rules'\nimport { Course } from './course'\nimport { CourseQuestion } from './course-question'\nimport { CourseUnit } from './course-unit'\nimport { CourseVersion } from './course-version'\nimport { CourseChoiceKey, CourseList } from './course-type'\nimport { learningManagerOf, mayReadVersion, publishedVersionOf, questionsOf, unitFilesOf, unitsOf } from './course-service'\n\n\n/*\n * The managers' reads of courses (ADR-0194 decisions 2-4, 10, 11) - `course` query, the task `learning.managing`. A learner\n * reads a course through their enrolment (enrollment-query.ts), never these.\n */\n@Resolver(Course)\n@UseMiddleware(SpeakRefusals)\nexport class CourseQuery {\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => CourseList, { description: 'The courses of the domain.' })\n async courses(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<CourseList> {\n const { domain } = context.state\n const qb = getQueryBuilderFromListParams({ domain, params, repository: getRepository(Course), alias: 'C', searchables: ['name', 'description', 'category'] })\n if (!params?.sortings?.length) qb.orderBy('C.name', 'ASC')\n const [items, total] = await qb.getManyAndCount()\n return { items, total }\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Course, { nullable: true, description: 'One course.' })\n async course(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Course | null> {\n return await getRepository(Course).findOne({ where: { id, domain: { id: context.state.domain.id } } as any })\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => CourseVersion, { nullable: true, description: 'One version of a course, with its units and questions.' })\n async courseVersion(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<CourseVersion | null> {\n return await getRepository(CourseVersion).findOne({ where: { id, domain: { id: context.state.domain.id } } as any })\n }\n\n @FieldResolver(type => [CourseVersion], { description: 'Its versions, the newest first - for a manager; nothing for anyone else.' })\n async versions(@Root() course: Course, @Ctx() context: ResolverContext): Promise<CourseVersion[]> {\n if (!(await requestHolds(context, 'course', 'query'))) return []\n return await getRepository(CourseVersion).find({ where: { course: { id: course.id } } as any, order: { number: 'DESC' } as any })\n }\n\n @FieldResolver(type => CourseVersion, { nullable: true, description: 'The version learners take now.' })\n async publishedVersion(@Root() course: Course, @Ctx() context: ResolverContext): Promise<CourseVersion | null> {\n return await publishedVersionOf(learningManagerOf(context), { id: course.domainId! }, course.id)\n }\n\n @FieldResolver(type => User, { nullable: true, description: 'Who keeps it.' })\n async manager(@Root() course: Course): Promise<User | null> {\n return course.managerId ? await getRepository(User).findOneBy({ id: course.managerId }) : null\n }\n}\n\n@Resolver(CourseVersion)\nexport class CourseVersionFields {\n @FieldResolver(type => [CourseUnit], { description: 'Its units, in order - for a manager, or a learner whose enrolment shows this version.' })\n async units(@Root() version: CourseVersion, @Ctx() context: ResolverContext): Promise<CourseUnit[]> {\n if (!(await mayReadVersion(context, version))) return []\n return await unitsOf(learningManagerOf(context), version.id)\n }\n\n @FieldResolver(type => [CourseQuestion], { description: 'Its questions, in order - for a manager; nothing for anyone else.' })\n async questions(@Root() version: CourseVersion, @Ctx() context: ResolverContext): Promise<CourseQuestion[]> {\n if (!(await requestHolds(context, 'course', 'query'))) return []\n return await questionsOf(learningManagerOf(context), version.id)\n }\n}\n\n@Resolver(CourseUnit)\nexport class CourseUnitFields {\n @FieldResolver(type => Int, { nullable: true, description: 'The fewest seconds a PDF page is looked at to count as read - the screen and the server read the same.' })\n secondsPerPage(@Root() unit: CourseUnit): number | null {\n return unit.kind === 'PDF' ? secondsPerPage(unit) : null\n }\n\n @FieldResolver(type => Attachment, { nullable: true, description: \"A video's or a PDF's file.\" })\n async file(@Root() unit: CourseUnit, @Ctx() context: ResolverContext): Promise<Attachment | null> {\n const version = await learningManagerOf(context).getRepository(CourseVersion).findOne({ where: { id: unit.versionId } as any, withDeleted: true })\n if (!(await mayReadVersion(context, version))) return null\n return (await unitFilesOf(context.state.domain, [unit.id])).get(unit.id) ?? null\n }\n}\n\n@Resolver(CourseQuestion)\nexport class CourseQuestionFields {\n @FieldResolver(type => [CourseChoiceKey], { description: 'Its choices with which are right - for a manager only.' })\n async choices(@Root() question: CourseQuestion, @Ctx() context: ResolverContext): Promise<CourseChoiceKey[]> {\n if (!(await requestHolds(context, 'course', 'query'))) return []\n return question.choices ?? []\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"course-query.js","sourceRoot":"","sources":["../../../server/service/course/course-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Int, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\n\nimport { Attachment } from '@things-factory/attachment-base'\nimport { requestHolds, User } from '@things-factory/auth-base'\nimport { getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\n\nimport { expectedSecondsOf, secondsPerPage } from '../enrollment/progress-rules'\nimport { Course } from './course'\nimport { CourseQuestion } from './course-question'\nimport { CourseUnit } from './course-unit'\nimport { CourseVersion } from './course-version'\nimport { CourseChoiceKey, CourseList } from './course-type'\nimport { learningManagerOf, mayReadVersion, publishedVersionOf, questionsOf, unitFilesOf, unitsOf } from './course-service'\n\n\n/*\n * The managers' reads of courses (ADR-0194 decisions 2-4, 10, 11) - `course` query, the task `learning.managing`. A learner\n * reads a course through their enrolment (enrollment-query.ts), never these.\n */\n@Resolver(Course)\n@UseMiddleware(SpeakRefusals)\nexport class CourseQuery {\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => CourseList, { description: 'The courses of the domain.' })\n async courses(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<CourseList> {\n const { domain } = context.state\n const qb = getQueryBuilderFromListParams({ domain, params, repository: getRepository(Course), alias: 'C', searchables: ['name', 'description', 'category'] })\n if (!params?.sortings?.length) qb.orderBy('C.name', 'ASC')\n const [items, total] = await qb.getManyAndCount()\n return { items, total }\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Course, { nullable: true, description: 'One course.' })\n async course(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Course | null> {\n return await getRepository(Course).findOne({ where: { id, domain: { id: context.state.domain.id } } as any })\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => CourseVersion, { nullable: true, description: 'One version of a course, with its units and questions.' })\n async courseVersion(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<CourseVersion | null> {\n return await getRepository(CourseVersion).findOne({ where: { id, domain: { id: context.state.domain.id } } as any })\n }\n\n @FieldResolver(type => [CourseVersion], { description: 'Its versions, the newest first - for a manager; nothing for anyone else.' })\n async versions(@Root() course: Course, @Ctx() context: ResolverContext): Promise<CourseVersion[]> {\n if (!(await requestHolds(context, 'course', 'query'))) return []\n return await getRepository(CourseVersion).find({ where: { course: { id: course.id } } as any, order: { number: 'DESC' } as any })\n }\n\n @FieldResolver(type => CourseVersion, { nullable: true, description: 'The version learners take now.' })\n async publishedVersion(@Root() course: Course, @Ctx() context: ResolverContext): Promise<CourseVersion | null> {\n return await publishedVersionOf(learningManagerOf(context), { id: course.domainId! }, course.id)\n }\n\n @FieldResolver(type => User, { nullable: true, description: 'Who keeps it.' })\n async manager(@Root() course: Course): Promise<User | null> {\n return course.managerId ? await getRepository(User).findOneBy({ id: course.managerId }) : null\n }\n}\n\n@Resolver(CourseVersion)\nexport class CourseVersionFields {\n @FieldResolver(type => [CourseUnit], { description: 'Its units, in order - for a manager, or a learner whose enrolment shows this version.' })\n async units(@Root() version: CourseVersion, @Ctx() context: ResolverContext): Promise<CourseUnit[]> {\n if (!(await mayReadVersion(context, version))) return []\n return await unitsOf(learningManagerOf(context), version.id)\n }\n\n @FieldResolver(type => Int, { nullable: true, description: 'The seconds it takes at least - every unit done (a video its length, a PDF or text its least time) and its least time, the longer. Empty for whoever may not read it.' })\n async expectedSeconds(@Root() version: CourseVersion, @Ctx() context: ResolverContext): Promise<number | null> {\n if (!(await mayReadVersion(context, version))) return null\n return expectedSecondsOf(await unitsOf(learningManagerOf(context), version.id), version.minSeconds)\n }\n\n @FieldResolver(type => [CourseQuestion], { description: 'Its questions, in order - for a manager; nothing for anyone else.' })\n async questions(@Root() version: CourseVersion, @Ctx() context: ResolverContext): Promise<CourseQuestion[]> {\n if (!(await requestHolds(context, 'course', 'query'))) return []\n return await questionsOf(learningManagerOf(context), version.id)\n }\n}\n\n@Resolver(CourseUnit)\nexport class CourseUnitFields {\n @FieldResolver(type => Int, { nullable: true, description: 'The fewest seconds a PDF page is looked at to count as read - the screen and the server read the same.' })\n secondsPerPage(@Root() unit: CourseUnit): number | null {\n return unit.kind === 'PDF' ? secondsPerPage(unit) : null\n }\n\n @FieldResolver(type => Attachment, { nullable: true, description: \"A video's or a PDF's file.\" })\n async file(@Root() unit: CourseUnit, @Ctx() context: ResolverContext): Promise<Attachment | null> {\n const version = await learningManagerOf(context).getRepository(CourseVersion).findOne({ where: { id: unit.versionId } as any, withDeleted: true })\n if (!(await mayReadVersion(context, version))) return null\n return (await unitFilesOf(context.state.domain, [unit.id])).get(unit.id) ?? null\n }\n}\n\n@Resolver(CourseQuestion)\nexport class CourseQuestionFields {\n @FieldResolver(type => [CourseChoiceKey], { description: 'Its choices with which are right - for a manager only.' })\n async choices(@Root() question: CourseQuestion, @Ctx() context: ResolverContext): Promise<CourseChoiceKey[]> {\n if (!(await requestHolds(context, 'course', 'query'))) return []\n return question.choices ?? []\n }\n}\n"]}
|
|
@@ -6,6 +6,6 @@ export declare class EnrollmentMutation {
|
|
|
6
6
|
startQuizAttempt(enrollmentId: string, context: ResolverContext): Promise<QuizAttemptView>;
|
|
7
7
|
submitQuizAttempt(attemptId: string, answers: Record<string, string[]>, context: ResolverContext): Promise<QuizResultView>;
|
|
8
8
|
assignCourse(courseId: string, audiences: LearningAudienceInput[], dueOn: string, context: ResolverContext): Promise<Enrollment[]>;
|
|
9
|
-
|
|
9
|
+
cancelEnrollments(ids: string[], reason: string, context: ResolverContext): Promise<Enrollment[]>;
|
|
10
10
|
remindEnrollments(ids: string[], context: ResolverContext): Promise<number>;
|
|
11
11
|
}
|
|
@@ -30,8 +30,8 @@ let EnrollmentMutation = class EnrollmentMutation {
|
|
|
30
30
|
async assignCourse(courseId, audiences, dueOn, context) {
|
|
31
31
|
return await (0, enrollment_service_1.enroll)({ kind: enrollment_service_1.DIRECT_SOURCE_KIND, id: '' }, await (0, enrollment_service_1.learnersOf)(audiences, context), courseId, dueOn, context);
|
|
32
32
|
}
|
|
33
|
-
async
|
|
34
|
-
return await (0, enrollment_service_1.
|
|
33
|
+
async cancelEnrollments(ids, reason, context) {
|
|
34
|
+
return await (0, enrollment_service_1.cancelEnrollments)(ids, reason, context);
|
|
35
35
|
}
|
|
36
36
|
async remindEnrollments(ids, context) {
|
|
37
37
|
return await (0, enrollment_remind_1.remindEnrollments)(ids, context);
|
|
@@ -99,14 +99,14 @@ tslib_1.__decorate([
|
|
|
99
99
|
tslib_1.__decorate([
|
|
100
100
|
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
101
101
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
102
|
-
(0, type_graphql_1.Mutation)(returns => enrollment_1.Enrollment, { description: 'To cancel
|
|
103
|
-
tslib_1.__param(0, (0, type_graphql_1.Arg)('
|
|
102
|
+
(0, type_graphql_1.Mutation)(returns => [enrollment_1.Enrollment], { description: 'To cancel enrolments with one reason, together - one refused, none is cancelled. A completed one stays on record as cancelled, and whoever asked for it is told.' }),
|
|
103
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('ids', type => [String])),
|
|
104
104
|
tslib_1.__param(1, (0, type_graphql_1.Arg)('reason')),
|
|
105
105
|
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
106
106
|
tslib_1.__metadata("design:type", Function),
|
|
107
|
-
tslib_1.__metadata("design:paramtypes", [
|
|
107
|
+
tslib_1.__metadata("design:paramtypes", [Array, String, Object]),
|
|
108
108
|
tslib_1.__metadata("design:returntype", Promise)
|
|
109
|
-
], EnrollmentMutation.prototype, "
|
|
109
|
+
], EnrollmentMutation.prototype, "cancelEnrollments", null);
|
|
110
110
|
tslib_1.__decorate([
|
|
111
111
|
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
112
112
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrollment-mutation.js","sourceRoot":"","sources":["../../../server/service/enrollment/enrollment-mutation.ts"],"names":[],"mappings":";;;;AAAA,+CAA0F;AAE1F,iDAAmE;AAEnE,6CAAyC;AACzC,
|
|
1
|
+
{"version":3,"file":"enrollment-mutation.js","sourceRoot":"","sources":["../../../server/service/enrollment/enrollment-mutation.ts"],"names":[],"mappings":";;;;AAAA,+CAA0F;AAE1F,iDAAmE;AAEnE,6CAAyC;AACzC,6DAAwK;AACxK,2DAAuD;AACvD,uDAA8G;AAG9G;;;;GAIG;AAGI,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAMvB,AAAN,KAAK,CAAC,kBAAkB,CACD,YAAoB,EAC1B,MAAc,EAC8H,OAAe,EACjE,QAAgB,EAClH,OAAwB;QAE/B,OAAO,MAAM,IAAA,+BAAU,EAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC3E,CAAC;IAKK,AAAN,KAAK,CAAC,qBAAqB,CAAY,EAAU,EAAS,OAAwB;QAChF,OAAO,MAAM,IAAA,0CAAqB,EAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IACjD,CAAC;IAKK,AAAN,KAAK,CAAC,gBAAgB,CAAsB,YAAoB,EAAS,OAAwB;QAC/F,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,IAAA,qCAAgB,EAAC,YAAY,EAAE,OAAO,CAAC,CAAA;QAC5E,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,CAAA;IAC7C,CAAC;IAKK,AAAN,KAAK,CAAC,iBAAiB,CACH,SAAiB,EAC8D,OAAiC,EAC3H,OAAwB;QAE/B,OAAO,MAAM,IAAA,sCAAiB,EAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IAC7D,CAAC;IAKK,AAAN,KAAK,CAAC,YAAY,CACC,QAAgB,EACkB,SAAkC,EACvB,KAAa,EACpE,OAAwB;QAE/B,OAAO,MAAM,IAAA,2BAAM,EAAC,EAAE,IAAI,EAAE,uCAAkB,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,IAAA,+BAAU,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;IAC3H,CAAC;IAKK,AAAN,KAAK,CAAC,iBAAiB,CAA+B,GAAa,EAAiB,MAAc,EAAS,OAAwB;QACjI,OAAO,MAAM,IAAA,sCAAiB,EAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;IACtD,CAAC;IAKK,AAAN,KAAK,CAAC,iBAAiB,CAA+B,GAAa,EAAS,OAAwB;QAClG,OAAO,MAAM,IAAA,qCAAiB,EAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAC9C,CAAC;CACF,CAAA;AAnEY,gDAAkB;AAMvB;IALL,IAAA,wBAAS,EAAC,mFAAmF,CAAC;IAC9F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,oCAAkB,EAAE;QACvC,WAAW,EAAE,oKAAoK;KAClL,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,cAAc,CAAC,CAAA;IACnB,mBAAA,IAAA,kBAAG,EAAC,QAAQ,CAAC,CAAA;IACb,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,WAAW,EAAE,2GAA2G,EAAE,CAAC,CAAA;IACzJ,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,WAAW,EAAE,wDAAwD,EAAE,CAAC,CAAA;IACvG,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;4DAGP;AAKK;IAHL,IAAA,wBAAS,EAAC,mFAAmF,CAAC;IAC9F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,EAAE,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC;IAChE,mBAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IAAc,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;+DAExD;AAKK;IAHL,IAAA,wBAAS,EAAC,mFAAmF,CAAC;IAC9F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,iCAAe,EAAE,EAAE,WAAW,EAAE,4FAA4F,EAAE,CAAC;IAC5H,mBAAA,IAAA,kBAAG,EAAC,cAAc,CAAC,CAAA;IAAwB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;0DAGvE;AAKK;IAHL,IAAA,wBAAS,EAAC,mFAAmF,CAAC;IAC9F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,gCAAc,EAAE,EAAE,WAAW,EAAE,0HAA0H,EAAE,CAAC;IAE9K,mBAAA,IAAA,kBAAG,EAAC,WAAW,CAAC,CAAA;IAChB,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,oBAAY,EAAE,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC,CAAA;IAC/F,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAGP;AAKK;IAHL,IAAA,wBAAS,EAAC,iFAAiF,CAAC;IAC5F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,EAAE,EAAE,WAAW,EAAE,4GAA4G,EAAE,CAAC;IAE9J,mBAAA,IAAA,kBAAG,EAAC,UAAU,CAAC,CAAA;IACf,mBAAA,IAAA,kBAAG,EAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,uCAAqB,CAAC,CAAC,CAAA;IACjD,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,CAAA;IAC5D,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;sDAGP;AAKK;IAHL,IAAA,wBAAS,EAAC,iFAAiF,CAAC;IAC5F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,EAAE,EAAE,WAAW,EAAE,kKAAkK,EAAE,CAAC;IAC9L,mBAAA,IAAA,kBAAG,EAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAAiB,mBAAA,IAAA,kBAAG,EAAC,QAAQ,CAAC,CAAA;IAAkB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAEzG;AAKK;IAHL,IAAA,wBAAS,EAAC,iFAAiF,CAAC;IAC5F,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,WAAW,EAAE,6EAA6E,EAAE,CAAC;IAChG,mBAAA,IAAA,kBAAG,EAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAAiB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAE1E;6BAlEU,kBAAkB;IAF9B,IAAA,uBAAQ,EAAC,uBAAU,CAAC;IACpB,IAAA,4BAAa,EAAC,qBAAa,CAAC;GAChB,kBAAkB,CAmE9B","sourcesContent":["import { Arg, Ctx, Directive, Int, Mutation, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { ScalarObject, SpeakRefusals } from '@things-factory/shell'\n\nimport { Enrollment } from './enrollment'\nimport { acknowledgeEnrollment, cancelEnrollments, DIRECT_SOURCE_KIND, enroll, learnersOf, recordTick, startQuizAttempt, submitQuizAttempt } from './enrollment-service'\nimport { remindEnrollments } from './enrollment-remind'\nimport { LearningAudienceInput, LearningTickResult, QuizAttemptView, QuizResultView } from './enrollment-type'\n\n\n/*\n * The writes of enrolments (ADR-0194 decisions 4-8): a learner's ticks, acknowledgement and quiz (`learning` mutation,\n * the task `learning.taking`, on their own enrolments only); a manager's assigning, cancelling and reminding (`course`\n * mutation, `learning.managing`).\n */\n@Resolver(Enrollment)\n@UseMiddleware(SpeakRefusals)\nexport class EnrollmentMutation {\n @Directive('@privilege(category: \"learning\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => LearningTickResult, {\n description: 'To record a tick of a unit looked at - the server counts the time since the last tick (15 seconds at most) and refuses a video position ahead of what was watched.'\n })\n async recordLearningTick(\n @Arg('enrollmentId') enrollmentId: string,\n @Arg('unitId') unitId: string,\n @Arg('seconds', type => Int, { description: 'Seconds looked at since the last tick, as the screen says - it may lower what is counted, never raise it.' }) seconds: number,\n @Arg('position', type => Int, { description: 'Where the video stands, in seconds - 0 for a document.' }) position: number,\n @Ctx() context: ResolverContext\n ): Promise<LearningTickResult> {\n return await recordTick(enrollmentId, unitId, seconds, position, context)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Enrollment, { description: \"To confirm the course's acknowledgement.\" })\n async acknowledgeEnrollment(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Enrollment> {\n return await acknowledgeEnrollment(id, context)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => QuizAttemptView, { description: 'To start a quiz attempt - the questions and choices drawn and shuffled, never the answers.' })\n async startQuizAttempt(@Arg('enrollmentId') enrollmentId: string, @Ctx() context: ResolverContext): Promise<QuizAttemptView> {\n const { attempt, questions } = await startQuizAttempt(enrollmentId, context)\n return { attemptId: attempt.id, questions }\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => QuizResultView, { description: \"To send an attempt's answers - scored on the server; the score and whether it passed come back, never the right answers.\" })\n async submitQuizAttempt(\n @Arg('attemptId') attemptId: string,\n @Arg('answers', type => ScalarObject, { description: 'The choice ids picked, by question id.' }) answers: Record<string, string[]>,\n @Ctx() context: ResolverContext\n ): Promise<QuizResultView> {\n return await submitQuizAttempt(attemptId, answers, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [Enrollment], { description: 'To assign a course to an audience - the people it names now - to be completed by a day; each gets a to-do.' })\n async assignCourse(\n @Arg('courseId') courseId: string,\n @Arg('audiences', type => [LearningAudienceInput]) audiences: LearningAudienceInput[],\n @Arg('dueOn', { nullable: true, description: 'YYYY-MM-DD.' }) dueOn: string,\n @Ctx() context: ResolverContext\n ): Promise<Enrollment[]> {\n return await enroll({ kind: DIRECT_SOURCE_KIND, id: '' }, await learnersOf(audiences, context), courseId, dueOn, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [Enrollment], { description: 'To cancel enrolments with one reason, together - one refused, none is cancelled. A completed one stays on record as cancelled, and whoever asked for it is told.' })\n async cancelEnrollments(@Arg('ids', type => [String]) ids: string[], @Arg('reason') reason: string, @Ctx() context: ResolverContext): Promise<Enrollment[]> {\n return await cancelEnrollments(ids, reason, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Int, { description: 'To remind the learners of open enrolments - answers how many were reminded.' })\n async remindEnrollments(@Arg('ids', type => [String]) ids: string[], @Ctx() context: ResolverContext): Promise<number> {\n return await remindEnrollments(ids, context)\n }\n}\n"]}
|
|
@@ -3,7 +3,7 @@ import { ListParam, ListValueCount } from '@things-factory/shell';
|
|
|
3
3
|
import { Course } from '../course/course';
|
|
4
4
|
import { CourseVersion } from '../course/course-version';
|
|
5
5
|
import { Enrollment } from './enrollment';
|
|
6
|
-
import { EnrollmentStatusList, EnrollmentStatusRow, LearningContent, LearningEnrollmentList, LearningUnit } from './enrollment-type';
|
|
6
|
+
import { CourseEnrollmentCounts, EnrollmentStatusList, EnrollmentStatusRow, LearningContent, LearningEnrollmentList, LearningUnit } from './enrollment-type';
|
|
7
7
|
export declare class EnrollmentQuery {
|
|
8
8
|
myEnrollments(context: ResolverContext): Promise<Enrollment[]>;
|
|
9
9
|
myEnrollment(id: string, context: ResolverContext): Promise<Enrollment>;
|
|
@@ -22,3 +22,6 @@ export declare class EnrollmentQuery {
|
|
|
22
22
|
attemptsLeft(enrollment: Enrollment, context: ResolverContext): Promise<number | null>;
|
|
23
23
|
quizSize(enrollment: Enrollment, context: ResolverContext): Promise<number>;
|
|
24
24
|
}
|
|
25
|
+
export declare class CourseEnrollmentFields {
|
|
26
|
+
enrollmentCounts(course: Course, context: ResolverContext): Promise<CourseEnrollmentCounts | null>;
|
|
27
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EnrollmentQuery = void 0;
|
|
3
|
+
exports.CourseEnrollmentFields = exports.EnrollmentQuery = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
6
|
const auth_base_1 = require("@things-factory/auth-base");
|
|
@@ -233,4 +233,24 @@ exports.EnrollmentQuery = EnrollmentQuery = tslib_1.__decorate([
|
|
|
233
233
|
(0, type_graphql_1.Resolver)(enrollment_1.Enrollment),
|
|
234
234
|
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
|
|
235
235
|
], EnrollmentQuery);
|
|
236
|
+
/* How a course's enrolments stand, on the course - for a manager (`course` query); nothing for anyone else. */
|
|
237
|
+
let CourseEnrollmentFields = class CourseEnrollmentFields {
|
|
238
|
+
async enrollmentCounts(course, context) {
|
|
239
|
+
if (!(await (0, auth_base_1.requestHolds)(context, 'course', 'query')))
|
|
240
|
+
return null;
|
|
241
|
+
return (await (0, enrollment_status_1.courseEnrollmentCounts)(context)).get(course.id) ?? { total: 0, assigned: 0, inProgress: 0, completed: 0, overdue: 0 };
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
exports.CourseEnrollmentFields = CourseEnrollmentFields;
|
|
245
|
+
tslib_1.__decorate([
|
|
246
|
+
(0, type_graphql_1.FieldResolver)(type => enrollment_type_1.CourseEnrollmentCounts, { nullable: true, description: "Where its enrolments stand - cancelled ones left out. For a manager; empty for anyone else." }),
|
|
247
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
248
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
249
|
+
tslib_1.__metadata("design:type", Function),
|
|
250
|
+
tslib_1.__metadata("design:paramtypes", [course_1.Course, Object]),
|
|
251
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
252
|
+
], CourseEnrollmentFields.prototype, "enrollmentCounts", null);
|
|
253
|
+
exports.CourseEnrollmentFields = CourseEnrollmentFields = tslib_1.__decorate([
|
|
254
|
+
(0, type_graphql_1.Resolver)(course_1.Course)
|
|
255
|
+
], CourseEnrollmentFields);
|
|
236
256
|
//# sourceMappingURL=enrollment-query.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrollment-query.js","sourceRoot":"","sources":["../../../server/service/enrollment/enrollment-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAkH;AAElH,yDAA8D;AAC9D,iDAA+F;AAE/F,6CAAyC;AACzC,+DAA0D;AAC1D,6DAAwD;AACxD,6DAAqE;AACrE,6CAAyC;AACzC,6DAAuH;AACvH,2DAAuH;AACvH,uDAAoI;AACpI,+CAAkE;AAClE,qDAAkD;AAGlD,MAAM,MAAM,GAAG,CAAC,GAAc,EAAuB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,GAAG,GAAG,EAAE,CAAC,CAAA;AAE3F,MAAM,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAwC,EAAwB,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAEpI,kFAAkF;AAClF,KAAK,UAAU,WAAW,CAAC,UAAsB,EAAE,OAAY;IAC7D,OAAO,UAAU,CAAC,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,IAAA,wBAAY,EAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;AACxG,CAAC;AAED;;;GAGG;AAGI,IAAM,eAAe,GAArB,MAAM,eAAe;IAGpB,AAAN,KAAK,CAAC,aAAa,CAAQ,OAAwB;QACjD,OAAO,MAAM,IAAA,kCAAa,EAAC,OAAO,CAAC,CAAA;IACrC,CAAC;IAIK,AAAN,KAAK,CAAC,YAAY,CAAY,EAAU,EAAS,OAAwB;QACvE,OAAO,MAAM,IAAA,mCAAc,EAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IAC1C,CAAC;IAIK,AAAN,KAAK,CAAC,oBAAoB,CAA0B,MAAiB,EAAS,OAAwB;QACpG,OAAO,MAAM,CAAC,MAAM,IAAA,kCAAc,EAAC,MAAM,EAAE,MAAM,IAAA,+BAAW,EAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAA;IAClF,CAAC;IAIK,AAAN,KAAK,CAAC,gBAAgB,CAA0B,MAAiB,EAAS,OAAwB;QAChG,OAAO,MAAM,CAAC,MAAM,IAAA,kCAAc,EAAC,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC,CAAA;IACvE,CAAC;IAIK,AAAN,KAAK,CAAC,qBAAqB,CAA0B,MAAiB,EAAS,OAAwB;QACrG,MAAM,KAAK,GAAG,CAAC,MAAM,IAAA,wBAAY,EAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAE,EAAE,IAAI,EAAE,KAAK,EAAY,CAAC,CAAC,CAAC,MAAM,IAAA,+BAAW,EAAC,OAAO,CAAC,CAAA;QACxH,OAAO,MAAM,IAAA,yCAAqB,EAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;IAC5D,CAAC;IAIK,AAAN,KAAK,CAAC,kBAAkB,CAAkB,QAAgB,EAAS,OAAwB;QACzF,OAAO,CAAC,MAAM,IAAA,sCAAkB,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAClE,CAAC;IAIK,AAAN,KAAK,CAAC,mBAAmB,CAA0B,MAAiB,EAAS,OAAwB;QACnG,OAAO,MAAM,IAAA,iCAAmB,EAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACnD,CAAC;IAIK,AAAN,KAAK,CAAC,eAAe,CAA0C,YAAoB,EAAwC,SAAiB,EAAS,OAAwB;QAC3K,OAAO,MAAM,IAAA,2BAAa,EAAC,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,CAAA;IAClE,CAAC;IAED,6EAA6E;IAGvE,AAAN,KAAK,CAAC,MAAM,CAAS,UAAsB;QACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,eAAM,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACxG,CAAC;IAGK,AAAN,KAAK,CAAC,IAAI,CAAS,UAAsB;QACvC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAClG,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAS,UAAsB,EAAS,OAAwB;QAC3E,OAAO,MAAM,IAAA,mCAAc,EAAC,IAAA,kCAAiB,EAAC,OAAO,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IAC3F,CAAC;IAGD,KAAK,CAAS,UAAsB,EAAS,OAAwB;QACnE,OAAO,IAAA,wBAAO,EAAC,UAAU,EAAE,IAAA,4BAAO,EAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAA;IAC3F,CAAC;IAGK,AAAN,KAAK,CAAC,KAAK,CAAS,UAAsB,EAAS,OAAwB;QACzE,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAAE,OAAO,EAAE,CAAA;QACxD,MAAM,EAAE,GAAG,IAAA,kCAAiB,EAAC,OAAO,CAAC,CAAA;QACrC,MAAM,OAAO,GAAG,MAAM,IAAA,mCAAc,EAAC,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;QAC1E,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAA;QACvB,MAAM,QAAQ,GAAG,MAAM,IAAA,iCAAY,EAAC,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC,CAAA;QACtD,OAAO,CAAC,MAAM,IAAA,wBAAO,EAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,MAAM,EAAE,IAAA,uBAAM,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IACtJ,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAS,UAAsB,EAAS,OAAwB;QAC3E,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAAE,OAAO,EAAE,CAAA;QACxD,OAAO,MAAM,IAAA,+BAAU,EAAC,IAAA,kCAAiB,EAAC,OAAO,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACvF,CAAC;IAGK,AAAN,KAAK,CAAC,YAAY,CAAS,UAAsB,EAAS,OAAwB;QAChF,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAAE,OAAO,IAAI,CAAA;QAC1D,MAAM,OAAO,GAAG,MAAM,IAAA,mCAAc,EAAC,IAAA,kCAAiB,EAAC,OAAO,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;QAClG,OAAO,OAAO,EAAE,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,GAAG,CAAC,UAAU,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC9G,CAAC;IAGK,AAAN,KAAK,CAAC,QAAQ,CAAS,UAAsB,EAAS,OAAwB;QAC5E,MAAM,EAAE,GAAG,IAAA,kCAAiB,EAAC,OAAO,CAAC,CAAA;QACrC,MAAM,OAAO,GAAG,MAAM,IAAA,mCAAc,EAAC,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;QAC1E,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,SAAS,IAAI,IAAI;YAAE,OAAO,CAAC,CAAA;QACnD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,aAAa,CAAC,gCAAc,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAS,EAAE,CAAC,CAAA;QAC3G,OAAO,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;IAC3E,CAAC;CACF,CAAA;AAvGY,0CAAe;AAGpB;IAFL,IAAA,wBAAS,EAAC,gFAAgF,CAAC;IAC3F,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,EAAE,EAAE,WAAW,EAAE,4FAA4F,EAAE,CAAC;IACzH,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;oDAEzB;AAIK;IAFL,IAAA,wBAAS,EAAC,gFAAgF,CAAC;IAC3F,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,EAAE,EAAE,WAAW,EAAE,sCAAsC,EAAE,CAAC;IAClE,mBAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IAAc,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;mDAE/C;AAIK;IAFL,IAAA,wBAAS,EAAC,gFAAgF,CAAC;IAC3F,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,sCAAoB,EAAE,EAAE,WAAW,EAAE,8LAA8L,EAAE,CAAC;IAC5N,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IAAqB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAjB,iBAAS;;2DAEpE;AAIK;IAFL,IAAA,wBAAS,EAAC,8EAA8E,CAAC;IACzF,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,sCAAoB,EAAE,EAAE,WAAW,EAAE,4IAA4I,EAAE,CAAC;IAC9K,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IAAqB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAjB,iBAAS;;uDAEhE;AAIK;IAFL,IAAA,wBAAS,EAAC,gFAAgF,CAAC;IAC3F,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,sBAAc,CAAC,EAAE,EAAE,WAAW,EAAE,kOAAkO,EAAE,CAAC;IAC3P,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IAAqB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAjB,iBAAS;;4DAGrE;AAIK;IAFL,IAAA,wBAAS,EAAC,8EAA8E,CAAC;IACzF,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,qCAAmB,CAAC,EAAE,EAAE,WAAW,EAAE,oEAAoE,EAAE,CAAC;IACrG,mBAAA,IAAA,kBAAG,EAAC,UAAU,CAAC,CAAA;IAAoB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;yDAEjE;AAIK;IAFL,IAAA,wBAAS,EAAC,gFAAgF,CAAC;IAC3F,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,wCAAsB,EAAE,EAAE,WAAW,EAAE,4KAA4K,EAAE,CAAC;IAC7M,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IAAqB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAjB,iBAAS;;0DAEnE;AAIK;IAFL,IAAA,wBAAS,EAAC,gFAAgF,CAAC;IAC3F,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,iCAAe,EAAE,EAAE,WAAW,EAAE,wKAAwK,EAAE,CAAC;IACtM,mBAAA,IAAA,kBAAG,EAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAAwB,mBAAA,IAAA,kBAAG,EAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAAqB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;sDAEnJ;AAKK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,eAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;IAChE,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAa,uBAAU;;6CAE1C;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;IAClE,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAa,uBAAU;;2CAExC;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,8BAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wEAAwE,EAAE,CAAC;IACjI,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA0B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAlB,uBAAU;;8CAE3C;AAGD;IADC,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,mEAAmE,EAAE,CAAC;IAC7G,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA0B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAlB,uBAAU;;4CAEnC;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,8BAAY,CAAC,EAAE,EAAE,WAAW,EAAE,yEAAyE,EAAE,CAAC;IACrH,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA0B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAlB,uBAAU;;4CAOzC;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,2EAA2E,EAAE,CAAC;IAC/G,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA0B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAlB,uBAAU;;8CAG3C;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,4DAA4D,EAAE,CAAC;IACtG,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA0B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAlB,uBAAU;;mDAIhD;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,WAAW,EAAE,yDAAyD,EAAE,CAAC;IACvF,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA0B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAlB,uBAAU;;+CAM5C;0BAtGU,eAAe;IAF3B,IAAA,uBAAQ,EAAC,uBAAU,CAAC;IACpB,IAAA,4BAAa,EAAC,qBAAa,CAAC;GAChB,eAAe,CAuG3B","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Int, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\n\nimport { requestHolds, User } from '@things-factory/auth-base'\nimport { getRepository, ListParam, ListValueCount, SpeakRefusals } from '@things-factory/shell'\n\nimport { Course } from '../course/course'\nimport { CourseQuestion } from '../course/course-question'\nimport { CourseVersion } from '../course/course-version'\nimport { learningManagerOf, unitsOf } from '../course/course-service'\nimport { Enrollment } from './enrollment'\nimport { missingFor, myEnrollmentOf, myEnrollments, progressesOf, shownVersionOf, todayIn } from './enrollment-service'\nimport { completionRegister, enrollmentPage, enrollmentStateCounts, StatusRow, teamReachOf } from './enrollment-status'\nimport { EnrollmentStatusList, EnrollmentStatusRow, LearningContent, LearningEnrollmentList, LearningUnit } from './enrollment-type'\nimport { courseContent, readableEnrollments } from './learning-ai'\nimport { counts, overdue } from './progress-rules'\n\n\nconst rowOut = (row: StatusRow): EnrollmentStatusRow => ({ id: row.enrollment.id, ...row })\n\nconst pageOf = ({ rows, total }: { rows: StatusRow[]; total: number }): EnrollmentStatusList => ({ items: rows.map(rowOut), total })\n\n/** Whether the request reads how an enrolment went - its learner or a manager. */\nasync function readsInside(enrollment: Enrollment, context: any): Promise<boolean> {\n return enrollment.userId === context.state.user.id || (await requestHolds(context, 'course', 'query'))\n}\n\n/*\n * The reads of enrolments (ADR-0194 decisions 5-11): one's own (`learning` query, the task `learning.taking`); every\n * enrolment and the completion register for a manager (`course` query); a department head's people, status only.\n */\n@Resolver(Enrollment)\n@UseMiddleware(SpeakRefusals)\nexport class EnrollmentQuery {\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [Enrollment], { description: \"The request's own enrolments - open ones first, the soonest due first, then the completed.\" })\n async myEnrollments(@Ctx() context: ResolverContext): Promise<Enrollment[]> {\n return await myEnrollments(context)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Enrollment, { description: \"One of the request's own enrolments.\" })\n async myEnrollment(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Enrollment> {\n return await myEnrollmentOf(context, id)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EnrollmentStatusList, { description: \"Where the people of the request's departments stand - for a department head, status and days only. Filters: course, state, sourceKind, sourceId; search: the learner's name or the course's.\" })\n async teamEnrollmentStatus(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EnrollmentStatusList> {\n return pageOf(await enrollmentPage(params, await teamReachOf(context), context))\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EnrollmentStatusList, { description: \"Every enrolment, with its progress and evidence. Filters: course, state, sourceKind, sourceId; search: the learner's name or the course's.\" })\n async enrollmentStatus(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EnrollmentStatusList> {\n return pageOf(await enrollmentPage(params, { kind: 'all' }, context))\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [ListValueCount], { description: \"How many enrolments stand in each state under the list's other conditions, every state in order - of everyone for a manager, else of a department head's people (refused to anyone heading none), as the status list reads them.\" })\n async enrollmentStateCounts(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ListValueCount[]> {\n const reach = (await requestHolds(context, 'course', 'query')) ? ({ kind: 'all' } as const) : await teamReachOf(context)\n return await enrollmentStateCounts(params, reach, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [EnrollmentStatusRow], { description: 'The completion register of a course - every completion by its day.' })\n async completionRegister(@Arg('courseId') courseId: string, @Ctx() context: ResolverContext): Promise<EnrollmentStatusRow[]> {\n return (await completionRegister(courseId, context)).map(rowOut)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => LearningEnrollmentList, { description: 'The enrolments the request may read - a manager every one, a department head their people (status only), anyone else their own - for the assistant (ADR-0194 decision 12).' })\n async learningEnrollments(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<LearningEnrollmentList> {\n return await readableEnrollments(params, context)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => LearningContent, { description: \"The units of one course version for the assistant - a learner's own enrolment's (not while a quiz attempt is open), or a version for a manager (ADR-0194 decision 12).\" })\n async learningContent(@Arg('enrollmentId', { nullable: true }) enrollmentId: string, @Arg('versionId', { nullable: true }) versionId: string, @Ctx() context: ResolverContext): Promise<LearningContent> {\n return await courseContent({ enrollmentId, versionId }, context)\n }\n\n /* ---------------------------------------------------------------- fields */\n\n @FieldResolver(type => Course, { nullable: true, description: 'The course.' })\n async course(@Root() enrollment: Enrollment): Promise<Course | null> {\n return enrollment.courseId ? await getRepository(Course).findOneBy({ id: enrollment.courseId }) : null\n }\n\n @FieldResolver(type => User, { nullable: true, description: 'Who takes it.' })\n async user(@Root() enrollment: Enrollment): Promise<User | null> {\n return enrollment.userId ? await getRepository(User).findOneBy({ id: enrollment.userId }) : null\n }\n\n @FieldResolver(type => CourseVersion, { nullable: true, description: 'The version it shows - its own once started, the published one before.' })\n async version(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<CourseVersion | null> {\n return await shownVersionOf(learningManagerOf(context), context.state.domain, enrollment)\n }\n\n @FieldResolver(type => String, { description: 'Where it stands today - OVERDUE for an open one past its due day.' })\n state(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): string {\n return overdue(enrollment, todayIn(context.state.domain)) ? 'OVERDUE' : enrollment.status\n }\n\n @FieldResolver(type => [LearningUnit], { description: 'Its units with how far the learner went - for its learner and managers.' })\n async units(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<LearningUnit[]> {\n if (!(await readsInside(enrollment, context))) return []\n const tx = learningManagerOf(context)\n const version = await shownVersionOf(tx, context.state.domain, enrollment)\n if (!version) return []\n const progress = await progressesOf(tx, enrollment.id)\n return (await unitsOf(tx, version.id)).map(unit => ({ unit, progress: progress.find(one => one.unitId === unit.id) ?? null, counts: counts(unit) }))\n }\n\n @FieldResolver(type => [String], { description: 'What still stands before completion - units, time, quiz, acknowledgement.' })\n async missing(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<string[]> {\n if (!(await readsInside(enrollment, context))) return []\n return await missingFor(learningManagerOf(context), context.state.domain, enrollment)\n }\n\n @FieldResolver(type => Int, { nullable: true, description: 'The quiz attempts left - no limit, or no quiz, when empty.' })\n async attemptsLeft(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<number | null> {\n if (!(await readsInside(enrollment, context))) return null\n const version = await shownVersionOf(learningManagerOf(context), context.state.domain, enrollment)\n return version?.attemptLimit != null ? Math.max(0, version.attemptLimit - (enrollment.attempts ?? 0)) : null\n }\n\n @FieldResolver(type => Int, { description: 'How many questions its quiz draws - 0 when it has none.' })\n async quizSize(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<number> {\n const tx = learningManagerOf(context)\n const version = await shownVersionOf(tx, context.state.domain, enrollment)\n if (!version || version.passScore == null) return 0\n const all = await tx.getRepository(CourseQuestion).count({ where: { version: { id: version.id } } as any })\n return version.questionCount ? Math.min(version.questionCount, all) : all\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"enrollment-query.js","sourceRoot":"","sources":["../../../server/service/enrollment/enrollment-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Int, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\n\nimport { requestHolds, User } from '@things-factory/auth-base'\nimport { getRepository, ListParam, ListValueCount, SpeakRefusals } from '@things-factory/shell'\n\nimport { Course } from '../course/course'\nimport { CourseQuestion } from '../course/course-question'\nimport { CourseVersion } from '../course/course-version'\nimport { learningManagerOf, unitsOf } from '../course/course-service'\nimport { Enrollment } from './enrollment'\nimport { missingFor, myEnrollmentOf, myEnrollments, progressesOf, shownVersionOf, todayIn } from './enrollment-service'\nimport { completionRegister, courseEnrollmentCounts, enrollmentPage, enrollmentStateCounts, StatusRow, teamReachOf } from './enrollment-status'\nimport { CourseEnrollmentCounts, EnrollmentStatusList, EnrollmentStatusRow, LearningContent, LearningEnrollmentList, LearningUnit } from './enrollment-type'\nimport { courseContent, readableEnrollments } from './learning-ai'\nimport { counts, overdue } from './progress-rules'\n\n\nconst rowOut = (row: StatusRow): EnrollmentStatusRow => ({ id: row.enrollment.id, ...row })\n\nconst pageOf = ({ rows, total }: { rows: StatusRow[]; total: number }): EnrollmentStatusList => ({ items: rows.map(rowOut), total })\n\n/** Whether the request reads how an enrolment went - its learner or a manager. */\nasync function readsInside(enrollment: Enrollment, context: any): Promise<boolean> {\n return enrollment.userId === context.state.user.id || (await requestHolds(context, 'course', 'query'))\n}\n\n/*\n * The reads of enrolments (ADR-0194 decisions 5-11): one's own (`learning` query, the task `learning.taking`); every\n * enrolment and the completion register for a manager (`course` query); a department head's people, status only.\n */\n@Resolver(Enrollment)\n@UseMiddleware(SpeakRefusals)\nexport class EnrollmentQuery {\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [Enrollment], { description: \"The request's own enrolments - open ones first, the soonest due first, then the completed.\" })\n async myEnrollments(@Ctx() context: ResolverContext): Promise<Enrollment[]> {\n return await myEnrollments(context)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Enrollment, { description: \"One of the request's own enrolments.\" })\n async myEnrollment(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Enrollment> {\n return await myEnrollmentOf(context, id)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EnrollmentStatusList, { description: \"Where the people of the request's departments stand - for a department head, status and days only. Filters: course, state, sourceKind, sourceId; search: the learner's name or the course's.\" })\n async teamEnrollmentStatus(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EnrollmentStatusList> {\n return pageOf(await enrollmentPage(params, await teamReachOf(context), context))\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => EnrollmentStatusList, { description: \"Every enrolment, with its progress and evidence. Filters: course, state, sourceKind, sourceId; search: the learner's name or the course's.\" })\n async enrollmentStatus(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<EnrollmentStatusList> {\n return pageOf(await enrollmentPage(params, { kind: 'all' }, context))\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [ListValueCount], { description: \"How many enrolments stand in each state under the list's other conditions, every state in order - of everyone for a manager, else of a department head's people (refused to anyone heading none), as the status list reads them.\" })\n async enrollmentStateCounts(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ListValueCount[]> {\n const reach = (await requestHolds(context, 'course', 'query')) ? ({ kind: 'all' } as const) : await teamReachOf(context)\n return await enrollmentStateCounts(params, reach, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [EnrollmentStatusRow], { description: 'The completion register of a course - every completion by its day.' })\n async completionRegister(@Arg('courseId') courseId: string, @Ctx() context: ResolverContext): Promise<EnrollmentStatusRow[]> {\n return (await completionRegister(courseId, context)).map(rowOut)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => LearningEnrollmentList, { description: 'The enrolments the request may read - a manager every one, a department head their people (status only), anyone else their own - for the assistant (ADR-0194 decision 12).' })\n async learningEnrollments(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<LearningEnrollmentList> {\n return await readableEnrollments(params, context)\n }\n\n @Directive('@privilege(category: \"learning\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => LearningContent, { description: \"The units of one course version for the assistant - a learner's own enrolment's (not while a quiz attempt is open), or a version for a manager (ADR-0194 decision 12).\" })\n async learningContent(@Arg('enrollmentId', { nullable: true }) enrollmentId: string, @Arg('versionId', { nullable: true }) versionId: string, @Ctx() context: ResolverContext): Promise<LearningContent> {\n return await courseContent({ enrollmentId, versionId }, context)\n }\n\n /* ---------------------------------------------------------------- fields */\n\n @FieldResolver(type => Course, { nullable: true, description: 'The course.' })\n async course(@Root() enrollment: Enrollment): Promise<Course | null> {\n return enrollment.courseId ? await getRepository(Course).findOneBy({ id: enrollment.courseId }) : null\n }\n\n @FieldResolver(type => User, { nullable: true, description: 'Who takes it.' })\n async user(@Root() enrollment: Enrollment): Promise<User | null> {\n return enrollment.userId ? await getRepository(User).findOneBy({ id: enrollment.userId }) : null\n }\n\n @FieldResolver(type => CourseVersion, { nullable: true, description: 'The version it shows - its own once started, the published one before.' })\n async version(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<CourseVersion | null> {\n return await shownVersionOf(learningManagerOf(context), context.state.domain, enrollment)\n }\n\n @FieldResolver(type => String, { description: 'Where it stands today - OVERDUE for an open one past its due day.' })\n state(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): string {\n return overdue(enrollment, todayIn(context.state.domain)) ? 'OVERDUE' : enrollment.status\n }\n\n @FieldResolver(type => [LearningUnit], { description: 'Its units with how far the learner went - for its learner and managers.' })\n async units(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<LearningUnit[]> {\n if (!(await readsInside(enrollment, context))) return []\n const tx = learningManagerOf(context)\n const version = await shownVersionOf(tx, context.state.domain, enrollment)\n if (!version) return []\n const progress = await progressesOf(tx, enrollment.id)\n return (await unitsOf(tx, version.id)).map(unit => ({ unit, progress: progress.find(one => one.unitId === unit.id) ?? null, counts: counts(unit) }))\n }\n\n @FieldResolver(type => [String], { description: 'What still stands before completion - units, time, quiz, acknowledgement.' })\n async missing(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<string[]> {\n if (!(await readsInside(enrollment, context))) return []\n return await missingFor(learningManagerOf(context), context.state.domain, enrollment)\n }\n\n @FieldResolver(type => Int, { nullable: true, description: 'The quiz attempts left - no limit, or no quiz, when empty.' })\n async attemptsLeft(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<number | null> {\n if (!(await readsInside(enrollment, context))) return null\n const version = await shownVersionOf(learningManagerOf(context), context.state.domain, enrollment)\n return version?.attemptLimit != null ? Math.max(0, version.attemptLimit - (enrollment.attempts ?? 0)) : null\n }\n\n @FieldResolver(type => Int, { description: 'How many questions its quiz draws - 0 when it has none.' })\n async quizSize(@Root() enrollment: Enrollment, @Ctx() context: ResolverContext): Promise<number> {\n const tx = learningManagerOf(context)\n const version = await shownVersionOf(tx, context.state.domain, enrollment)\n if (!version || version.passScore == null) return 0\n const all = await tx.getRepository(CourseQuestion).count({ where: { version: { id: version.id } } as any })\n return version.questionCount ? Math.min(version.questionCount, all) : all\n }\n}\n\n/* How a course's enrolments stand, on the course - for a manager (`course` query); nothing for anyone else. */\n@Resolver(Course)\nexport class CourseEnrollmentFields {\n @FieldResolver(type => CourseEnrollmentCounts, { nullable: true, description: \"Where its enrolments stand - cancelled ones left out. For a manager; empty for anyone else.\" })\n async enrollmentCounts(@Root() course: Course, @Ctx() context: ResolverContext): Promise<CourseEnrollmentCounts | null> {\n if (!(await requestHolds(context, 'course', 'query'))) return null\n return (await courseEnrollmentCounts(context)).get(course.id) ?? { total: 0, assigned: 0, inProgress: 0, completed: 0, overdue: 0 }\n }\n}\n"]}
|
|
@@ -29,10 +29,11 @@ export declare function enroll(source: LearningSource, userIds: string[], course
|
|
|
29
29
|
*/
|
|
30
30
|
export declare function withdraw(source: LearningSource, reason: string, context: any): Promise<number>;
|
|
31
31
|
/**
|
|
32
|
-
* A manager cancels
|
|
33
|
-
* cancelled - never deleted - and whoever asked for it is told in the same
|
|
32
|
+
* A manager cancels enrolments with one reason (decision 8) - together: one refused, none is cancelled. An open one is
|
|
33
|
+
* withdrawn; a completed one stays on record as cancelled - never deleted - and whoever asked for it is told in the same
|
|
34
|
+
* transaction.
|
|
34
35
|
*/
|
|
35
|
-
export declare function
|
|
36
|
+
export declare function cancelEnrollments(ids: string[], reason: string, context: any): Promise<Enrollment[]>;
|
|
36
37
|
/**
|
|
37
38
|
* The people an audience names now - the domain, departments with those under them, roles and people, by organization's
|
|
38
39
|
* one rule (ADR-0163). Each target must be of this domain.
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.isOpen = exports.certificateNoOf = exports.todayIn = exports.learningAddressOf = exports.DIRECT_SOURCE_KIND = void 0;
|
|
4
4
|
exports.enroll = enroll;
|
|
5
5
|
exports.withdraw = withdraw;
|
|
6
|
-
exports.
|
|
6
|
+
exports.cancelEnrollments = cancelEnrollments;
|
|
7
7
|
exports.learnersOf = learnersOf;
|
|
8
8
|
exports.enrollmentOf = enrollmentOf;
|
|
9
9
|
exports.myEnrollmentOf = myEnrollmentOf;
|
|
@@ -50,13 +50,18 @@ const notFound = () => new shell_1.Refusal('learning-not-found', {}, 'the record
|
|
|
50
50
|
const isOpen = (status) => enrollment_1.OPEN_ENROLLMENT_STATUSES.includes(status);
|
|
51
51
|
exports.isOpen = isOpen;
|
|
52
52
|
/* ---------------------------------------------------------------- the to-do (decision 5) */
|
|
53
|
-
/** The to-do
|
|
53
|
+
/** The context worklist closes a to-do under - `by` ends or aborts it; worklist speaks its refusals through `t`. */
|
|
54
54
|
function todoContextOf(tx, domain, user) {
|
|
55
55
|
const t = (0, translator_1.translatorFor)(user.locale || 'ko');
|
|
56
56
|
return { state: { domain, user, tx }, t: (key, options) => t(key, options) };
|
|
57
57
|
}
|
|
58
|
-
/**
|
|
59
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Hands out 「<과정> 수강」 to the person, with the due day - nothing where the domain has not installed the to-do. worklist's
|
|
60
|
+
* handOut: the person's 할 일 and nobody's 상신함, also when the manager assigning it is the person (2026-11-08). The one
|
|
61
|
+
* who asked (`context`) stands as its issuer.
|
|
62
|
+
*/
|
|
63
|
+
async function issueTodo(context, enrollment, course, person) {
|
|
64
|
+
const { domain, tx } = context.state;
|
|
60
65
|
const activity = await tx.getRepository(worklist_1.Activity).findOne({ where: { domain: { id: domain.id }, name: activities_1.LEARNING_COURSE_ACTIVITY } });
|
|
61
66
|
if (!activity) {
|
|
62
67
|
env_1.logger.warn(`[learning] ${domain.subdomain}: the activity "${activities_1.LEARNING_COURSE_ACTIVITY}" is not installed - "${course.name}" not handed out`);
|
|
@@ -66,10 +71,8 @@ async function issueTodo(tx, domain, enrollment, course, person) {
|
|
|
66
71
|
const name = t('text.learning-todo-name', { course: course.name });
|
|
67
72
|
const headline = enrollment.dueOn ? t('text.learning-todo-headline', { dueOn: enrollment.dueOn }) : t('text.learning-todo-headline-no-due');
|
|
68
73
|
const dueAt = enrollment.dueOn ? dueAtOf(enrollment.dueOn, domain.timezone) : undefined;
|
|
69
|
-
const context = todoContextOf(tx, domain, person);
|
|
70
74
|
const input = { enrollmentId: enrollment.id, headline, address: (0, exports.learningAddressOf)(enrollment.id) };
|
|
71
|
-
const instance = await (0, worklist_1.
|
|
72
|
-
await (0, worklist_1.assign)({ id: instance.id, assignees: [person.email], dueAt, reason: name }, context);
|
|
75
|
+
const instance = await (0, worklist_1.handOut)({ activityId: activity.id, name, description: headline, input, assignee: person, dueAt }, context);
|
|
73
76
|
return instance.id;
|
|
74
77
|
}
|
|
75
78
|
/** The end of the due day in the domain's time zone. */
|
|
@@ -127,7 +130,7 @@ async function enroll(source, userIds, courseId, dueOn, context) {
|
|
|
127
130
|
continue;
|
|
128
131
|
}
|
|
129
132
|
const saved = await repository.save({ domain, user: person, course, dueOn: dueOn || null, sourceKind: source.kind, sourceId, status: enrollment_1.EnrollmentStatus.ASSIGNED, learnedSeconds: 0, attempts: 0, creator: user, updater: user });
|
|
130
|
-
const todo = await issueTodo(
|
|
133
|
+
const todo = await issueTodo(context, saved, course, person);
|
|
131
134
|
if (todo)
|
|
132
135
|
await repository.update(saved.id, { todoInstanceId: todo });
|
|
133
136
|
out.push((await repository.findOneBy({ id: saved.id })));
|
|
@@ -156,23 +159,33 @@ async function cancelOpen(tx, domain, row, by, reason) {
|
|
|
156
159
|
return true;
|
|
157
160
|
}
|
|
158
161
|
/**
|
|
159
|
-
* A manager cancels
|
|
160
|
-
* cancelled - never deleted - and whoever asked for it is told in the same
|
|
162
|
+
* A manager cancels enrolments with one reason (decision 8) - together: one refused, none is cancelled. An open one is
|
|
163
|
+
* withdrawn; a completed one stays on record as cancelled - never deleted - and whoever asked for it is told in the same
|
|
164
|
+
* transaction.
|
|
161
165
|
*/
|
|
162
|
-
async function
|
|
163
|
-
const { domain, user, tx } = context.state;
|
|
166
|
+
async function cancelEnrollments(ids, reason, context) {
|
|
164
167
|
if (!reason?.trim())
|
|
165
168
|
throw new shell_1.Refusal('learning-cancel-reason-required', {}, 'say why it is cancelled');
|
|
169
|
+
const unique = [...new Set(ids ?? [])];
|
|
170
|
+
if (!unique.length)
|
|
171
|
+
throw new shell_1.Refusal('learning-cancel-none', {}, 'pick the enrolments to cancel');
|
|
172
|
+
const out = [];
|
|
173
|
+
for (const id of unique)
|
|
174
|
+
out.push(await cancelOne(id, reason.trim(), context));
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
async function cancelOne(id, reason, context) {
|
|
178
|
+
const { domain, user, tx } = context.state;
|
|
166
179
|
const row = await enrollmentOf(tx, domain, id);
|
|
167
180
|
if (isOpen(row.status)) {
|
|
168
|
-
if (!(await cancelOpen(tx, domain, row, user, reason
|
|
181
|
+
if (!(await cancelOpen(tx, domain, row, user, reason)))
|
|
169
182
|
throw new shell_1.Refusal('learning-enrollment-moved', {}, 'the enrolment changed meanwhile - reload and try again');
|
|
170
183
|
}
|
|
171
184
|
else if (row.status === enrollment_1.EnrollmentStatus.COMPLETED) {
|
|
172
|
-
const claimed = await tx.getRepository(enrollment_1.Enrollment).update({ id: row.id, status: enrollment_1.EnrollmentStatus.COMPLETED }, { status: enrollment_1.EnrollmentStatus.CANCELLED, cancelledAt: new Date(), cancelReason: reason
|
|
185
|
+
const claimed = await tx.getRepository(enrollment_1.Enrollment).update({ id: row.id, status: enrollment_1.EnrollmentStatus.COMPLETED }, { status: enrollment_1.EnrollmentStatus.CANCELLED, cancelledAt: new Date(), cancelReason: reason, updater: user });
|
|
173
186
|
if (!claimed.affected)
|
|
174
187
|
throw new shell_1.Refusal('learning-enrollment-moved', {}, 'the enrolment changed meanwhile - reload and try again');
|
|
175
|
-
await (0, learning_outcome_1.learningOutcomeOf)(row.sourceKind)?.cancelled?.((await enrollmentOf(tx, domain, id)), reason
|
|
188
|
+
await (0, learning_outcome_1.learningOutcomeOf)(row.sourceKind)?.cancelled?.((await enrollmentOf(tx, domain, id)), reason, context);
|
|
176
189
|
}
|
|
177
190
|
else
|
|
178
191
|
throw new shell_1.Refusal('learning-enrollment-cancelled', {}, 'the enrolment is cancelled already');
|