@things-factory/learning 0.0.0-stage → 10.1.261
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/bootstrap.d.ts +2 -0
- package/dist-client/bootstrap.js +4 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/components/learning-assign-form.d.ts +24 -0
- package/dist-client/components/learning-assign-form.js +77 -0
- package/dist-client/components/learning-assign-form.js.map +1 -0
- package/dist-client/components/learning-course-form.d.ts +29 -0
- package/dist-client/components/learning-course-form.js +104 -0
- package/dist-client/components/learning-course-form.js.map +1 -0
- package/dist-client/components/learning-material-form.d.ts +41 -0
- package/dist-client/components/learning-material-form.js +202 -0
- package/dist-client/components/learning-material-form.js.map +1 -0
- package/dist-client/components/learning-question-form.d.ts +33 -0
- package/dist-client/components/learning-question-form.js +142 -0
- package/dist-client/components/learning-question-form.js.map +1 -0
- package/dist-client/components/learning-todo.d.ts +12 -0
- package/dist-client/components/learning-todo.js +43 -0
- package/dist-client/components/learning-todo.js.map +1 -0
- package/dist-client/components/learning-unit-form.d.ts +44 -0
- package/dist-client/components/learning-unit-form.js +151 -0
- package/dist-client/components/learning-unit-form.js.map +1 -0
- package/dist-client/index.d.ts +2 -0
- package/dist-client/index.js +3 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/pages/learning-course-editor.d.ts +63 -0
- package/dist-client/pages/learning-course-editor.js +476 -0
- package/dist-client/pages/learning-course-editor.js.map +1 -0
- package/dist-client/pages/learning-course-list.d.ts +37 -0
- package/dist-client/pages/learning-course-list.js +92 -0
- package/dist-client/pages/learning-course-list.js.map +1 -0
- package/dist-client/pages/learning-enrollment-status.d.ts +65 -0
- package/dist-client/pages/learning-enrollment-status.js +211 -0
- package/dist-client/pages/learning-enrollment-status.js.map +1 -0
- package/dist-client/pages/learning-view.d.ts +63 -0
- package/dist-client/pages/learning-view.js +446 -0
- package/dist-client/pages/learning-view.js.map +1 -0
- package/dist-client/pages/my-learning.d.ts +22 -0
- package/dist-client/pages/my-learning.js +110 -0
- package/dist-client/pages/my-learning.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +21 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-client/utils/learning-api.d.ts +61 -0
- package/dist-client/utils/learning-api.js +85 -0
- package/dist-client/utils/learning-api.js.map +1 -0
- package/dist-client/utils/learning-words.d.ts +20 -0
- package/dist-client/utils/learning-words.js +22 -0
- package/dist-client/utils/learning-words.js.map +1 -0
- package/dist-client/utils/material-source.d.ts +12 -0
- package/dist-client/utils/material-source.js +77 -0
- package/dist-client/utils/material-source.js.map +1 -0
- package/dist-server/activities.d.ts +38 -0
- package/dist-server/activities.js +42 -0
- package/dist-server/activities.js.map +1 -0
- package/dist-server/ai-reads.d.ts +9 -0
- package/dist-server/ai-reads.js +70 -0
- package/dist-server/ai-reads.js.map +1 -0
- package/dist-server/attachment-reader.d.ts +1 -0
- package/dist-server/attachment-reader.js +23 -0
- package/dist-server/attachment-reader.js.map +1 -0
- package/dist-server/index.d.ts +4 -0
- package/dist-server/index.js +33 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/learning-subjects.d.ts +10 -0
- package/dist-server/learning-subjects.js +31 -0
- package/dist-server/learning-subjects.js.map +1 -0
- package/dist-server/role-tasks.d.ts +2 -0
- package/dist-server/role-tasks.js +17 -0
- package/dist-server/role-tasks.js.map +1 -0
- package/dist-server/service/course/course-mutation.d.ts +19 -0
- package/dist-server/service/course/course-mutation.js +177 -0
- package/dist-server/service/course/course-mutation.js.map +1 -0
- package/dist-server/service/course/course-query.d.ts +27 -0
- package/dist-server/service/course/course-query.js +183 -0
- package/dist-server/service/course/course-query.js.map +1 -0
- package/dist-server/service/course/course-question.d.ts +41 -0
- package/dist-server/service/course/course-question.js +116 -0
- package/dist-server/service/course/course-question.js.map +1 -0
- package/dist-server/service/course/course-rules.d.ts +51 -0
- package/dist-server/service/course/course-rules.js +93 -0
- package/dist-server/service/course/course-rules.js.map +1 -0
- package/dist-server/service/course/course-service.d.ts +72 -0
- package/dist-server/service/course/course-service.js +398 -0
- package/dist-server/service/course/course-service.js.map +1 -0
- package/dist-server/service/course/course-type.d.ts +56 -0
- package/dist-server/service/course/course-type.js +202 -0
- package/dist-server/service/course/course-type.js.map +1 -0
- package/dist-server/service/course/course-unit.d.ts +37 -0
- package/dist-server/service/course/course-unit.js +128 -0
- package/dist-server/service/course/course-unit.js.map +1 -0
- package/dist-server/service/course/course-version.d.ts +45 -0
- package/dist-server/service/course/course-version.js +151 -0
- package/dist-server/service/course/course-version.js.map +1 -0
- package/dist-server/service/course/course.d.ts +23 -0
- package/dist-server/service/course/course.js +92 -0
- package/dist-server/service/course/course.js.map +1 -0
- package/dist-server/service/course/index.d.ts +15 -0
- package/dist-server/service/course/index.js +25 -0
- package/dist-server/service/course/index.js.map +1 -0
- package/dist-server/service/course/material-audio.d.ts +1 -0
- package/dist-server/service/course/material-audio.js +43 -0
- package/dist-server/service/course/material-audio.js.map +1 -0
- package/dist-server/service/course/material-draft-mutation.d.ts +13 -0
- package/dist-server/service/course/material-draft-mutation.js +55 -0
- package/dist-server/service/course/material-draft-mutation.js.map +1 -0
- package/dist-server/service/course/material-draft-rules.d.ts +38 -0
- package/dist-server/service/course/material-draft-rules.js +83 -0
- package/dist-server/service/course/material-draft-rules.js.map +1 -0
- package/dist-server/service/course/material-draft-service.d.ts +15 -0
- package/dist-server/service/course/material-draft-service.js +162 -0
- package/dist-server/service/course/material-draft-service.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-mutation.d.ts +11 -0
- package/dist-server/service/enrollment/enrollment-mutation.js +124 -0
- package/dist-server/service/enrollment/enrollment-mutation.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-query.d.ts +24 -0
- package/dist-server/service/enrollment/enrollment-query.js +236 -0
- package/dist-server/service/enrollment/enrollment-query.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-remind.d.ts +1 -0
- package/dist-server/service/enrollment/enrollment-remind.js +45 -0
- package/dist-server/service/enrollment/enrollment-remind.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-service.d.ts +110 -0
- package/dist-server/service/enrollment/enrollment-service.js +427 -0
- package/dist-server/service/enrollment/enrollment-service.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-status.d.ts +53 -0
- package/dist-server/service/enrollment/enrollment-status.js +194 -0
- package/dist-server/service/enrollment/enrollment-status.js.map +1 -0
- package/dist-server/service/enrollment/enrollment-type.d.ts +82 -0
- package/dist-server/service/enrollment/enrollment-type.js +293 -0
- package/dist-server/service/enrollment/enrollment-type.js.map +1 -0
- package/dist-server/service/enrollment/enrollment.d.ts +53 -0
- package/dist-server/service/enrollment/enrollment.js +191 -0
- package/dist-server/service/enrollment/enrollment.js.map +1 -0
- package/dist-server/service/enrollment/index.d.ts +15 -0
- package/dist-server/service/enrollment/index.js +26 -0
- package/dist-server/service/enrollment/index.js.map +1 -0
- package/dist-server/service/enrollment/learning-ai.d.ts +45 -0
- package/dist-server/service/enrollment/learning-ai.js +93 -0
- package/dist-server/service/enrollment/learning-ai.js.map +1 -0
- package/dist-server/service/enrollment/learning-documents.d.ts +7 -0
- package/dist-server/service/enrollment/learning-documents.js +159 -0
- package/dist-server/service/enrollment/learning-documents.js.map +1 -0
- package/dist-server/service/enrollment/learning-outcome.d.ts +10 -0
- package/dist-server/service/enrollment/learning-outcome.js +16 -0
- package/dist-server/service/enrollment/learning-outcome.js.map +1 -0
- package/dist-server/service/enrollment/progress-rules.d.ts +119 -0
- package/dist-server/service/enrollment/progress-rules.js +132 -0
- package/dist-server/service/enrollment/progress-rules.js.map +1 -0
- package/dist-server/service/enrollment/quiz-attempt.d.ts +34 -0
- package/dist-server/service/enrollment/quiz-attempt.js +105 -0
- package/dist-server/service/enrollment/quiz-attempt.js.map +1 -0
- package/dist-server/service/enrollment/unit-progress.d.ts +34 -0
- package/dist-server/service/enrollment/unit-progress.js +134 -0
- package/dist-server/service/enrollment/unit-progress.js.map +1 -0
- package/dist-server/service/index.d.ts +14 -0
- package/dist-server/service/index.js +43 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +57 -4
- package/things-factory.config.js +14 -0
- package/translations/en.json +278 -0
- package/translations/es.json +278 -0
- package/translations/ja.json +278 -0
- package/translations/ko.json +278 -0
- package/translations/ms.json +278 -0
- package/translations/zh.json +278 -0
- package/README.md +0 -3
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The enrolment and the course version open on screen, named for the assistant each turn (operato-application
|
|
3
|
+
* design/ai/screen-pattern.md §2-1, ADR-0194 decision 12). The course screen anchors its conversation to
|
|
4
|
+
* `enrollment:<uuid>` - its learner's own, read by `Query.myEnrollment` - and the course editor to `course-version:<uuid>`,
|
|
5
|
+
* read by `Query.courseVersion`; each is named only for someone that door lets through.
|
|
6
|
+
*/
|
|
7
|
+
import { type RecordSubject } from '@things-factory/ai-assistant';
|
|
8
|
+
export declare const ENROLLMENT_SUBJECT: RecordSubject;
|
|
9
|
+
export declare const COURSE_VERSION_SUBJECT: RecordSubject;
|
|
10
|
+
export declare function registerLearningSubjects(): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.COURSE_VERSION_SUBJECT = exports.ENROLLMENT_SUBJECT = void 0;
|
|
4
|
+
exports.registerLearningSubjects = registerLearningSubjects;
|
|
5
|
+
/**
|
|
6
|
+
* The enrolment and the course version open on screen, named for the assistant each turn (operato-application
|
|
7
|
+
* design/ai/screen-pattern.md §2-1, ADR-0194 decision 12). The course screen anchors its conversation to
|
|
8
|
+
* `enrollment:<uuid>` - its learner's own, read by `Query.myEnrollment` - and the course editor to `course-version:<uuid>`,
|
|
9
|
+
* read by `Query.courseVersion`; each is named only for someone that door lets through.
|
|
10
|
+
*/
|
|
11
|
+
const ai_assistant_1 = require("@things-factory/ai-assistant");
|
|
12
|
+
const shell_1 = require("@things-factory/shell");
|
|
13
|
+
exports.ENROLLMENT_SUBJECT = {
|
|
14
|
+
axis: 'enrollment',
|
|
15
|
+
noun: 'course enrolment',
|
|
16
|
+
door: 'Query.myEnrollment',
|
|
17
|
+
read: (rowId, domainId) => (0, shell_1.getRepository)('Enrollment').findOne({ where: { id: rowId, domain: { id: domainId } }, relations: ['course'] }),
|
|
18
|
+
nameOf: row => row.course?.name ?? ''
|
|
19
|
+
};
|
|
20
|
+
exports.COURSE_VERSION_SUBJECT = {
|
|
21
|
+
axis: 'course-version',
|
|
22
|
+
noun: 'course version',
|
|
23
|
+
door: 'Query.courseVersion',
|
|
24
|
+
read: (rowId, domainId) => (0, shell_1.getRepository)('CourseVersion').findOne({ where: { id: rowId, domain: { id: domainId } }, relations: ['course'] }),
|
|
25
|
+
nameOf: row => (row.course?.name ? `${row.course.name} v${row.number} (${row.status})` : '')
|
|
26
|
+
};
|
|
27
|
+
function registerLearningSubjects() {
|
|
28
|
+
(0, ai_assistant_1.registerRecordSubject)(exports.ENROLLMENT_SUBJECT);
|
|
29
|
+
(0, ai_assistant_1.registerRecordSubject)(exports.COURSE_VERSION_SUBJECT);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=learning-subjects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learning-subjects.js","sourceRoot":"","sources":["../server/learning-subjects.ts"],"names":[],"mappings":";;;AAyBA,4DAGC;AA5BD;;;;;GAKG;AACH,+DAAwF;AACxF,iDAAqD;AAExC,QAAA,kBAAkB,GAAkB;IAC/C,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,kBAAkB;IACxB,IAAI,EAAE,oBAAoB;IAC1B,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAA,qBAAa,EAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAS,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IAChJ,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE;CACtC,CAAA;AAEY,QAAA,sBAAsB,GAAkB;IACnD,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAA,qBAAa,EAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAS,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IACnJ,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;CAC7F,CAAA;AAED,SAAgB,wBAAwB;IACtC,IAAA,oCAAqB,EAAC,0BAAkB,CAAC,CAAA;IACzC,IAAA,oCAAqB,EAAC,8BAAsB,CAAC,CAAA;AAC/C,CAAC","sourcesContent":["/**\n * The enrolment and the course version open on screen, named for the assistant each turn (operato-application\n * design/ai/screen-pattern.md §2-1, ADR-0194 decision 12). The course screen anchors its conversation to\n * `enrollment:<uuid>` - its learner's own, read by `Query.myEnrollment` - and the course editor to `course-version:<uuid>`,\n * read by `Query.courseVersion`; each is named only for someone that door lets through.\n */\nimport { registerRecordSubject, type RecordSubject } from '@things-factory/ai-assistant'\nimport { getRepository } from '@things-factory/shell'\n\nexport const ENROLLMENT_SUBJECT: RecordSubject = {\n axis: 'enrollment',\n noun: 'course enrolment',\n door: 'Query.myEnrollment',\n read: (rowId, domainId) => getRepository('Enrollment').findOne({ where: { id: rowId, domain: { id: domainId } } as any, relations: ['course'] }),\n nameOf: row => row.course?.name ?? ''\n}\n\nexport const COURSE_VERSION_SUBJECT: RecordSubject = {\n axis: 'course-version',\n noun: 'course version',\n door: 'Query.courseVersion',\n read: (rowId, domainId) => getRepository('CourseVersion').findOne({ where: { id: rowId, domain: { id: domainId } } as any, relations: ['course'] }),\n nameOf: row => (row.course?.name ? `${row.course.name} v${row.number} (${row.status})` : '')\n}\n\nexport function registerLearningSubjects(): void {\n registerRecordSubject(ENROLLMENT_SUBJECT)\n registerRecordSubject(COURSE_VERSION_SUBJECT)\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* The work this module names, for the seats applications build (ADR-0139 decision 11, ADR-0194 decision 11).
|
|
4
|
+
*
|
|
5
|
+
* `learning.taking` - one's own enrolments, progress, quiz attempts and certificates; every employee. A department head
|
|
6
|
+
* reads where the people of their departments stand through it too - status only, no score.
|
|
7
|
+
* `learning.managing` - writing courses, assigning them, the status of everyone and the completion register.
|
|
8
|
+
*
|
|
9
|
+
* Data only - `server/index.ts` registers it - so an application's tests read it without starting the framework.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ROLE_TASKS = void 0;
|
|
13
|
+
exports.ROLE_TASKS = [
|
|
14
|
+
{ id: 'learning.taking', grants: [{ category: 'learning', axes: ['query', 'mutation'] }] },
|
|
15
|
+
{ id: 'learning.managing', grants: [{ category: 'course', axes: ['query', 'mutation'] }] }
|
|
16
|
+
];
|
|
17
|
+
//# sourceMappingURL=role-tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-tasks.js","sourceRoot":"","sources":["../server/role-tasks.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAIU,QAAA,UAAU,GAAe;IACpC,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE;IAC1F,EAAE,EAAE,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE;CAC3F,CAAA","sourcesContent":["/*\n * The work this module names, for the seats applications build (ADR-0139 decision 11, ADR-0194 decision 11).\n *\n * `learning.taking` - one's own enrolments, progress, quiz attempts and certificates; every employee. A department head\n * reads where the people of their departments stand through it too - status only, no score.\n * `learning.managing` - writing courses, assigning them, the status of everyone and the completion register.\n *\n * Data only - `server/index.ts` registers it - so an application's tests read it without starting the framework.\n */\n\nimport type { RoleTask } from '@things-factory/auth-base'\n\nexport const ROLE_TASKS: RoleTask[] = [\n { id: 'learning.taking', grants: [{ category: 'learning', axes: ['query', 'mutation'] }] },\n { id: 'learning.managing', grants: [{ category: 'course', axes: ['query', 'mutation'] }] }\n]\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FileUpload } from 'graphql-upload/GraphQLUpload.js';
|
|
2
|
+
import { Course } from './course';
|
|
3
|
+
import { CourseQuestion } from './course-question';
|
|
4
|
+
import { CourseUnit } from './course-unit';
|
|
5
|
+
import { CourseVersion } from './course-version';
|
|
6
|
+
import { CoursePatch, CourseQuestionInput, CourseUnitInput, CourseVersionPatch, NewCourse } from './course-type';
|
|
7
|
+
export declare class CourseMutation {
|
|
8
|
+
createCourse(course: NewCourse, context: ResolverContext): Promise<Course>;
|
|
9
|
+
updateCourse(id: string, patch: CoursePatch, context: ResolverContext): Promise<Course>;
|
|
10
|
+
createCourseVersion(courseId: string, fromId: string, context: ResolverContext): Promise<CourseVersion>;
|
|
11
|
+
updateCourseVersion(id: string, patch: CourseVersionPatch, context: ResolverContext): Promise<CourseVersion>;
|
|
12
|
+
saveCourseUnits(versionId: string, units: CourseUnitInput[], context: ResolverContext): Promise<CourseUnit[]>;
|
|
13
|
+
attachCourseUnitFile(unitId: string, file: FileUpload, durationSeconds: number, pageCount: number, context: ResolverContext): Promise<CourseUnit>;
|
|
14
|
+
saveCourseQuestions(versionId: string, questions: CourseQuestionInput[], context: ResolverContext): Promise<CourseQuestion[]>;
|
|
15
|
+
addDraftedCourseQuestion(versionId: string, question: CourseQuestionInput, context: ResolverContext): Promise<CourseQuestion>;
|
|
16
|
+
publishCourseVersion(id: string, context: ResolverContext): Promise<CourseVersion>;
|
|
17
|
+
closeCourseVersion(id: string, context: ResolverContext): Promise<CourseVersion>;
|
|
18
|
+
deleteCourseVersion(id: string, context: ResolverContext): Promise<boolean>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CourseMutation = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const GraphQLUpload_js_1 = tslib_1.__importDefault(require("graphql-upload/GraphQLUpload.js"));
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const course_1 = require("./course");
|
|
9
|
+
const course_question_1 = require("./course-question");
|
|
10
|
+
const course_unit_1 = require("./course-unit");
|
|
11
|
+
const course_version_1 = require("./course-version");
|
|
12
|
+
const course_type_1 = require("./course-type");
|
|
13
|
+
const course_service_1 = require("./course-service");
|
|
14
|
+
/* The managers' writes of courses (ADR-0194 decisions 2-4) - `course` mutation, the task `learning.managing`. */
|
|
15
|
+
let CourseMutation = class CourseMutation {
|
|
16
|
+
async createCourse(course, context) {
|
|
17
|
+
return await (0, course_service_1.createCourse)(course, context);
|
|
18
|
+
}
|
|
19
|
+
async updateCourse(id, patch, context) {
|
|
20
|
+
return await (0, course_service_1.updateCourse)(id, patch, context);
|
|
21
|
+
}
|
|
22
|
+
async createCourseVersion(courseId, fromId, context) {
|
|
23
|
+
return await (0, course_service_1.createCourseVersion)(courseId, fromId, context);
|
|
24
|
+
}
|
|
25
|
+
async updateCourseVersion(id, patch, context) {
|
|
26
|
+
return await (0, course_service_1.updateCourseVersion)(id, patch, context);
|
|
27
|
+
}
|
|
28
|
+
async saveCourseUnits(versionId, units, context) {
|
|
29
|
+
return await (0, course_service_1.saveCourseUnits)(versionId, units, context);
|
|
30
|
+
}
|
|
31
|
+
async attachCourseUnitFile(unitId, file, durationSeconds, pageCount, context) {
|
|
32
|
+
return await (0, course_service_1.attachCourseUnitFile)(unitId, file, { durationSeconds, pageCount }, context);
|
|
33
|
+
}
|
|
34
|
+
async saveCourseQuestions(versionId, questions, context) {
|
|
35
|
+
return await (0, course_service_1.saveCourseQuestions)(versionId, questions, context);
|
|
36
|
+
}
|
|
37
|
+
async addDraftedCourseQuestion(versionId, question, context) {
|
|
38
|
+
const [saved] = await (0, course_service_1.addDraftedQuestions)(versionId, [question], context);
|
|
39
|
+
if (!saved)
|
|
40
|
+
throw new shell_1.Refusal('learning-question-draft-invalid', {}, 'the drafted question is not complete - its text, two choices and the right ones');
|
|
41
|
+
return saved;
|
|
42
|
+
}
|
|
43
|
+
async publishCourseVersion(id, context) {
|
|
44
|
+
return await (0, course_service_1.publishCourseVersion)(id, context);
|
|
45
|
+
}
|
|
46
|
+
async closeCourseVersion(id, context) {
|
|
47
|
+
return await (0, course_service_1.closeCourseVersion)(id, context);
|
|
48
|
+
}
|
|
49
|
+
async deleteCourseVersion(id, context) {
|
|
50
|
+
return await (0, course_service_1.deleteCourseVersion)(id, context);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
exports.CourseMutation = CourseMutation;
|
|
54
|
+
tslib_1.__decorate([
|
|
55
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
56
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
57
|
+
(0, type_graphql_1.Mutation)(returns => course_1.Course, { description: 'To make a course.' }),
|
|
58
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('course', type => course_type_1.NewCourse)),
|
|
59
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
60
|
+
tslib_1.__metadata("design:type", Function),
|
|
61
|
+
tslib_1.__metadata("design:paramtypes", [course_type_1.NewCourse, Object]),
|
|
62
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
63
|
+
], CourseMutation.prototype, "createCourse", null);
|
|
64
|
+
tslib_1.__decorate([
|
|
65
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
66
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
67
|
+
(0, type_graphql_1.Mutation)(returns => course_1.Course, { description: "To change a course's name, description, category or manager." }),
|
|
68
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
69
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('patch', type => course_type_1.CoursePatch)),
|
|
70
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
71
|
+
tslib_1.__metadata("design:type", Function),
|
|
72
|
+
tslib_1.__metadata("design:paramtypes", [String, course_type_1.CoursePatch, Object]),
|
|
73
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
74
|
+
], CourseMutation.prototype, "updateCourse", null);
|
|
75
|
+
tslib_1.__decorate([
|
|
76
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
77
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
78
|
+
(0, type_graphql_1.Mutation)(returns => course_version_1.CourseVersion, { description: 'To make the next draft version of a course - a copy of `fromId`, or of the latest version.' }),
|
|
79
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('courseId')),
|
|
80
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('fromId', { nullable: true })),
|
|
81
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
82
|
+
tslib_1.__metadata("design:type", Function),
|
|
83
|
+
tslib_1.__metadata("design:paramtypes", [String, String, Object]),
|
|
84
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
85
|
+
], CourseMutation.prototype, "createCourseVersion", null);
|
|
86
|
+
tslib_1.__decorate([
|
|
87
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
88
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
89
|
+
(0, type_graphql_1.Mutation)(returns => course_version_1.CourseVersion, { description: 'To change what a draft version says - a published one never changes.' }),
|
|
90
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
91
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('patch', type => course_type_1.CourseVersionPatch)),
|
|
92
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
93
|
+
tslib_1.__metadata("design:type", Function),
|
|
94
|
+
tslib_1.__metadata("design:paramtypes", [String, course_type_1.CourseVersionPatch, Object]),
|
|
95
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
96
|
+
], CourseMutation.prototype, "updateCourseVersion", null);
|
|
97
|
+
tslib_1.__decorate([
|
|
98
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
99
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
100
|
+
(0, type_graphql_1.Mutation)(returns => [course_unit_1.CourseUnit], { description: 'To save the units of a draft version, in order - the ones left out are deleted.' }),
|
|
101
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('versionId')),
|
|
102
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('units', type => [course_type_1.CourseUnitInput])),
|
|
103
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
104
|
+
tslib_1.__metadata("design:type", Function),
|
|
105
|
+
tslib_1.__metadata("design:paramtypes", [String, Array, Object]),
|
|
106
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
107
|
+
], CourseMutation.prototype, "saveCourseUnits", null);
|
|
108
|
+
tslib_1.__decorate([
|
|
109
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
110
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
111
|
+
(0, type_graphql_1.Mutation)(returns => course_unit_1.CourseUnit, { description: "To attach a video's or a PDF's file to a unit of a draft version - a video with its length, a PDF with its page count." }),
|
|
112
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('unitId')),
|
|
113
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('file', type => GraphQLUpload_js_1.default)),
|
|
114
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('durationSeconds', type => type_graphql_1.Int, { nullable: true, description: "A video's length in seconds, read from the file." })),
|
|
115
|
+
tslib_1.__param(3, (0, type_graphql_1.Arg)('pageCount', type => type_graphql_1.Int, { nullable: true, description: "A PDF's page count, read from the file." })),
|
|
116
|
+
tslib_1.__param(4, (0, type_graphql_1.Ctx)()),
|
|
117
|
+
tslib_1.__metadata("design:type", Function),
|
|
118
|
+
tslib_1.__metadata("design:paramtypes", [String, Object, Number, Number, Object]),
|
|
119
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
120
|
+
], CourseMutation.prototype, "attachCourseUnitFile", null);
|
|
121
|
+
tslib_1.__decorate([
|
|
122
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
123
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
124
|
+
(0, type_graphql_1.Mutation)(returns => [course_question_1.CourseQuestion], { description: 'To save the questions of a draft version, in order - the ones left out are deleted.' }),
|
|
125
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('versionId')),
|
|
126
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('questions', type => [course_type_1.CourseQuestionInput])),
|
|
127
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
128
|
+
tslib_1.__metadata("design:type", Function),
|
|
129
|
+
tslib_1.__metadata("design:paramtypes", [String, Array, Object]),
|
|
130
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
131
|
+
], CourseMutation.prototype, "saveCourseQuestions", null);
|
|
132
|
+
tslib_1.__decorate([
|
|
133
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
134
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
135
|
+
(0, type_graphql_1.Mutation)(returns => course_question_1.CourseQuestion, { description: 'To add a question drafted by the assistant to a draft version - marked drafted until a manager saves it (ADR-0194 decision 12).' }),
|
|
136
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('versionId')),
|
|
137
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('question', type => course_type_1.CourseQuestionInput)),
|
|
138
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
139
|
+
tslib_1.__metadata("design:type", Function),
|
|
140
|
+
tslib_1.__metadata("design:paramtypes", [String, course_type_1.CourseQuestionInput, Object]),
|
|
141
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
142
|
+
], CourseMutation.prototype, "addDraftedCourseQuestion", null);
|
|
143
|
+
tslib_1.__decorate([
|
|
144
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
145
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
146
|
+
(0, type_graphql_1.Mutation)(returns => course_version_1.CourseVersion, { description: 'To publish a draft version - the version published before is closed.' }),
|
|
147
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
148
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
149
|
+
tslib_1.__metadata("design:type", Function),
|
|
150
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
151
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
152
|
+
], CourseMutation.prototype, "publishCourseVersion", null);
|
|
153
|
+
tslib_1.__decorate([
|
|
154
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
155
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
156
|
+
(0, type_graphql_1.Mutation)(returns => course_version_1.CourseVersion, { description: 'To close the published version - nobody starts it any more.' }),
|
|
157
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
158
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
159
|
+
tslib_1.__metadata("design:type", Function),
|
|
160
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
161
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
162
|
+
], CourseMutation.prototype, "closeCourseVersion", null);
|
|
163
|
+
tslib_1.__decorate([
|
|
164
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "mutation", domainOwnerGranted: true)'),
|
|
165
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
166
|
+
(0, type_graphql_1.Mutation)(returns => Boolean, { description: 'To delete a draft version.' }),
|
|
167
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
168
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
169
|
+
tslib_1.__metadata("design:type", Function),
|
|
170
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
171
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
172
|
+
], CourseMutation.prototype, "deleteCourseVersion", null);
|
|
173
|
+
exports.CourseMutation = CourseMutation = tslib_1.__decorate([
|
|
174
|
+
(0, type_graphql_1.Resolver)(course_1.Course),
|
|
175
|
+
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
|
|
176
|
+
], CourseMutation);
|
|
177
|
+
//# sourceMappingURL=course-mutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"course-mutation.js","sourceRoot":"","sources":["../../../server/service/course/course-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\nimport { Arg, Ctx, Directive, Int, Mutation, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { Refusal, SpeakRefusals } from '@things-factory/shell'\n\nimport { Course } from './course'\nimport { CourseQuestion } from './course-question'\nimport { CourseUnit } from './course-unit'\nimport { CourseVersion } from './course-version'\nimport { CoursePatch, CourseQuestionInput, CourseUnitInput, CourseVersionPatch, NewCourse } from './course-type'\nimport {\n addDraftedQuestions,\n attachCourseUnitFile,\n closeCourseVersion,\n createCourse,\n createCourseVersion,\n deleteCourseVersion,\n publishCourseVersion,\n saveCourseQuestions,\n saveCourseUnits,\n updateCourse,\n updateCourseVersion\n} from './course-service'\n\n\n/* The managers' writes of courses (ADR-0194 decisions 2-4) - `course` mutation, the task `learning.managing`. */\n@Resolver(Course)\n@UseMiddleware(SpeakRefusals)\nexport class CourseMutation {\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Course, { description: 'To make a course.' })\n async createCourse(@Arg('course', type => NewCourse) course: NewCourse, @Ctx() context: ResolverContext): Promise<Course> {\n return await createCourse(course, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Course, { description: \"To change a course's name, description, category or manager.\" })\n async updateCourse(@Arg('id') id: string, @Arg('patch', type => CoursePatch) patch: CoursePatch, @Ctx() context: ResolverContext): Promise<Course> {\n return await updateCourse(id, patch, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseVersion, { description: 'To make the next draft version of a course - a copy of `fromId`, or of the latest version.' })\n async createCourseVersion(@Arg('courseId') courseId: string, @Arg('fromId', { nullable: true }) fromId: string, @Ctx() context: ResolverContext): Promise<CourseVersion> {\n return await createCourseVersion(courseId, fromId, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseVersion, { description: 'To change what a draft version says - a published one never changes.' })\n async updateCourseVersion(@Arg('id') id: string, @Arg('patch', type => CourseVersionPatch) patch: CourseVersionPatch, @Ctx() context: ResolverContext): Promise<CourseVersion> {\n return await updateCourseVersion(id, patch, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [CourseUnit], { description: 'To save the units of a draft version, in order - the ones left out are deleted.' })\n async saveCourseUnits(@Arg('versionId') versionId: string, @Arg('units', type => [CourseUnitInput]) units: CourseUnitInput[], @Ctx() context: ResolverContext): Promise<CourseUnit[]> {\n return await saveCourseUnits(versionId, units, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseUnit, { description: \"To attach a video's or a PDF's file to a unit of a draft version - a video with its length, a PDF with its page count.\" })\n async attachCourseUnitFile(\n @Arg('unitId') unitId: string,\n @Arg('file', type => GraphQLUpload) file: FileUpload,\n @Arg('durationSeconds', type => Int, { nullable: true, description: \"A video's length in seconds, read from the file.\" }) durationSeconds: number,\n @Arg('pageCount', type => Int, { nullable: true, description: \"A PDF's page count, read from the file.\" }) pageCount: number,\n @Ctx() context: ResolverContext\n ): Promise<CourseUnit> {\n return await attachCourseUnitFile(unitId, file, { durationSeconds, pageCount }, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [CourseQuestion], { description: 'To save the questions of a draft version, in order - the ones left out are deleted.' })\n async saveCourseQuestions(@Arg('versionId') versionId: string, @Arg('questions', type => [CourseQuestionInput]) questions: CourseQuestionInput[], @Ctx() context: ResolverContext): Promise<CourseQuestion[]> {\n return await saveCourseQuestions(versionId, questions, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseQuestion, { description: 'To add a question drafted by the assistant to a draft version - marked drafted until a manager saves it (ADR-0194 decision 12).' })\n async addDraftedCourseQuestion(@Arg('versionId') versionId: string, @Arg('question', type => CourseQuestionInput) question: CourseQuestionInput, @Ctx() context: ResolverContext): Promise<CourseQuestion> {\n const [saved] = await addDraftedQuestions(versionId, [question], context)\n if (!saved) throw new Refusal('learning-question-draft-invalid', {}, 'the drafted question is not complete - its text, two choices and the right ones')\n return saved\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseVersion, { description: 'To publish a draft version - the version published before is closed.' })\n async publishCourseVersion(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<CourseVersion> {\n return await publishCourseVersion(id, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => CourseVersion, { description: 'To close the published version - nobody starts it any more.' })\n async closeCourseVersion(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<CourseVersion> {\n return await closeCourseVersion(id, context)\n }\n\n @Directive('@privilege(category: \"course\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: 'To delete a draft version.' })\n async deleteCourseVersion(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n return await deleteCourseVersion(id, context)\n }\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Attachment } from '@things-factory/attachment-base';
|
|
2
|
+
import { User } from '@things-factory/auth-base';
|
|
3
|
+
import { ListParam } from '@things-factory/shell';
|
|
4
|
+
import { Course } from './course';
|
|
5
|
+
import { CourseQuestion } from './course-question';
|
|
6
|
+
import { CourseUnit } from './course-unit';
|
|
7
|
+
import { CourseVersion } from './course-version';
|
|
8
|
+
import { CourseChoiceKey, CourseList } from './course-type';
|
|
9
|
+
export declare class CourseQuery {
|
|
10
|
+
courses(params: ListParam, context: ResolverContext): Promise<CourseList>;
|
|
11
|
+
course(id: string, context: ResolverContext): Promise<Course | null>;
|
|
12
|
+
courseVersion(id: string, context: ResolverContext): Promise<CourseVersion | null>;
|
|
13
|
+
versions(course: Course, context: ResolverContext): Promise<CourseVersion[]>;
|
|
14
|
+
publishedVersion(course: Course, context: ResolverContext): Promise<CourseVersion | null>;
|
|
15
|
+
manager(course: Course): Promise<User | null>;
|
|
16
|
+
}
|
|
17
|
+
export declare class CourseVersionFields {
|
|
18
|
+
units(version: CourseVersion, context: ResolverContext): Promise<CourseUnit[]>;
|
|
19
|
+
questions(version: CourseVersion, context: ResolverContext): Promise<CourseQuestion[]>;
|
|
20
|
+
}
|
|
21
|
+
export declare class CourseUnitFields {
|
|
22
|
+
secondsPerPage(unit: CourseUnit): number | null;
|
|
23
|
+
file(unit: CourseUnit, context: ResolverContext): Promise<Attachment | null>;
|
|
24
|
+
}
|
|
25
|
+
export declare class CourseQuestionFields {
|
|
26
|
+
choices(question: CourseQuestion, context: ResolverContext): Promise<CourseChoiceKey[]>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CourseQuestionFields = exports.CourseUnitFields = exports.CourseVersionFields = exports.CourseQuery = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const attachment_base_1 = require("@things-factory/attachment-base");
|
|
7
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
8
|
+
const shell_1 = require("@things-factory/shell");
|
|
9
|
+
const progress_rules_1 = require("../enrollment/progress-rules");
|
|
10
|
+
const course_1 = require("./course");
|
|
11
|
+
const course_question_1 = require("./course-question");
|
|
12
|
+
const course_unit_1 = require("./course-unit");
|
|
13
|
+
const course_version_1 = require("./course-version");
|
|
14
|
+
const course_type_1 = require("./course-type");
|
|
15
|
+
const course_service_1 = require("./course-service");
|
|
16
|
+
/*
|
|
17
|
+
* The managers' reads of courses (ADR-0194 decisions 2-4, 10, 11) - `course` query, the task `learning.managing`. A learner
|
|
18
|
+
* reads a course through their enrolment (enrollment-query.ts), never these.
|
|
19
|
+
*/
|
|
20
|
+
let CourseQuery = class CourseQuery {
|
|
21
|
+
async courses(params, context) {
|
|
22
|
+
const { domain } = context.state;
|
|
23
|
+
const qb = (0, shell_1.getQueryBuilderFromListParams)({ domain, params, repository: (0, shell_1.getRepository)(course_1.Course), alias: 'C', searchables: ['name', 'description', 'category'] });
|
|
24
|
+
if (!params?.sortings?.length)
|
|
25
|
+
qb.orderBy('C.name', 'ASC');
|
|
26
|
+
const [items, total] = await qb.getManyAndCount();
|
|
27
|
+
return { items, total };
|
|
28
|
+
}
|
|
29
|
+
async course(id, context) {
|
|
30
|
+
return await (0, shell_1.getRepository)(course_1.Course).findOne({ where: { id, domain: { id: context.state.domain.id } } });
|
|
31
|
+
}
|
|
32
|
+
async courseVersion(id, context) {
|
|
33
|
+
return await (0, shell_1.getRepository)(course_version_1.CourseVersion).findOne({ where: { id, domain: { id: context.state.domain.id } } });
|
|
34
|
+
}
|
|
35
|
+
async versions(course, context) {
|
|
36
|
+
if (!(await (0, auth_base_1.requestHolds)(context, 'course', 'query')))
|
|
37
|
+
return [];
|
|
38
|
+
return await (0, shell_1.getRepository)(course_version_1.CourseVersion).find({ where: { course: { id: course.id } }, order: { number: 'DESC' } });
|
|
39
|
+
}
|
|
40
|
+
async publishedVersion(course, context) {
|
|
41
|
+
return await (0, course_service_1.publishedVersionOf)((0, course_service_1.learningManagerOf)(context), { id: course.domainId }, course.id);
|
|
42
|
+
}
|
|
43
|
+
async manager(course) {
|
|
44
|
+
return course.managerId ? await (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: course.managerId }) : null;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
exports.CourseQuery = CourseQuery;
|
|
48
|
+
tslib_1.__decorate([
|
|
49
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "query", domainOwnerGranted: true)'),
|
|
50
|
+
(0, type_graphql_1.Query)(returns => course_type_1.CourseList, { description: 'The courses of the domain.' }),
|
|
51
|
+
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
52
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
53
|
+
tslib_1.__metadata("design:type", Function),
|
|
54
|
+
tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
|
|
55
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
56
|
+
], CourseQuery.prototype, "courses", null);
|
|
57
|
+
tslib_1.__decorate([
|
|
58
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "query", domainOwnerGranted: true)'),
|
|
59
|
+
(0, type_graphql_1.Query)(returns => course_1.Course, { nullable: true, description: 'One course.' }),
|
|
60
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
61
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
62
|
+
tslib_1.__metadata("design:type", Function),
|
|
63
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
64
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
65
|
+
], CourseQuery.prototype, "course", null);
|
|
66
|
+
tslib_1.__decorate([
|
|
67
|
+
(0, type_graphql_1.Directive)('@privilege(category: "course", privilege: "query", domainOwnerGranted: true)'),
|
|
68
|
+
(0, type_graphql_1.Query)(returns => course_version_1.CourseVersion, { nullable: true, description: 'One version of a course, with its units and questions.' }),
|
|
69
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
70
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
71
|
+
tslib_1.__metadata("design:type", Function),
|
|
72
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
73
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
74
|
+
], CourseQuery.prototype, "courseVersion", null);
|
|
75
|
+
tslib_1.__decorate([
|
|
76
|
+
(0, type_graphql_1.FieldResolver)(type => [course_version_1.CourseVersion], { description: 'Its versions, the newest first - for a manager; nothing for anyone else.' }),
|
|
77
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
78
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
79
|
+
tslib_1.__metadata("design:type", Function),
|
|
80
|
+
tslib_1.__metadata("design:paramtypes", [course_1.Course, Object]),
|
|
81
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
82
|
+
], CourseQuery.prototype, "versions", null);
|
|
83
|
+
tslib_1.__decorate([
|
|
84
|
+
(0, type_graphql_1.FieldResolver)(type => course_version_1.CourseVersion, { nullable: true, description: 'The version learners take now.' }),
|
|
85
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
86
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
87
|
+
tslib_1.__metadata("design:type", Function),
|
|
88
|
+
tslib_1.__metadata("design:paramtypes", [course_1.Course, Object]),
|
|
89
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
90
|
+
], CourseQuery.prototype, "publishedVersion", null);
|
|
91
|
+
tslib_1.__decorate([
|
|
92
|
+
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true, description: 'Who keeps it.' }),
|
|
93
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
94
|
+
tslib_1.__metadata("design:type", Function),
|
|
95
|
+
tslib_1.__metadata("design:paramtypes", [course_1.Course]),
|
|
96
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
97
|
+
], CourseQuery.prototype, "manager", null);
|
|
98
|
+
exports.CourseQuery = CourseQuery = tslib_1.__decorate([
|
|
99
|
+
(0, type_graphql_1.Resolver)(course_1.Course),
|
|
100
|
+
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
|
|
101
|
+
], CourseQuery);
|
|
102
|
+
let CourseVersionFields = class CourseVersionFields {
|
|
103
|
+
async units(version, context) {
|
|
104
|
+
if (!(await (0, course_service_1.mayReadVersion)(context, version)))
|
|
105
|
+
return [];
|
|
106
|
+
return await (0, course_service_1.unitsOf)((0, course_service_1.learningManagerOf)(context), version.id);
|
|
107
|
+
}
|
|
108
|
+
async questions(version, context) {
|
|
109
|
+
if (!(await (0, auth_base_1.requestHolds)(context, 'course', 'query')))
|
|
110
|
+
return [];
|
|
111
|
+
return await (0, course_service_1.questionsOf)((0, course_service_1.learningManagerOf)(context), version.id);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
exports.CourseVersionFields = CourseVersionFields;
|
|
115
|
+
tslib_1.__decorate([
|
|
116
|
+
(0, type_graphql_1.FieldResolver)(type => [course_unit_1.CourseUnit], { description: 'Its units, in order - for a manager, or a learner whose enrolment shows this version.' }),
|
|
117
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
118
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
119
|
+
tslib_1.__metadata("design:type", Function),
|
|
120
|
+
tslib_1.__metadata("design:paramtypes", [course_version_1.CourseVersion, Object]),
|
|
121
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
122
|
+
], CourseVersionFields.prototype, "units", null);
|
|
123
|
+
tslib_1.__decorate([
|
|
124
|
+
(0, type_graphql_1.FieldResolver)(type => [course_question_1.CourseQuestion], { description: 'Its questions, in order - for a manager; nothing for anyone else.' }),
|
|
125
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
126
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
127
|
+
tslib_1.__metadata("design:type", Function),
|
|
128
|
+
tslib_1.__metadata("design:paramtypes", [course_version_1.CourseVersion, Object]),
|
|
129
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
130
|
+
], CourseVersionFields.prototype, "questions", null);
|
|
131
|
+
exports.CourseVersionFields = CourseVersionFields = tslib_1.__decorate([
|
|
132
|
+
(0, type_graphql_1.Resolver)(course_version_1.CourseVersion)
|
|
133
|
+
], CourseVersionFields);
|
|
134
|
+
let CourseUnitFields = class CourseUnitFields {
|
|
135
|
+
secondsPerPage(unit) {
|
|
136
|
+
return unit.kind === 'PDF' ? (0, progress_rules_1.secondsPerPage)(unit) : null;
|
|
137
|
+
}
|
|
138
|
+
async file(unit, context) {
|
|
139
|
+
const version = await (0, course_service_1.learningManagerOf)(context).getRepository(course_version_1.CourseVersion).findOne({ where: { id: unit.versionId }, withDeleted: true });
|
|
140
|
+
if (!(await (0, course_service_1.mayReadVersion)(context, version)))
|
|
141
|
+
return null;
|
|
142
|
+
return (await (0, course_service_1.unitFilesOf)(context.state.domain, [unit.id])).get(unit.id) ?? null;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
exports.CourseUnitFields = CourseUnitFields;
|
|
146
|
+
tslib_1.__decorate([
|
|
147
|
+
(0, type_graphql_1.FieldResolver)(type => type_graphql_1.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.' }),
|
|
148
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
149
|
+
tslib_1.__metadata("design:type", Function),
|
|
150
|
+
tslib_1.__metadata("design:paramtypes", [course_unit_1.CourseUnit]),
|
|
151
|
+
tslib_1.__metadata("design:returntype", Number)
|
|
152
|
+
], CourseUnitFields.prototype, "secondsPerPage", null);
|
|
153
|
+
tslib_1.__decorate([
|
|
154
|
+
(0, type_graphql_1.FieldResolver)(type => attachment_base_1.Attachment, { nullable: true, description: "A video's or a PDF's file." }),
|
|
155
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
156
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
157
|
+
tslib_1.__metadata("design:type", Function),
|
|
158
|
+
tslib_1.__metadata("design:paramtypes", [course_unit_1.CourseUnit, Object]),
|
|
159
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
160
|
+
], CourseUnitFields.prototype, "file", null);
|
|
161
|
+
exports.CourseUnitFields = CourseUnitFields = tslib_1.__decorate([
|
|
162
|
+
(0, type_graphql_1.Resolver)(course_unit_1.CourseUnit)
|
|
163
|
+
], CourseUnitFields);
|
|
164
|
+
let CourseQuestionFields = class CourseQuestionFields {
|
|
165
|
+
async choices(question, context) {
|
|
166
|
+
if (!(await (0, auth_base_1.requestHolds)(context, 'course', 'query')))
|
|
167
|
+
return [];
|
|
168
|
+
return question.choices ?? [];
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
exports.CourseQuestionFields = CourseQuestionFields;
|
|
172
|
+
tslib_1.__decorate([
|
|
173
|
+
(0, type_graphql_1.FieldResolver)(type => [course_type_1.CourseChoiceKey], { description: 'Its choices with which are right - for a manager only.' }),
|
|
174
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
175
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
176
|
+
tslib_1.__metadata("design:type", Function),
|
|
177
|
+
tslib_1.__metadata("design:paramtypes", [course_question_1.CourseQuestion, Object]),
|
|
178
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
179
|
+
], CourseQuestionFields.prototype, "choices", null);
|
|
180
|
+
exports.CourseQuestionFields = CourseQuestionFields = tslib_1.__decorate([
|
|
181
|
+
(0, type_graphql_1.Resolver)(course_question_1.CourseQuestion)
|
|
182
|
+
], CourseQuestionFields);
|
|
183
|
+
//# sourceMappingURL=course-query.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { User } from '@things-factory/auth-base';
|
|
2
|
+
import { Domain } from '@things-factory/shell';
|
|
3
|
+
import { CourseVersion } from './course-version';
|
|
4
|
+
/** How a question is answered. */
|
|
5
|
+
export declare enum CourseQuestionKind {
|
|
6
|
+
SINGLE = "SINGLE",
|
|
7
|
+
MULTIPLE = "MULTIPLE",
|
|
8
|
+
TRUE_FALSE = "TRUE_FALSE"
|
|
9
|
+
}
|
|
10
|
+
/** One choice of a question, with whether it is right - kept in the row, never sent to a learner. */
|
|
11
|
+
export interface CourseChoice {
|
|
12
|
+
id: string;
|
|
13
|
+
text: string;
|
|
14
|
+
correct: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 문항 (ADR-0194 decision 4) - one question of a version's quiz: its choices with which are right, and why. Whether a
|
|
18
|
+
* choice is right is read by the server's scoring and the managers' editor only; a learner is drawn the question without
|
|
19
|
+
* it. One the assistant drafted stays `drafted` until a manager looks it over (decision 12).
|
|
20
|
+
*/
|
|
21
|
+
export declare class CourseQuestion {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
domain?: Domain;
|
|
24
|
+
domainId?: string;
|
|
25
|
+
version?: CourseVersion;
|
|
26
|
+
versionId?: string;
|
|
27
|
+
seq: number;
|
|
28
|
+
kind: CourseQuestionKind;
|
|
29
|
+
text: string;
|
|
30
|
+
/** The choices with which are right - not a field: a learner never reads it. */
|
|
31
|
+
choices: CourseChoice[];
|
|
32
|
+
explanation?: string;
|
|
33
|
+
drafted: boolean;
|
|
34
|
+
createdAt?: Date;
|
|
35
|
+
updatedAt?: Date;
|
|
36
|
+
deletedAt?: Date;
|
|
37
|
+
creator?: User;
|
|
38
|
+
creatorId?: string;
|
|
39
|
+
updater?: User;
|
|
40
|
+
updaterId?: string;
|
|
41
|
+
}
|