@things-factory/learning 10.1.260 → 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.
Files changed (103) hide show
  1. package/dist-client/components/learning-material-form.d.ts +41 -0
  2. package/dist-client/components/learning-material-form.js +202 -0
  3. package/dist-client/components/learning-material-form.js.map +1 -0
  4. package/dist-client/components/learning-unit-form.d.ts +3 -0
  5. package/dist-client/components/learning-unit-form.js +10 -2
  6. package/dist-client/components/learning-unit-form.js.map +1 -1
  7. package/dist-client/pages/learning-course-editor.d.ts +1 -0
  8. package/dist-client/pages/learning-course-editor.js +19 -6
  9. package/dist-client/pages/learning-course-editor.js.map +1 -1
  10. package/dist-client/pages/learning-course-list.d.ts +1 -5
  11. package/dist-client/pages/learning-course-list.js +54 -16
  12. package/dist-client/pages/learning-course-list.js.map +1 -1
  13. package/dist-client/pages/learning-enrollment-status.d.ts +31 -16
  14. package/dist-client/pages/learning-enrollment-status.js +104 -117
  15. package/dist-client/pages/learning-enrollment-status.js.map +1 -1
  16. package/dist-client/pages/learning-view.d.ts +11 -0
  17. package/dist-client/pages/learning-view.js +94 -19
  18. package/dist-client/pages/learning-view.js.map +1 -1
  19. package/dist-client/tsconfig.tsbuildinfo +1 -1
  20. package/dist-client/utils/learning-api.d.ts +48 -3
  21. package/dist-client/utils/learning-api.js +51 -2
  22. package/dist-client/utils/learning-api.js.map +1 -1
  23. package/dist-client/utils/material-source.d.ts +12 -0
  24. package/dist-client/utils/material-source.js +77 -0
  25. package/dist-client/utils/material-source.js.map +1 -0
  26. package/dist-server/ai-reads.js +1 -1
  27. package/dist-server/ai-reads.js.map +1 -1
  28. package/dist-server/service/course/course-mutation.d.ts +1 -1
  29. package/dist-server/service/course/course-mutation.js +7 -6
  30. package/dist-server/service/course/course-mutation.js.map +1 -1
  31. package/dist-server/service/course/course-query.d.ts +2 -0
  32. package/dist-server/service/course/course-query.js +27 -3
  33. package/dist-server/service/course/course-query.js.map +1 -1
  34. package/dist-server/service/course/course-rules.d.ts +3 -1
  35. package/dist-server/service/course/course-rules.js +5 -1
  36. package/dist-server/service/course/course-rules.js.map +1 -1
  37. package/dist-server/service/course/course-service.d.ts +5 -4
  38. package/dist-server/service/course/course-service.js +10 -14
  39. package/dist-server/service/course/course-service.js.map +1 -1
  40. package/dist-server/service/course/course-type.d.ts +1 -0
  41. package/dist-server/service/course/course-type.js +4 -0
  42. package/dist-server/service/course/course-type.js.map +1 -1
  43. package/dist-server/service/course/course-unit.d.ts +3 -2
  44. package/dist-server/service/course/course-unit.js +7 -2
  45. package/dist-server/service/course/course-unit.js.map +1 -1
  46. package/dist-server/service/course/index.d.ts +2 -1
  47. package/dist-server/service/course/index.js +2 -1
  48. package/dist-server/service/course/index.js.map +1 -1
  49. package/dist-server/service/course/material-audio.d.ts +1 -0
  50. package/dist-server/service/course/material-audio.js +43 -0
  51. package/dist-server/service/course/material-audio.js.map +1 -0
  52. package/dist-server/service/course/material-draft-mutation.d.ts +13 -0
  53. package/dist-server/service/course/material-draft-mutation.js +55 -0
  54. package/dist-server/service/course/material-draft-mutation.js.map +1 -0
  55. package/dist-server/service/course/material-draft-rules.d.ts +38 -0
  56. package/dist-server/service/course/material-draft-rules.js +83 -0
  57. package/dist-server/service/course/material-draft-rules.js.map +1 -0
  58. package/dist-server/service/course/material-draft-service.d.ts +15 -0
  59. package/dist-server/service/course/material-draft-service.js +162 -0
  60. package/dist-server/service/course/material-draft-service.js.map +1 -0
  61. package/dist-server/service/enrollment/enrollment-mutation.d.ts +1 -1
  62. package/dist-server/service/enrollment/enrollment-mutation.js +6 -6
  63. package/dist-server/service/enrollment/enrollment-mutation.js.map +1 -1
  64. package/dist-server/service/enrollment/enrollment-query.d.ts +8 -4
  65. package/dist-server/service/enrollment/enrollment-query.js +47 -36
  66. package/dist-server/service/enrollment/enrollment-query.js.map +1 -1
  67. package/dist-server/service/enrollment/enrollment-service.d.ts +4 -3
  68. package/dist-server/service/enrollment/enrollment-service.js +41 -18
  69. package/dist-server/service/enrollment/enrollment-service.js.map +1 -1
  70. package/dist-server/service/enrollment/enrollment-status.d.ts +42 -18
  71. package/dist-server/service/enrollment/enrollment-status.js +143 -42
  72. package/dist-server/service/enrollment/enrollment-status.js.map +1 -1
  73. package/dist-server/service/enrollment/enrollment-type.d.ts +2 -8
  74. package/dist-server/service/enrollment/enrollment-type.js +20 -42
  75. package/dist-server/service/enrollment/enrollment-type.js.map +1 -1
  76. package/dist-server/service/enrollment/enrollment.d.ts +1 -0
  77. package/dist-server/service/enrollment/enrollment.js +5 -0
  78. package/dist-server/service/enrollment/enrollment.js.map +1 -1
  79. package/dist-server/service/enrollment/index.d.ts +3 -3
  80. package/dist-server/service/enrollment/index.js +3 -3
  81. package/dist-server/service/enrollment/index.js.map +1 -1
  82. package/dist-server/service/enrollment/learning-ai.d.ts +9 -2
  83. package/dist-server/service/enrollment/learning-ai.js +25 -28
  84. package/dist-server/service/enrollment/learning-ai.js.map +1 -1
  85. package/dist-server/service/enrollment/learning-documents.js +3 -4
  86. package/dist-server/service/enrollment/learning-documents.js.map +1 -1
  87. package/dist-server/service/enrollment/progress-rules.d.ts +40 -11
  88. package/dist-server/service/enrollment/progress-rules.js +54 -13
  89. package/dist-server/service/enrollment/progress-rules.js.map +1 -1
  90. package/dist-server/service/enrollment/unit-progress.d.ts +4 -0
  91. package/dist-server/service/enrollment/unit-progress.js +20 -0
  92. package/dist-server/service/enrollment/unit-progress.js.map +1 -1
  93. package/dist-server/service/index.d.ts +2 -2
  94. package/dist-server/service/index.js +2 -2
  95. package/dist-server/service/index.js.map +1 -1
  96. package/dist-server/tsconfig.tsbuildinfo +1 -1
  97. package/package.json +14 -13
  98. package/translations/en.json +42 -9
  99. package/translations/es.json +42 -9
  100. package/translations/ja.json +42 -9
  101. package/translations/ko.json +42 -9
  102. package/translations/ms.json +42 -9
  103. package/translations/zh.json +42 -9
@@ -41,6 +41,8 @@ function unitInputRefusal(unit) {
41
41
  return 'learning-unit-min-time-invalid';
42
42
  if (unit.durationSeconds != null && (!Number.isInteger(unit.durationSeconds) || unit.durationSeconds < 1))
43
43
  return 'learning-unit-duration-invalid';
44
+ if (unit.pageCount != null && (!Number.isInteger(unit.pageCount) || unit.pageCount < 1))
45
+ return 'learning-unit-pages-invalid';
44
46
  return null;
45
47
  }
46
48
  /** Why a question may not be kept: its text, two choices or more (TRUE_FALSE exactly two), and the right ones its kind allows. */
@@ -63,7 +65,7 @@ function questionInputRefusal(question) {
63
65
  }
64
66
  /**
65
67
  * Why a draft may not be published (decisions 2-4): a unit or more; a video or a PDF with its file, a video with its
66
- * length; a quiz with questions - as many as it draws, none of them a draft the assistant made that no manager looked over.
68
+ * length, a PDF with its page count; a quiz with questions - as many as it draws, none of them a draft the assistant made that no manager looked over.
67
69
  */
68
70
  function publishRefusal({ version, units, questions }) {
69
71
  if (version.status !== 'DRAFT')
@@ -75,6 +77,8 @@ function publishRefusal({ version, units, questions }) {
75
77
  return 'learning-unit-file-required';
76
78
  if (unit.kind === 'VIDEO' && !unit.durationSeconds)
77
79
  return 'learning-unit-duration-required';
80
+ if (unit.kind === 'PDF' && !unit.pageCount)
81
+ return 'learning-unit-pages-required';
78
82
  }
79
83
  if (version.passScore != null) {
80
84
  if (!questions.length)
@@ -1 +1 @@
1
- {"version":3,"file":"course-rules.js","sourceRoot":"","sources":["../../../server/service/course/course-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What may be done to a course's versions (ADR-0194 decisions 2-4) - data in, the refusal's code out, no database.\n */\n\nexport interface VersionShape {\n status: string\n passScore?: number | null\n questionCount?: number | null\n attemptLimit?: number | null\n minSeconds?: number | null\n}\n\n/** Why a version may not be written to - a published or closed one never changes (decision 2). */\nexport function versionEditRefusal(version: { status: string } | null | undefined): string | null {\n if (!version) return 'learning-version-not-found'\n return version.status === 'DRAFT' ? null : 'learning-version-not-draft'\n}\n\n/** Why what a version says may not be kept. */\nexport function versionInputRefusal(input: VersionShape): string | null {\n if (input.minSeconds != null && (!Number.isInteger(input.minSeconds) || input.minSeconds < 0)) return 'learning-min-time-invalid'\n if (input.passScore != null && (!Number.isInteger(input.passScore) || input.passScore < 1 || input.passScore > 100)) return 'learning-pass-score-invalid'\n if (input.questionCount != null && (!Number.isInteger(input.questionCount) || input.questionCount < 1)) return 'learning-question-count-invalid'\n if (input.attemptLimit != null && (!Number.isInteger(input.attemptLimit) || input.attemptLimit < 1)) return 'learning-attempt-limit-invalid'\n return null\n}\n\nexport interface UnitInput {\n kind: string\n name?: string | null\n body?: string | null\n url?: string | null\n durationSeconds?: number | null\n minSeconds?: number | null\n}\n\nconst KINDS = ['VIDEO', 'PDF', 'MARKDOWN', 'LINK']\n\n/** Why a unit may not be kept as given. A video's or a PDF's file is attached apart - publishing asks for it. */\nexport function unitInputRefusal(unit: UnitInput): string | null {\n if (!KINDS.includes(unit.kind)) return 'learning-unit-kind-invalid'\n if (!unit.name?.trim()) return 'learning-unit-name-required'\n if (unit.kind === 'MARKDOWN' && !unit.body?.trim()) return 'learning-unit-body-required'\n if (unit.kind === 'LINK' && !/^https?:\\/\\//i.test(unit.url?.trim() ?? '')) return 'learning-unit-url-invalid'\n if (unit.minSeconds != null && (!Number.isInteger(unit.minSeconds) || unit.minSeconds < 1)) return 'learning-unit-min-time-invalid'\n if (unit.durationSeconds != null && (!Number.isInteger(unit.durationSeconds) || unit.durationSeconds < 1)) return 'learning-unit-duration-invalid'\n return null\n}\n\nexport interface QuestionInput {\n kind: string\n text?: string | null\n choices: { text: string; correct: boolean }[]\n}\n\n/** Why a question may not be kept: its text, two choices or more (TRUE_FALSE exactly two), and the right ones its kind allows. */\nexport function questionInputRefusal(question: QuestionInput): string | null {\n if (!['SINGLE', 'MULTIPLE', 'TRUE_FALSE'].includes(question.kind)) return 'learning-question-kind-invalid'\n if (!question.text?.trim()) return 'learning-question-text-required'\n const choices = question.choices ?? []\n if (choices.length < 2 || choices.some(one => !one.text?.trim())) return 'learning-question-choices-required'\n if (question.kind === 'TRUE_FALSE' && choices.length !== 2) return 'learning-question-choices-required'\n const right = choices.filter(one => one.correct).length\n if (right === 0) return 'learning-question-answer-required'\n if (question.kind !== 'MULTIPLE' && right !== 1) return 'learning-question-one-answer'\n return null\n}\n\nexport interface PublishFacts {\n version: VersionShape\n units: { kind: string; durationSeconds?: number | null; hasFile: boolean }[]\n questions: { drafted: boolean }[]\n}\n\n/**\n * Why a draft may not be published (decisions 2-4): a unit or more; a video or a PDF with its file, a video with its\n * length; a quiz with questions - as many as it draws, none of them a draft the assistant made that no manager looked over.\n */\nexport function publishRefusal({ version, units, questions }: PublishFacts): string | null {\n if (version.status !== 'DRAFT') return 'learning-version-not-draft'\n if (!units.length) return 'learning-units-required'\n for (const unit of units) {\n if ((unit.kind === 'VIDEO' || unit.kind === 'PDF') && !unit.hasFile) return 'learning-unit-file-required'\n if (unit.kind === 'VIDEO' && !unit.durationSeconds) return 'learning-unit-duration-required'\n }\n if (version.passScore != null) {\n if (!questions.length) return 'learning-questions-required'\n if (version.questionCount != null && version.questionCount > questions.length) return 'learning-question-count-too-many'\n }\n if (questions.some(one => one.drafted)) return 'learning-questions-drafted'\n return null\n}\n"]}
1
+ {"version":3,"file":"course-rules.js","sourceRoot":"","sources":["../../../server/service/course/course-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What may be done to a course's versions (ADR-0194 decisions 2-4) - data in, the refusal's code out, no database.\n */\n\nexport interface VersionShape {\n status: string\n passScore?: number | null\n questionCount?: number | null\n attemptLimit?: number | null\n minSeconds?: number | null\n}\n\n/** Why a version may not be written to - a published or closed one never changes (decision 2). */\nexport function versionEditRefusal(version: { status: string } | null | undefined): string | null {\n if (!version) return 'learning-version-not-found'\n return version.status === 'DRAFT' ? null : 'learning-version-not-draft'\n}\n\n/** Why what a version says may not be kept. */\nexport function versionInputRefusal(input: VersionShape): string | null {\n if (input.minSeconds != null && (!Number.isInteger(input.minSeconds) || input.minSeconds < 0)) return 'learning-min-time-invalid'\n if (input.passScore != null && (!Number.isInteger(input.passScore) || input.passScore < 1 || input.passScore > 100)) return 'learning-pass-score-invalid'\n if (input.questionCount != null && (!Number.isInteger(input.questionCount) || input.questionCount < 1)) return 'learning-question-count-invalid'\n if (input.attemptLimit != null && (!Number.isInteger(input.attemptLimit) || input.attemptLimit < 1)) return 'learning-attempt-limit-invalid'\n return null\n}\n\nexport interface UnitInput {\n kind: string\n name?: string | null\n body?: string | null\n url?: string | null\n durationSeconds?: number | null\n pageCount?: number | null\n minSeconds?: number | null\n}\n\nconst KINDS = ['VIDEO', 'PDF', 'MARKDOWN', 'LINK']\n\n/** Why a unit may not be kept as given. A video's or a PDF's file is attached apart - publishing asks for it. */\nexport function unitInputRefusal(unit: UnitInput): string | null {\n if (!KINDS.includes(unit.kind)) return 'learning-unit-kind-invalid'\n if (!unit.name?.trim()) return 'learning-unit-name-required'\n if (unit.kind === 'MARKDOWN' && !unit.body?.trim()) return 'learning-unit-body-required'\n if (unit.kind === 'LINK' && !/^https?:\\/\\//i.test(unit.url?.trim() ?? '')) return 'learning-unit-url-invalid'\n if (unit.minSeconds != null && (!Number.isInteger(unit.minSeconds) || unit.minSeconds < 1)) return 'learning-unit-min-time-invalid'\n if (unit.durationSeconds != null && (!Number.isInteger(unit.durationSeconds) || unit.durationSeconds < 1)) return 'learning-unit-duration-invalid'\n if (unit.pageCount != null && (!Number.isInteger(unit.pageCount) || unit.pageCount < 1)) return 'learning-unit-pages-invalid'\n return null\n}\n\nexport interface QuestionInput {\n kind: string\n text?: string | null\n choices: { text: string; correct: boolean }[]\n}\n\n/** Why a question may not be kept: its text, two choices or more (TRUE_FALSE exactly two), and the right ones its kind allows. */\nexport function questionInputRefusal(question: QuestionInput): string | null {\n if (!['SINGLE', 'MULTIPLE', 'TRUE_FALSE'].includes(question.kind)) return 'learning-question-kind-invalid'\n if (!question.text?.trim()) return 'learning-question-text-required'\n const choices = question.choices ?? []\n if (choices.length < 2 || choices.some(one => !one.text?.trim())) return 'learning-question-choices-required'\n if (question.kind === 'TRUE_FALSE' && choices.length !== 2) return 'learning-question-choices-required'\n const right = choices.filter(one => one.correct).length\n if (right === 0) return 'learning-question-answer-required'\n if (question.kind !== 'MULTIPLE' && right !== 1) return 'learning-question-one-answer'\n return null\n}\n\nexport interface PublishFacts {\n version: VersionShape\n units: { kind: string; durationSeconds?: number | null; pageCount?: number | null; hasFile: boolean }[]\n questions: { drafted: boolean }[]\n}\n\n/**\n * Why a draft may not be published (decisions 2-4): a unit or more; a video or a PDF with its file, a video with its\n * length, a PDF with its page count; a quiz with questions - as many as it draws, none of them a draft the assistant made that no manager looked over.\n */\nexport function publishRefusal({ version, units, questions }: PublishFacts): string | null {\n if (version.status !== 'DRAFT') return 'learning-version-not-draft'\n if (!units.length) return 'learning-units-required'\n for (const unit of units) {\n if ((unit.kind === 'VIDEO' || unit.kind === 'PDF') && !unit.hasFile) return 'learning-unit-file-required'\n if (unit.kind === 'VIDEO' && !unit.durationSeconds) return 'learning-unit-duration-required'\n if (unit.kind === 'PDF' && !unit.pageCount) return 'learning-unit-pages-required'\n }\n if (version.passScore != null) {\n if (!questions.length) return 'learning-questions-required'\n if (version.questionCount != null && version.questionCount > questions.length) return 'learning-question-count-too-many'\n }\n if (questions.some(one => one.drafted)) return 'learning-questions-drafted'\n return null\n}\n"]}
@@ -9,8 +9,6 @@ import { CoursePatch, CourseQuestionInput, CourseUnitInput, CourseVersionPatch,
9
9
  export declare const COURSE_UNIT_REF_TYPE = "CourseUnit";
10
10
  /** The request's transaction, or the data source's manager for a read that runs without one. */
11
11
  export declare function learningManagerOf(context: any): EntityManager;
12
- /** Whether the request holds `category` of this module (`course`, `learning`) - asked once per request. */
13
- export declare function holds(context: any, category: 'course' | 'learning', privilege?: 'query' | 'mutation'): Promise<boolean>;
14
12
  /**
15
13
  * Whether the request may read what a version says - its units and their files: a manager (`course` query) any version;
16
14
  * anyone else only the version an enrolment of theirs shows - its own once started, the published one before. Asked on
@@ -47,8 +45,11 @@ export declare function updateCourseVersion(id: string, patch: CourseVersionPatc
47
45
  * their files.
48
46
  */
49
47
  export declare function saveCourseUnits(versionId: string, units: CourseUnitInput[], context: any): Promise<CourseUnit[]>;
50
- /** A video's or a PDF's file for a unit of a draft - it replaces the one before. A video's length comes with it. */
51
- export declare function attachCourseUnitFile(unitId: string, file: any, durationSeconds: number | null | undefined, context: any): Promise<CourseUnit>;
48
+ /** A video's or a PDF's file for a unit of a draft - it replaces the one before. A video's length and a PDF's page count come with it. */
49
+ export declare function attachCourseUnitFile(unitId: string, file: any, read: {
50
+ durationSeconds?: number | null;
51
+ pageCount?: number | null;
52
+ }, context: any): Promise<CourseUnit>;
52
53
  /**
53
54
  * The questions of a draft, in the order given - saved by a manager, so each is looked over (`drafted` off). The ones
54
55
  * left out are deleted.
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.COURSE_UNIT_REF_TYPE = void 0;
4
4
  exports.learningManagerOf = learningManagerOf;
5
- exports.holds = holds;
6
5
  exports.mayReadVersion = mayReadVersion;
7
6
  exports.courseOf = courseOf;
8
7
  exports.createCourse = createCourse;
@@ -44,16 +43,6 @@ const text = (value) => (typeof value === 'string' && value.trim() ? value.trim(
44
43
  function learningManagerOf(context) {
45
44
  return context?.state?.tx ?? (0, shell_1.getRepository)(course_1.Course).manager;
46
45
  }
47
- /** Whether the request holds `category` of this module (`course`, `learning`) - asked once per request. */
48
- async function holds(context, category, privilege = 'mutation') {
49
- const state = context?.state ?? {};
50
- const { domain, user, unsafeIP, prohibitedPrivileges } = state;
51
- if (!domain || !user)
52
- return false;
53
- const key = `__learning:${category}:${privilege}`;
54
- state[key] ??= (0, auth_base_1.checkPermission)({ category, privilege, owner: true }, user, domain, unsafeIP, prohibitedPrivileges).then(Boolean);
55
- return await state[key];
56
- }
57
46
  /**
58
47
  * Whether the request may read what a version says - its units and their files: a manager (`course` query) any version;
59
48
  * anyone else only the version an enrolment of theirs shows - its own once started, the published one before. Asked on
@@ -63,7 +52,7 @@ async function holds(context, category, privilege = 'mutation') {
63
52
  async function mayReadVersion(context, version) {
64
53
  if (!version)
65
54
  return false;
66
- if (await holds(context, 'course', 'query'))
55
+ if (await (0, auth_base_1.requestHolds)(context, 'course', 'query'))
67
56
  return true;
68
57
  const { domain, user } = context?.state ?? {};
69
58
  if (!domain || !user)
@@ -203,6 +192,7 @@ async function createCourseVersion(courseId, fromId, context) {
203
192
  body: unit.body,
204
193
  url: unit.url,
205
194
  durationSeconds: unit.durationSeconds,
195
+ pageCount: unit.pageCount,
206
196
  minSeconds: unit.minSeconds,
207
197
  creator: user,
208
198
  updater: user
@@ -273,6 +263,7 @@ async function saveCourseUnits(versionId, units, context) {
273
263
  body: unit.kind === course_unit_1.CourseUnitKind.MARKDOWN ? unit.body : null,
274
264
  url: unit.kind === course_unit_1.CourseUnitKind.LINK ? unit.url?.trim() : null,
275
265
  durationSeconds: unit.kind === course_unit_1.CourseUnitKind.VIDEO ? (unit.durationSeconds ?? row.durationSeconds ?? null) : null,
266
+ pageCount: unit.kind === course_unit_1.CourseUnitKind.PDF ? (unit.pageCount ?? row.pageCount ?? null) : null,
276
267
  minSeconds: unit.kind === course_unit_1.CourseUnitKind.PDF || unit.kind === course_unit_1.CourseUnitKind.MARKDOWN ? (unit.minSeconds ?? null) : null,
277
268
  updater: user
278
269
  });
@@ -280,8 +271,9 @@ async function saveCourseUnits(versionId, units, context) {
280
271
  }
281
272
  return saved;
282
273
  }
283
- /** A video's or a PDF's file for a unit of a draft - it replaces the one before. A video's length comes with it. */
284
- async function attachCourseUnitFile(unitId, file, durationSeconds, context) {
274
+ /** A video's or a PDF's file for a unit of a draft - it replaces the one before. A video's length and a PDF's page count come with it. */
275
+ async function attachCourseUnitFile(unitId, file, read, context) {
276
+ const { durationSeconds, pageCount } = read ?? {};
285
277
  const { domain, user, tx } = context.state;
286
278
  const unit = await tx.getRepository(course_unit_1.CourseUnit).findOne({ where: { id: unitId, domain: { id: domain.id } } });
287
279
  if (!unit)
@@ -295,6 +287,10 @@ async function attachCourseUnitFile(unitId, file, durationSeconds, context) {
295
287
  refuse((0, course_rules_1.unitInputRefusal)({ kind: unit.kind, name: unit.name, durationSeconds: Math.round(durationSeconds) }));
296
288
  unit.durationSeconds = Math.round(durationSeconds);
297
289
  }
290
+ if (unit.kind === course_unit_1.CourseUnitKind.PDF && pageCount != null) {
291
+ refuse((0, course_rules_1.unitInputRefusal)({ kind: unit.kind, name: unit.name, pageCount: Math.round(pageCount) }));
292
+ unit.pageCount = Math.round(pageCount);
293
+ }
298
294
  unit.updater = user;
299
295
  return await tx.getRepository(course_unit_1.CourseUnit).save(unit);
300
296
  }
@@ -1 +1 @@
1
- {"version":3,"file":"course-service.js","sourceRoot":"","sources":["../../../server/service/course/course-service.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What the doors of courses do with the database (ADR-0194 decisions 2-4): a course, its versions written as drafts,\n * their units and questions, publishing one (the one before closes) and copying one into the next draft. Nothing here\n * changes a published version.\n */\nimport { randomUUID } from 'crypto'\nimport { Readable } from 'stream'\nimport { EntityManager, In, Not } from 'typeorm'\n\nimport { Attachment, createAttachment, deleteAttachmentsByRef, STORAGE } from '@things-factory/attachment-base'\nimport { checkPermission, User } from '@things-factory/auth-base'\nimport { getRepository, Refusal } from '@things-factory/shell'\n\nimport { Course } from './course'\nimport { CourseChoice, CourseQuestion, CourseQuestionKind } from './course-question'\nimport { publishRefusal, questionInputRefusal, unitInputRefusal, versionEditRefusal, versionInputRefusal } from './course-rules'\nimport { CourseUnit, CourseUnitKind } from './course-unit'\nimport { CourseVersion, CourseVersionStatus } from './course-version'\nimport { CoursePatch, CourseQuestionInput, CourseUnitInput, CourseVersionPatch, NewCourse } from './course-type'\n\n/** A unit's file hangs on it under this `refType` (attachment-base). */\nexport const COURSE_UNIT_REF_TYPE = 'CourseUnit'\n\nconst text = (value: unknown) => (typeof value === 'string' && value.trim() ? value.trim() : null)\n\n/** The request's transaction, or the data source's manager for a read that runs without one. */\nexport function learningManagerOf(context: any): EntityManager {\n return context?.state?.tx ?? getRepository(Course).manager\n}\n\n/** Whether the request holds `category` of this module (`course`, `learning`) - asked once per request. */\nexport async function holds(context: any, category: 'course' | 'learning', privilege: 'query' | 'mutation' = 'mutation'): Promise<boolean> {\n const state = context?.state ?? {}\n const { domain, user, unsafeIP, prohibitedPrivileges } = state\n if (!domain || !user) return false\n const key = `__learning:${category}:${privilege}`\n state[key] ??= checkPermission({ category, privilege, owner: true } as any, user, domain, unsafeIP, prohibitedPrivileges).then(Boolean)\n return await state[key]\n}\n\n/**\n * Whether the request may read what a version says - its units and their files: a manager (`course` query) any version;\n * anyone else only the version an enrolment of theirs shows - its own once started, the published one before. Asked on\n * every path to a version, not only the top-level reads: a learner reached a draft through\n * `myEnrollment → course → versions → units` (2026-11-08).\n */\nexport async function mayReadVersion(context: any, version: { id: string; courseId?: string; status: string } | null | undefined): Promise<boolean> {\n if (!version) return false\n if (await holds(context, 'course', 'query')) return true\n const { domain, user } = context?.state ?? {}\n if (!domain || !user) return false\n const state = context.state\n state.__learningShown ??= learningManagerOf(context)\n .getRepository('Enrollment')\n .find({ where: { domain: { id: domain.id }, user: { id: user.id }, status: In(['ASSIGNED', 'IN_PROGRESS', 'COMPLETED']) } as any, relations: ['course', 'version'] })\n const mine: any[] = await state.__learningShown\n return mine.some(one => one.course?.id === version.courseId && (one.version ? one.version.id === version.id : version.status === CourseVersionStatus.PUBLISHED))\n}\n\nconst notFound = () => new Refusal('learning-not-found', {}, 'the record was not found. reload and try again.')\n\nfunction refuse(code: string | null): void {\n if (code) throw new Refusal(code, {}, `refused (${code})`)\n}\n\n/* ---------------------------------------------------------------- courses */\n\nexport async function courseOf(tx: EntityManager, domain: { id: string }, id: string): Promise<Course> {\n const row = id ? await tx.getRepository(Course).findOne({ where: { id, domain: { id: domain.id } } as any }) : null\n if (!row) throw notFound()\n return row\n}\n\nasync function managerOf(tx: EntityManager, domain: any, managerId: string | null | undefined, fallback: User): Promise<User> {\n if (!managerId) return fallback\n const user = await tx.getRepository(User).findOne({ where: { id: managerId }, relations: ['domains'] })\n if (!user || !(user.domains ?? []).some(one => one.id === domain.id)) throw new Refusal('learning-manager-unknown', {}, 'the manager must be a user of this domain')\n return user\n}\n\nexport async function createCourse(input: NewCourse, context: any): Promise<Course> {\n const { domain, user, tx } = context.state\n const name = text(input.name)\n if (!name) throw new Refusal('learning-course-name-required', {}, 'give the course a name')\n if (await tx.getRepository(Course).findOne({ where: { domain: { id: domain.id }, name } as any })) throw new Refusal('learning-course-name-taken', { name }, `a course named ${name} exists`)\n return await tx.getRepository(Course).save({\n domain,\n name,\n description: text(input.description),\n category: text(input.category),\n manager: await managerOf(tx, domain, input.managerId, user),\n creator: user,\n updater: user\n } as any)\n}\n\nexport async function updateCourse(id: string, patch: CoursePatch, context: any): Promise<Course> {\n const { domain, user, tx } = context.state\n const row = await courseOf(tx, domain, id)\n if (patch.name !== undefined) {\n const name = text(patch.name)\n if (!name) throw new Refusal('learning-course-name-required', {}, 'give the course a name')\n const taken = await tx.getRepository(Course).findOne({ where: { domain: { id: domain.id }, name, id: Not(id) } as any })\n if (taken) throw new Refusal('learning-course-name-taken', { name }, `a course named ${name} exists`)\n row.name = name\n }\n if (patch.description !== undefined) row.description = text(patch.description)\n if (patch.category !== undefined) row.category = text(patch.category)\n if (patch.managerId !== undefined) row.manager = await managerOf(tx, domain, patch.managerId, user)\n row.updater = user\n return await tx.getRepository(Course).save(row)\n}\n\n/* ---------------------------------------------------------------- versions */\n\nexport async function versionOf(tx: EntityManager, domain: { id: string }, id: string): Promise<CourseVersion> {\n const row = id ? await tx.getRepository(CourseVersion).findOne({ where: { id, domain: { id: domain.id } } as any }) : null\n if (!row) throw notFound()\n return row\n}\n\n/** The version learners take now - the one published, or none. */\nexport async function publishedVersionOf(tx: EntityManager, domain: { id: string }, courseId: string): Promise<CourseVersion | null> {\n return await tx.getRepository(CourseVersion).findOne({ where: { domain: { id: domain.id }, course: { id: courseId }, status: CourseVersionStatus.PUBLISHED } as any })\n}\n\nexport async function unitsOf(tx: EntityManager, versionId: string): Promise<CourseUnit[]> {\n return await tx.getRepository(CourseUnit).find({ where: { version: { id: versionId } } as any, order: { seq: 'ASC' } as any })\n}\n\nexport async function questionsOf(tx: EntityManager, versionId: string): Promise<CourseQuestion[]> {\n return await tx.getRepository(CourseQuestion).find({ where: { version: { id: versionId } } as any, order: { seq: 'ASC' } as any })\n}\n\n/** A draft version to write in, refused while the version is published or closed (decision 2). */\nasync function draftOf(tx: EntityManager, domain: { id: string }, id: string): Promise<CourseVersion> {\n const version = await versionOf(tx, domain, id)\n refuse(versionEditRefusal(version))\n return version\n}\n\n/** The file of a unit, copied into a new file of another unit - each version keeps its own. */\nasync function copyFile(from: Attachment, toUnitId: string, context: any): Promise<void> {\n const bytes: Buffer = Buffer.from(await STORAGE.readFile(from.path))\n const file = Promise.resolve({ filename: from.name, mimetype: from.mimetype, encoding: from.encoding, createReadStream: () => Readable.from([bytes]) })\n await createAttachment(null, { attachment: { file, refType: COURSE_UNIT_REF_TYPE, refBy: toUnitId } } as any, context)\n}\n\n/**\n * A new draft of a course - the next number, with what `fromId` says copied (the latest version when not given): its\n * settings, units with their files, and questions. One draft at a time.\n */\nexport async function createCourseVersion(courseId: string, fromId: string | null | undefined, context: any): Promise<CourseVersion> {\n const { domain, user, tx } = context.state\n const course = await courseOf(tx, domain, courseId)\n const repository = (tx as EntityManager).getRepository(CourseVersion)\n const versions = await repository.find({ where: { domain: { id: domain.id }, course: { id: course.id } } as any, order: { number: 'DESC' } as any })\n if (versions.some(one => one.status === CourseVersionStatus.DRAFT)) throw new Refusal('learning-draft-exists', {}, 'the course has a draft version - write in it')\n const from = fromId ? versions.find(one => one.id === fromId) : versions[0]\n if (fromId && !from) throw notFound()\n\n const draft = await repository.save({\n domain,\n course,\n number: (versions[0]?.number ?? 0) + 1,\n status: CourseVersionStatus.DRAFT,\n minSeconds: from?.minSeconds ?? 0,\n acknowledgement: from?.acknowledgement ?? null,\n passScore: from?.passScore ?? null,\n questionCount: from?.questionCount ?? null,\n attemptLimit: from?.attemptLimit ?? null,\n sourceKind: from?.sourceKind ?? null,\n sourceNote: from?.sourceNote ?? null,\n creator: user,\n updater: user\n } as any)\n if (!from) return draft\n\n for (const unit of await unitsOf(tx, from.id)) {\n const copy = await tx.getRepository(CourseUnit).save({\n domain,\n version: draft,\n seq: unit.seq,\n kind: unit.kind,\n name: unit.name,\n body: unit.body,\n url: unit.url,\n durationSeconds: unit.durationSeconds,\n minSeconds: unit.minSeconds,\n creator: user,\n updater: user\n } as any)\n const file = await tx.getRepository(Attachment).findOne({ where: { domain: { id: domain.id }, refType: COURSE_UNIT_REF_TYPE, refBy: unit.id } as any })\n if (file) await copyFile(file, copy.id, context)\n }\n for (const question of await questionsOf(tx, from.id)) {\n await tx.getRepository(CourseQuestion).save({\n domain,\n version: draft,\n seq: question.seq,\n kind: question.kind,\n text: question.text,\n choices: question.choices,\n explanation: question.explanation,\n drafted: question.drafted,\n creator: user,\n updater: user\n } as any)\n }\n return draft\n}\n\nexport async function updateCourseVersion(id: string, patch: CourseVersionPatch, context: any): Promise<CourseVersion> {\n const { domain, user, tx } = context.state\n const version = await draftOf(tx, domain, id)\n const next = { ...version, ...Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined)) } as CourseVersion\n refuse(versionInputRefusal(next))\n for (const field of ['minSeconds', 'passScore', 'questionCount', 'attemptLimit', 'sourceKind'] as const) if (patch[field] !== undefined) (version as any)[field] = patch[field]\n if (patch.minSeconds === null) version.minSeconds = 0\n if (patch.acknowledgement !== undefined) version.acknowledgement = text(patch.acknowledgement)\n if (patch.sourceNote !== undefined) version.sourceNote = text(patch.sourceNote)\n version.updater = user\n return await tx.getRepository(CourseVersion).save(version)\n}\n\n/**\n * The units of a draft, in the order given - new ones made, the ones given changed, the ones left out deleted with\n * their files.\n */\nexport async function saveCourseUnits(versionId: string, units: CourseUnitInput[], context: any): Promise<CourseUnit[]> {\n const { domain, user, tx } = context.state\n const version = await draftOf(tx, domain, versionId)\n for (const unit of units) refuse(unitInputRefusal(unit))\n const repository = (tx as EntityManager).getRepository(CourseUnit)\n const existing = await unitsOf(tx, version.id)\n const kept = new Set(units.map(one => one.id).filter(Boolean))\n if ([...kept].some(id => !existing.some(one => one.id === id))) throw notFound()\n\n const gone = existing.filter(one => !kept.has(one.id))\n if (gone.length) {\n await deleteAttachmentsByRef(null, { refBys: gone.map(one => one.id), refType: COURSE_UNIT_REF_TYPE }, context)\n await repository.softDelete({ id: In(gone.map(one => one.id)) })\n }\n const saved: CourseUnit[] = []\n for (const [index, unit] of units.entries()) {\n const row: any = unit.id ? existing.find(one => one.id === unit.id) : repository.create({ domain, version, creator: user } as any)\n Object.assign(row, {\n seq: index + 1,\n kind: unit.kind,\n name: unit.name.trim(),\n body: unit.kind === CourseUnitKind.MARKDOWN ? unit.body : null,\n url: unit.kind === CourseUnitKind.LINK ? unit.url?.trim() : null,\n durationSeconds: unit.kind === CourseUnitKind.VIDEO ? (unit.durationSeconds ?? row.durationSeconds ?? null) : null,\n minSeconds: unit.kind === CourseUnitKind.PDF || unit.kind === CourseUnitKind.MARKDOWN ? (unit.minSeconds ?? null) : null,\n updater: user\n })\n saved.push(await repository.save(row))\n }\n return saved\n}\n\n/** A video's or a PDF's file for a unit of a draft - it replaces the one before. A video's length comes with it. */\nexport async function attachCourseUnitFile(unitId: string, file: any, durationSeconds: number | null | undefined, context: any): Promise<CourseUnit> {\n const { domain, user, tx } = context.state\n const unit = await (tx as EntityManager).getRepository(CourseUnit).findOne({ where: { id: unitId, domain: { id: domain.id } } as any })\n if (!unit) throw notFound()\n await draftOf(tx, domain, unit.versionId!)\n if (unit.kind !== CourseUnitKind.VIDEO && unit.kind !== CourseUnitKind.PDF) throw new Refusal('learning-unit-file-not-taken', {}, 'only a video or a PDF unit takes a file')\n await deleteAttachmentsByRef(null, { refBys: [unit.id], refType: COURSE_UNIT_REF_TYPE }, context)\n await createAttachment(null, { attachment: { file, refType: COURSE_UNIT_REF_TYPE, refBy: unit.id } } as any, context)\n if (unit.kind === CourseUnitKind.VIDEO && durationSeconds != null) {\n refuse(unitInputRefusal({ kind: unit.kind, name: unit.name, durationSeconds: Math.round(durationSeconds) }))\n unit.durationSeconds = Math.round(durationSeconds)\n }\n unit.updater = user\n return await tx.getRepository(CourseUnit).save(unit)\n}\n\n/** The choices kept with their ids - an id given stays, a new choice gets one. */\nconst choicesOf = (input: CourseQuestionInput): CourseChoice[] => input.choices.map(one => ({ id: one.id || randomUUID(), text: one.text.trim(), correct: !!one.correct }))\n\n/**\n * The questions of a draft, in the order given - saved by a manager, so each is looked over (`drafted` off). The ones\n * left out are deleted.\n */\nexport async function saveCourseQuestions(versionId: string, questions: CourseQuestionInput[], context: any): Promise<CourseQuestion[]> {\n const { domain, user, tx } = context.state\n const version = await draftOf(tx, domain, versionId)\n for (const question of questions) refuse(questionInputRefusal(question))\n const repository = (tx as EntityManager).getRepository(CourseQuestion)\n const existing = await questionsOf(tx, version.id)\n const kept = new Set(questions.map(one => one.id).filter(Boolean))\n if ([...kept].some(id => !existing.some(one => one.id === id))) throw notFound()\n const gone = existing.filter(one => !kept.has(one.id))\n if (gone.length) await repository.softDelete({ id: In(gone.map(one => one.id)) })\n const saved: CourseQuestion[] = []\n for (const [index, question] of questions.entries()) {\n const row: any = question.id ? existing.find(one => one.id === question.id) : repository.create({ domain, version, creator: user } as any)\n Object.assign(row, { seq: index + 1, kind: question.kind, text: question.text.trim(), choices: choicesOf(question), explanation: text(question.explanation), drafted: false, updater: user })\n saved.push(await repository.save(row))\n }\n return saved\n}\n\n/** Questions the assistant drafted, added at the end of a draft - each `drafted` until a manager looks it over (decision 12). */\nexport async function addDraftedQuestions(versionId: string, questions: CourseQuestionInput[], context: any): Promise<CourseQuestion[]> {\n const { domain, user, tx } = context.state\n const version = await draftOf(tx, domain, versionId)\n const valid = questions.filter(one => !questionInputRefusal(one))\n const last = (await questionsOf(tx, version.id)).reduce((max, one) => Math.max(max, one.seq), 0)\n const saved: CourseQuestion[] = []\n for (const [index, question] of valid.entries()) {\n saved.push(\n await tx.getRepository(CourseQuestion).save({\n domain,\n version,\n seq: last + index + 1,\n kind: question.kind as CourseQuestionKind,\n text: question.text.trim(),\n choices: choicesOf(question),\n explanation: text(question.explanation),\n drafted: true,\n creator: user,\n updater: user\n } as any)\n )\n }\n return saved\n}\n\n/**\n * Publishes a draft: what it says is checked (decisions 2-4), it is claimed by an update that only a draft matches -\n * two at once publish once - and the version published before closes. Enrolments in progress end on their own version.\n */\nexport async function publishCourseVersion(id: string, context: any): Promise<CourseVersion> {\n const { domain, user, tx } = context.state\n const version = await versionOf(tx, domain, id)\n const units = await unitsOf(tx, version.id)\n const files = units.length\n ? await tx.getRepository(Attachment).find({ where: { domain: { id: domain.id }, refType: COURSE_UNIT_REF_TYPE, refBy: In(units.map(one => one.id)) } as any })\n : []\n const questions = await questionsOf(tx, version.id)\n refuse(publishRefusal({ version, units: units.map(one => ({ ...one, hasFile: files.some(file => file.refBy === one.id) })), questions }))\n\n const now = new Date()\n const claimed = await tx.getRepository(CourseVersion).update({ id: version.id, status: CourseVersionStatus.DRAFT } as any, { status: CourseVersionStatus.PUBLISHED, publishedAt: now, updater: user } as any)\n if (!claimed.affected) throw new Refusal('learning-version-not-draft', {}, 'the version is not a draft any more')\n await tx\n .getRepository(CourseVersion)\n .update({ domain: { id: domain.id }, course: { id: version.courseId }, status: CourseVersionStatus.PUBLISHED, id: Not(version.id) } as any, { status: CourseVersionStatus.CLOSED, closedAt: now, updater: user } as any)\n return await versionOf(tx, domain, version.id)\n}\n\n/** Closes the published version - nobody starts it any more; those who started end on it. */\nexport async function closeCourseVersion(id: string, context: any): Promise<CourseVersion> {\n const { domain, user, tx } = context.state\n const version = await versionOf(tx, domain, id)\n const claimed = await tx.getRepository(CourseVersion).update({ id: version.id, status: CourseVersionStatus.PUBLISHED } as any, { status: CourseVersionStatus.CLOSED, closedAt: new Date(), updater: user } as any)\n if (!claimed.affected) throw new Refusal('learning-version-not-published', {}, 'only the published version is closed')\n return await versionOf(tx, domain, version.id)\n}\n\n/** A draft no learner saw is deleted with its units, their files and its questions. */\nexport async function deleteCourseVersion(id: string, context: any): Promise<boolean> {\n const { domain, tx } = context.state\n const version = await draftOf(tx, domain, id)\n const units = await unitsOf(tx, version.id)\n if (units.length) {\n await deleteAttachmentsByRef(null, { refBys: units.map(one => one.id), refType: COURSE_UNIT_REF_TYPE }, context)\n await tx.getRepository(CourseUnit).softDelete({ id: In(units.map(one => one.id)) })\n }\n await tx.getRepository(CourseQuestion).softDelete({ version: { id: version.id } } as any)\n await tx.getRepository(CourseVersion).softDelete({ id: version.id })\n return true\n}\n\n/** The file of each unit given - for a video's or a PDF's address. */\nexport async function unitFilesOf(domain: { id: string }, unitIds: string[]): Promise<Map<string, Attachment>> {\n if (!unitIds.length) return new Map()\n const rows = await getRepository(Attachment).find({ where: { domain: { id: domain.id }, refType: COURSE_UNIT_REF_TYPE, refBy: In(unitIds) } as any })\n return new Map(rows.map(one => [one.refBy!, one]))\n}\n\n"]}
1
+ {"version":3,"file":"course-service.js","sourceRoot":"","sources":["../../../server/service/course/course-service.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What the doors of courses do with the database (ADR-0194 decisions 2-4): a course, its versions written as drafts,\n * their units and questions, publishing one (the one before closes) and copying one into the next draft. Nothing here\n * changes a published version.\n */\nimport { randomUUID } from 'crypto'\nimport { Readable } from 'stream'\nimport { EntityManager, In, Not } from 'typeorm'\n\nimport { Attachment, createAttachment, deleteAttachmentsByRef, STORAGE } from '@things-factory/attachment-base'\nimport { requestHolds, User } from '@things-factory/auth-base'\nimport { getRepository, Refusal } from '@things-factory/shell'\n\nimport { Course } from './course'\nimport { CourseChoice, CourseQuestion, CourseQuestionKind } from './course-question'\nimport { publishRefusal, questionInputRefusal, unitInputRefusal, versionEditRefusal, versionInputRefusal } from './course-rules'\nimport { CourseUnit, CourseUnitKind } from './course-unit'\nimport { CourseVersion, CourseVersionStatus } from './course-version'\nimport { CoursePatch, CourseQuestionInput, CourseUnitInput, CourseVersionPatch, NewCourse } from './course-type'\n\n/** A unit's file hangs on it under this `refType` (attachment-base). */\nexport const COURSE_UNIT_REF_TYPE = 'CourseUnit'\n\nconst text = (value: unknown) => (typeof value === 'string' && value.trim() ? value.trim() : null)\n\n/** The request's transaction, or the data source's manager for a read that runs without one. */\nexport function learningManagerOf(context: any): EntityManager {\n return context?.state?.tx ?? getRepository(Course).manager\n}\n\n/**\n * Whether the request may read what a version says - its units and their files: a manager (`course` query) any version;\n * anyone else only the version an enrolment of theirs shows - its own once started, the published one before. Asked on\n * every path to a version, not only the top-level reads: a learner reached a draft through\n * `myEnrollment → course → versions → units` (2026-11-08).\n */\nexport async function mayReadVersion(context: any, version: { id: string; courseId?: string; status: string } | null | undefined): Promise<boolean> {\n if (!version) return false\n if (await requestHolds(context, 'course', 'query')) return true\n const { domain, user } = context?.state ?? {}\n if (!domain || !user) return false\n const state = context.state\n state.__learningShown ??= learningManagerOf(context)\n .getRepository('Enrollment')\n .find({ where: { domain: { id: domain.id }, user: { id: user.id }, status: In(['ASSIGNED', 'IN_PROGRESS', 'COMPLETED']) } as any, relations: ['course', 'version'] })\n const mine: any[] = await state.__learningShown\n return mine.some(one => one.course?.id === version.courseId && (one.version ? one.version.id === version.id : version.status === CourseVersionStatus.PUBLISHED))\n}\n\nconst notFound = () => new Refusal('learning-not-found', {}, 'the record was not found. reload and try again.')\n\nfunction refuse(code: string | null): void {\n if (code) throw new Refusal(code, {}, `refused (${code})`)\n}\n\n/* ---------------------------------------------------------------- courses */\n\nexport async function courseOf(tx: EntityManager, domain: { id: string }, id: string): Promise<Course> {\n const row = id ? await tx.getRepository(Course).findOne({ where: { id, domain: { id: domain.id } } as any }) : null\n if (!row) throw notFound()\n return row\n}\n\nasync function managerOf(tx: EntityManager, domain: any, managerId: string | null | undefined, fallback: User): Promise<User> {\n if (!managerId) return fallback\n const user = await tx.getRepository(User).findOne({ where: { id: managerId }, relations: ['domains'] })\n if (!user || !(user.domains ?? []).some(one => one.id === domain.id)) throw new Refusal('learning-manager-unknown', {}, 'the manager must be a user of this domain')\n return user\n}\n\nexport async function createCourse(input: NewCourse, context: any): Promise<Course> {\n const { domain, user, tx } = context.state\n const name = text(input.name)\n if (!name) throw new Refusal('learning-course-name-required', {}, 'give the course a name')\n if (await tx.getRepository(Course).findOne({ where: { domain: { id: domain.id }, name } as any })) throw new Refusal('learning-course-name-taken', { name }, `a course named ${name} exists`)\n return await tx.getRepository(Course).save({\n domain,\n name,\n description: text(input.description),\n category: text(input.category),\n manager: await managerOf(tx, domain, input.managerId, user),\n creator: user,\n updater: user\n } as any)\n}\n\nexport async function updateCourse(id: string, patch: CoursePatch, context: any): Promise<Course> {\n const { domain, user, tx } = context.state\n const row = await courseOf(tx, domain, id)\n if (patch.name !== undefined) {\n const name = text(patch.name)\n if (!name) throw new Refusal('learning-course-name-required', {}, 'give the course a name')\n const taken = await tx.getRepository(Course).findOne({ where: { domain: { id: domain.id }, name, id: Not(id) } as any })\n if (taken) throw new Refusal('learning-course-name-taken', { name }, `a course named ${name} exists`)\n row.name = name\n }\n if (patch.description !== undefined) row.description = text(patch.description)\n if (patch.category !== undefined) row.category = text(patch.category)\n if (patch.managerId !== undefined) row.manager = await managerOf(tx, domain, patch.managerId, user)\n row.updater = user\n return await tx.getRepository(Course).save(row)\n}\n\n/* ---------------------------------------------------------------- versions */\n\nexport async function versionOf(tx: EntityManager, domain: { id: string }, id: string): Promise<CourseVersion> {\n const row = id ? await tx.getRepository(CourseVersion).findOne({ where: { id, domain: { id: domain.id } } as any }) : null\n if (!row) throw notFound()\n return row\n}\n\n/** The version learners take now - the one published, or none. */\nexport async function publishedVersionOf(tx: EntityManager, domain: { id: string }, courseId: string): Promise<CourseVersion | null> {\n return await tx.getRepository(CourseVersion).findOne({ where: { domain: { id: domain.id }, course: { id: courseId }, status: CourseVersionStatus.PUBLISHED } as any })\n}\n\nexport async function unitsOf(tx: EntityManager, versionId: string): Promise<CourseUnit[]> {\n return await tx.getRepository(CourseUnit).find({ where: { version: { id: versionId } } as any, order: { seq: 'ASC' } as any })\n}\n\nexport async function questionsOf(tx: EntityManager, versionId: string): Promise<CourseQuestion[]> {\n return await tx.getRepository(CourseQuestion).find({ where: { version: { id: versionId } } as any, order: { seq: 'ASC' } as any })\n}\n\n/** A draft version to write in, refused while the version is published or closed (decision 2). */\nasync function draftOf(tx: EntityManager, domain: { id: string }, id: string): Promise<CourseVersion> {\n const version = await versionOf(tx, domain, id)\n refuse(versionEditRefusal(version))\n return version\n}\n\n/** The file of a unit, copied into a new file of another unit - each version keeps its own. */\nasync function copyFile(from: Attachment, toUnitId: string, context: any): Promise<void> {\n const bytes: Buffer = Buffer.from(await STORAGE.readFile(from.path))\n const file = Promise.resolve({ filename: from.name, mimetype: from.mimetype, encoding: from.encoding, createReadStream: () => Readable.from([bytes]) })\n await createAttachment(null, { attachment: { file, refType: COURSE_UNIT_REF_TYPE, refBy: toUnitId } } as any, context)\n}\n\n/**\n * A new draft of a course - the next number, with what `fromId` says copied (the latest version when not given): its\n * settings, units with their files, and questions. One draft at a time.\n */\nexport async function createCourseVersion(courseId: string, fromId: string | null | undefined, context: any): Promise<CourseVersion> {\n const { domain, user, tx } = context.state\n const course = await courseOf(tx, domain, courseId)\n const repository = (tx as EntityManager).getRepository(CourseVersion)\n const versions = await repository.find({ where: { domain: { id: domain.id }, course: { id: course.id } } as any, order: { number: 'DESC' } as any })\n if (versions.some(one => one.status === CourseVersionStatus.DRAFT)) throw new Refusal('learning-draft-exists', {}, 'the course has a draft version - write in it')\n const from = fromId ? versions.find(one => one.id === fromId) : versions[0]\n if (fromId && !from) throw notFound()\n\n const draft = await repository.save({\n domain,\n course,\n number: (versions[0]?.number ?? 0) + 1,\n status: CourseVersionStatus.DRAFT,\n minSeconds: from?.minSeconds ?? 0,\n acknowledgement: from?.acknowledgement ?? null,\n passScore: from?.passScore ?? null,\n questionCount: from?.questionCount ?? null,\n attemptLimit: from?.attemptLimit ?? null,\n sourceKind: from?.sourceKind ?? null,\n sourceNote: from?.sourceNote ?? null,\n creator: user,\n updater: user\n } as any)\n if (!from) return draft\n\n for (const unit of await unitsOf(tx, from.id)) {\n const copy = await tx.getRepository(CourseUnit).save({\n domain,\n version: draft,\n seq: unit.seq,\n kind: unit.kind,\n name: unit.name,\n body: unit.body,\n url: unit.url,\n durationSeconds: unit.durationSeconds,\n pageCount: unit.pageCount,\n minSeconds: unit.minSeconds,\n creator: user,\n updater: user\n } as any)\n const file = await tx.getRepository(Attachment).findOne({ where: { domain: { id: domain.id }, refType: COURSE_UNIT_REF_TYPE, refBy: unit.id } as any })\n if (file) await copyFile(file, copy.id, context)\n }\n for (const question of await questionsOf(tx, from.id)) {\n await tx.getRepository(CourseQuestion).save({\n domain,\n version: draft,\n seq: question.seq,\n kind: question.kind,\n text: question.text,\n choices: question.choices,\n explanation: question.explanation,\n drafted: question.drafted,\n creator: user,\n updater: user\n } as any)\n }\n return draft\n}\n\nexport async function updateCourseVersion(id: string, patch: CourseVersionPatch, context: any): Promise<CourseVersion> {\n const { domain, user, tx } = context.state\n const version = await draftOf(tx, domain, id)\n const next = { ...version, ...Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined)) } as CourseVersion\n refuse(versionInputRefusal(next))\n for (const field of ['minSeconds', 'passScore', 'questionCount', 'attemptLimit', 'sourceKind'] as const) if (patch[field] !== undefined) (version as any)[field] = patch[field]\n if (patch.minSeconds === null) version.minSeconds = 0\n if (patch.acknowledgement !== undefined) version.acknowledgement = text(patch.acknowledgement)\n if (patch.sourceNote !== undefined) version.sourceNote = text(patch.sourceNote)\n version.updater = user\n return await tx.getRepository(CourseVersion).save(version)\n}\n\n/**\n * The units of a draft, in the order given - new ones made, the ones given changed, the ones left out deleted with\n * their files.\n */\nexport async function saveCourseUnits(versionId: string, units: CourseUnitInput[], context: any): Promise<CourseUnit[]> {\n const { domain, user, tx } = context.state\n const version = await draftOf(tx, domain, versionId)\n for (const unit of units) refuse(unitInputRefusal(unit))\n const repository = (tx as EntityManager).getRepository(CourseUnit)\n const existing = await unitsOf(tx, version.id)\n const kept = new Set(units.map(one => one.id).filter(Boolean))\n if ([...kept].some(id => !existing.some(one => one.id === id))) throw notFound()\n\n const gone = existing.filter(one => !kept.has(one.id))\n if (gone.length) {\n await deleteAttachmentsByRef(null, { refBys: gone.map(one => one.id), refType: COURSE_UNIT_REF_TYPE }, context)\n await repository.softDelete({ id: In(gone.map(one => one.id)) })\n }\n const saved: CourseUnit[] = []\n for (const [index, unit] of units.entries()) {\n const row: any = unit.id ? existing.find(one => one.id === unit.id) : repository.create({ domain, version, creator: user } as any)\n Object.assign(row, {\n seq: index + 1,\n kind: unit.kind,\n name: unit.name.trim(),\n body: unit.kind === CourseUnitKind.MARKDOWN ? unit.body : null,\n url: unit.kind === CourseUnitKind.LINK ? unit.url?.trim() : null,\n durationSeconds: unit.kind === CourseUnitKind.VIDEO ? (unit.durationSeconds ?? row.durationSeconds ?? null) : null,\n pageCount: unit.kind === CourseUnitKind.PDF ? (unit.pageCount ?? row.pageCount ?? null) : null,\n minSeconds: unit.kind === CourseUnitKind.PDF || unit.kind === CourseUnitKind.MARKDOWN ? (unit.minSeconds ?? null) : null,\n updater: user\n })\n saved.push(await repository.save(row))\n }\n return saved\n}\n\n/** A video's or a PDF's file for a unit of a draft - it replaces the one before. A video's length and a PDF's page count come with it. */\nexport async function attachCourseUnitFile(\n unitId: string,\n file: any,\n read: { durationSeconds?: number | null; pageCount?: number | null },\n context: any\n): Promise<CourseUnit> {\n const { durationSeconds, pageCount } = read ?? {}\n const { domain, user, tx } = context.state\n const unit = await (tx as EntityManager).getRepository(CourseUnit).findOne({ where: { id: unitId, domain: { id: domain.id } } as any })\n if (!unit) throw notFound()\n await draftOf(tx, domain, unit.versionId!)\n if (unit.kind !== CourseUnitKind.VIDEO && unit.kind !== CourseUnitKind.PDF) throw new Refusal('learning-unit-file-not-taken', {}, 'only a video or a PDF unit takes a file')\n await deleteAttachmentsByRef(null, { refBys: [unit.id], refType: COURSE_UNIT_REF_TYPE }, context)\n await createAttachment(null, { attachment: { file, refType: COURSE_UNIT_REF_TYPE, refBy: unit.id } } as any, context)\n if (unit.kind === CourseUnitKind.VIDEO && durationSeconds != null) {\n refuse(unitInputRefusal({ kind: unit.kind, name: unit.name, durationSeconds: Math.round(durationSeconds) }))\n unit.durationSeconds = Math.round(durationSeconds)\n }\n if (unit.kind === CourseUnitKind.PDF && pageCount != null) {\n refuse(unitInputRefusal({ kind: unit.kind, name: unit.name, pageCount: Math.round(pageCount) }))\n unit.pageCount = Math.round(pageCount)\n }\n unit.updater = user\n return await tx.getRepository(CourseUnit).save(unit)\n}\n\n/** The choices kept with their ids - an id given stays, a new choice gets one. */\nconst choicesOf = (input: CourseQuestionInput): CourseChoice[] => input.choices.map(one => ({ id: one.id || randomUUID(), text: one.text.trim(), correct: !!one.correct }))\n\n/**\n * The questions of a draft, in the order given - saved by a manager, so each is looked over (`drafted` off). The ones\n * left out are deleted.\n */\nexport async function saveCourseQuestions(versionId: string, questions: CourseQuestionInput[], context: any): Promise<CourseQuestion[]> {\n const { domain, user, tx } = context.state\n const version = await draftOf(tx, domain, versionId)\n for (const question of questions) refuse(questionInputRefusal(question))\n const repository = (tx as EntityManager).getRepository(CourseQuestion)\n const existing = await questionsOf(tx, version.id)\n const kept = new Set(questions.map(one => one.id).filter(Boolean))\n if ([...kept].some(id => !existing.some(one => one.id === id))) throw notFound()\n const gone = existing.filter(one => !kept.has(one.id))\n if (gone.length) await repository.softDelete({ id: In(gone.map(one => one.id)) })\n const saved: CourseQuestion[] = []\n for (const [index, question] of questions.entries()) {\n const row: any = question.id ? existing.find(one => one.id === question.id) : repository.create({ domain, version, creator: user } as any)\n Object.assign(row, { seq: index + 1, kind: question.kind, text: question.text.trim(), choices: choicesOf(question), explanation: text(question.explanation), drafted: false, updater: user })\n saved.push(await repository.save(row))\n }\n return saved\n}\n\n/** Questions the assistant drafted, added at the end of a draft - each `drafted` until a manager looks it over (decision 12). */\nexport async function addDraftedQuestions(versionId: string, questions: CourseQuestionInput[], context: any): Promise<CourseQuestion[]> {\n const { domain, user, tx } = context.state\n const version = await draftOf(tx, domain, versionId)\n const valid = questions.filter(one => !questionInputRefusal(one))\n const last = (await questionsOf(tx, version.id)).reduce((max, one) => Math.max(max, one.seq), 0)\n const saved: CourseQuestion[] = []\n for (const [index, question] of valid.entries()) {\n saved.push(\n await tx.getRepository(CourseQuestion).save({\n domain,\n version,\n seq: last + index + 1,\n kind: question.kind as CourseQuestionKind,\n text: question.text.trim(),\n choices: choicesOf(question),\n explanation: text(question.explanation),\n drafted: true,\n creator: user,\n updater: user\n } as any)\n )\n }\n return saved\n}\n\n/**\n * Publishes a draft: what it says is checked (decisions 2-4), it is claimed by an update that only a draft matches -\n * two at once publish once - and the version published before closes. Enrolments in progress end on their own version.\n */\nexport async function publishCourseVersion(id: string, context: any): Promise<CourseVersion> {\n const { domain, user, tx } = context.state\n const version = await versionOf(tx, domain, id)\n const units = await unitsOf(tx, version.id)\n const files = units.length\n ? await tx.getRepository(Attachment).find({ where: { domain: { id: domain.id }, refType: COURSE_UNIT_REF_TYPE, refBy: In(units.map(one => one.id)) } as any })\n : []\n const questions = await questionsOf(tx, version.id)\n refuse(publishRefusal({ version, units: units.map(one => ({ ...one, hasFile: files.some(file => file.refBy === one.id) })), questions }))\n\n const now = new Date()\n const claimed = await tx.getRepository(CourseVersion).update({ id: version.id, status: CourseVersionStatus.DRAFT } as any, { status: CourseVersionStatus.PUBLISHED, publishedAt: now, updater: user } as any)\n if (!claimed.affected) throw new Refusal('learning-version-not-draft', {}, 'the version is not a draft any more')\n await tx\n .getRepository(CourseVersion)\n .update({ domain: { id: domain.id }, course: { id: version.courseId }, status: CourseVersionStatus.PUBLISHED, id: Not(version.id) } as any, { status: CourseVersionStatus.CLOSED, closedAt: now, updater: user } as any)\n return await versionOf(tx, domain, version.id)\n}\n\n/** Closes the published version - nobody starts it any more; those who started end on it. */\nexport async function closeCourseVersion(id: string, context: any): Promise<CourseVersion> {\n const { domain, user, tx } = context.state\n const version = await versionOf(tx, domain, id)\n const claimed = await tx.getRepository(CourseVersion).update({ id: version.id, status: CourseVersionStatus.PUBLISHED } as any, { status: CourseVersionStatus.CLOSED, closedAt: new Date(), updater: user } as any)\n if (!claimed.affected) throw new Refusal('learning-version-not-published', {}, 'only the published version is closed')\n return await versionOf(tx, domain, version.id)\n}\n\n/** A draft no learner saw is deleted with its units, their files and its questions. */\nexport async function deleteCourseVersion(id: string, context: any): Promise<boolean> {\n const { domain, tx } = context.state\n const version = await draftOf(tx, domain, id)\n const units = await unitsOf(tx, version.id)\n if (units.length) {\n await deleteAttachmentsByRef(null, { refBys: units.map(one => one.id), refType: COURSE_UNIT_REF_TYPE }, context)\n await tx.getRepository(CourseUnit).softDelete({ id: In(units.map(one => one.id)) })\n }\n await tx.getRepository(CourseQuestion).softDelete({ version: { id: version.id } } as any)\n await tx.getRepository(CourseVersion).softDelete({ id: version.id })\n return true\n}\n\n/** The file of each unit given - for a video's or a PDF's address. */\nexport async function unitFilesOf(domain: { id: string }, unitIds: string[]): Promise<Map<string, Attachment>> {\n if (!unitIds.length) return new Map()\n const rows = await getRepository(Attachment).find({ where: { domain: { id: domain.id }, refType: COURSE_UNIT_REF_TYPE, refBy: In(unitIds) } as any })\n return new Map(rows.map(one => [one.refBy!, one]))\n}\n\n"]}
@@ -30,6 +30,7 @@ export declare class CourseUnitInput {
30
30
  body?: string;
31
31
  url?: string;
32
32
  durationSeconds?: number;
33
+ pageCount?: number;
33
34
  minSeconds?: number;
34
35
  }
35
36
  export declare class CourseChoiceInput {
@@ -112,6 +112,10 @@ tslib_1.__decorate([
112
112
  (0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: "The video's length in seconds, read from the file." }),
113
113
  tslib_1.__metadata("design:type", Number)
114
114
  ], CourseUnitInput.prototype, "durationSeconds", void 0);
115
+ tslib_1.__decorate([
116
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: "A PDF's page count, read from the file." }),
117
+ tslib_1.__metadata("design:type", Number)
118
+ ], CourseUnitInput.prototype, "pageCount", void 0);
115
119
  tslib_1.__decorate([
116
120
  (0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: 'Seconds a PDF or a text is looked at to be done - 60 when empty.' }),
117
121
  tslib_1.__metadata("design:type", Number)
@@ -1 +1 @@
1
- {"version":3,"file":"course-type.js","sourceRoot":"","sources":["../../../server/service/course/course-type.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, InputType, Int, ObjectType } from 'type-graphql'\n\nimport { Course } from './course'\nimport { CourseQuestionKind } from './course-question'\nimport { CourseUnitKind } from './course-unit'\nimport { CourseSourceKind } from './course-version'\n\n@InputType({ description: 'A course to make' })\nexport class NewCourse {\n @Field({ description: 'What it is called.' })\n name: string\n\n @Field({ nullable: true, description: 'What it is about.' })\n description?: string\n\n @Field({ nullable: true, description: 'Its category.' })\n category?: string\n\n @Field({ nullable: true, description: 'The user who keeps it - the one making it when empty.' })\n managerId?: string\n}\n\n@InputType({ description: 'What a course says, changed' })\nexport class CoursePatch {\n @Field({ nullable: true, description: 'What it is called.' })\n name?: string\n\n @Field({ nullable: true, description: 'What it is about.' })\n description?: string\n\n @Field({ nullable: true, description: 'Its category.' })\n category?: string\n\n @Field({ nullable: true, description: 'The user who keeps it.' })\n managerId?: string\n}\n\n@InputType({ description: 'What a draft version says, changed' })\nexport class CourseVersionPatch {\n @Field(type => Int, { nullable: true, description: 'The least time in seconds.' })\n minSeconds?: number\n\n @Field({ nullable: true, description: 'What the learner confirms - nothing asked when empty.' })\n acknowledgement?: string\n\n @Field(type => Int, { nullable: true, description: 'The pass score out of 100 - no quiz when empty.' })\n passScore?: number\n\n @Field(type => Int, { nullable: true, description: 'How many questions an attempt draws - all when empty.' })\n questionCount?: number\n\n @Field(type => Int, { nullable: true, description: 'How many attempts a learner has - no limit when empty.' })\n attemptLimit?: number\n\n @Field(type => CourseSourceKind, { nullable: true, description: 'Where its material came from.' })\n sourceKind?: CourseSourceKind\n\n @Field({ nullable: true, description: 'Who gave the material and on what terms.' })\n sourceNote?: string\n}\n\n@InputType({ description: 'A unit of a draft version, new (no id) or changed' })\nexport class CourseUnitInput {\n @Field({ nullable: true, description: 'The unit to change - a new one when empty.' })\n id?: string\n\n @Field(type => CourseUnitKind, { description: 'What it is.' })\n kind: CourseUnitKind\n\n @Field({ description: 'What it is called.' })\n name: string\n\n @Field({ nullable: true, description: 'The text in markdown - a MARKDOWN unit.' })\n body?: string\n\n @Field({ nullable: true, description: 'The address - a LINK unit.' })\n url?: string\n\n @Field(type => Int, { nullable: true, description: \"The video's length in seconds, read from the file.\" })\n durationSeconds?: number\n\n @Field(type => Int, { nullable: true, description: 'Seconds a PDF or a text is looked at to be done - 60 when empty.' })\n minSeconds?: number\n}\n\n@InputType({ description: 'A choice of a question, with whether it is right' })\nexport class CourseChoiceInput {\n @Field({ nullable: true, description: 'The choice id - kept when the question is changed.' })\n id?: string\n\n @Field({ description: 'What it says.' })\n text: string\n\n @Field({ description: 'Whether it is right.' })\n correct: boolean\n}\n\n@InputType({ description: 'A question of a draft version, new (no id) or changed' })\nexport class CourseQuestionInput {\n @Field({ nullable: true, description: 'The question to change - a new one when empty.' })\n id?: string\n\n @Field(type => CourseQuestionKind, { description: 'How it is answered.' })\n kind: CourseQuestionKind\n\n @Field({ description: 'What it asks.' })\n text: string\n\n @Field(type => [CourseChoiceInput], { description: 'Its choices.' })\n choices: CourseChoiceInput[]\n\n @Field({ nullable: true, description: 'Why the answer is what it is.' })\n explanation?: string\n}\n\n@ObjectType({ description: 'A choice of a question as a manager reads it - with whether it is right' })\nexport class CourseChoiceKey {\n @Field({ description: 'The choice id.' })\n id: string\n\n @Field({ description: 'What it says.' })\n text: string\n\n @Field({ description: 'Whether it is right.' })\n correct: boolean\n}\n\n@ObjectType({ description: 'A page of courses' })\nexport class CourseList {\n @Field(type => [Course], { description: 'The courses.' })\n items: Course[]\n\n @Field(type => Int, { description: 'How many there are.' })\n total: number\n}\n"]}
1
+ {"version":3,"file":"course-type.js","sourceRoot":"","sources":["../../../server/service/course/course-type.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, InputType, Int, ObjectType } from 'type-graphql'\n\nimport { Course } from './course'\nimport { CourseQuestionKind } from './course-question'\nimport { CourseUnitKind } from './course-unit'\nimport { CourseSourceKind } from './course-version'\n\n@InputType({ description: 'A course to make' })\nexport class NewCourse {\n @Field({ description: 'What it is called.' })\n name: string\n\n @Field({ nullable: true, description: 'What it is about.' })\n description?: string\n\n @Field({ nullable: true, description: 'Its category.' })\n category?: string\n\n @Field({ nullable: true, description: 'The user who keeps it - the one making it when empty.' })\n managerId?: string\n}\n\n@InputType({ description: 'What a course says, changed' })\nexport class CoursePatch {\n @Field({ nullable: true, description: 'What it is called.' })\n name?: string\n\n @Field({ nullable: true, description: 'What it is about.' })\n description?: string\n\n @Field({ nullable: true, description: 'Its category.' })\n category?: string\n\n @Field({ nullable: true, description: 'The user who keeps it.' })\n managerId?: string\n}\n\n@InputType({ description: 'What a draft version says, changed' })\nexport class CourseVersionPatch {\n @Field(type => Int, { nullable: true, description: 'The least time in seconds.' })\n minSeconds?: number\n\n @Field({ nullable: true, description: 'What the learner confirms - nothing asked when empty.' })\n acknowledgement?: string\n\n @Field(type => Int, { nullable: true, description: 'The pass score out of 100 - no quiz when empty.' })\n passScore?: number\n\n @Field(type => Int, { nullable: true, description: 'How many questions an attempt draws - all when empty.' })\n questionCount?: number\n\n @Field(type => Int, { nullable: true, description: 'How many attempts a learner has - no limit when empty.' })\n attemptLimit?: number\n\n @Field(type => CourseSourceKind, { nullable: true, description: 'Where its material came from.' })\n sourceKind?: CourseSourceKind\n\n @Field({ nullable: true, description: 'Who gave the material and on what terms.' })\n sourceNote?: string\n}\n\n@InputType({ description: 'A unit of a draft version, new (no id) or changed' })\nexport class CourseUnitInput {\n @Field({ nullable: true, description: 'The unit to change - a new one when empty.' })\n id?: string\n\n @Field(type => CourseUnitKind, { description: 'What it is.' })\n kind: CourseUnitKind\n\n @Field({ description: 'What it is called.' })\n name: string\n\n @Field({ nullable: true, description: 'The text in markdown - a MARKDOWN unit.' })\n body?: string\n\n @Field({ nullable: true, description: 'The address - a LINK unit.' })\n url?: string\n\n @Field(type => Int, { nullable: true, description: \"The video's length in seconds, read from the file.\" })\n durationSeconds?: number\n\n @Field(type => Int, { nullable: true, description: \"A PDF's page count, read from the file.\" })\n pageCount?: number\n\n @Field(type => Int, { nullable: true, description: 'Seconds a PDF or a text is looked at to be done - 60 when empty.' })\n minSeconds?: number\n}\n\n@InputType({ description: 'A choice of a question, with whether it is right' })\nexport class CourseChoiceInput {\n @Field({ nullable: true, description: 'The choice id - kept when the question is changed.' })\n id?: string\n\n @Field({ description: 'What it says.' })\n text: string\n\n @Field({ description: 'Whether it is right.' })\n correct: boolean\n}\n\n@InputType({ description: 'A question of a draft version, new (no id) or changed' })\nexport class CourseQuestionInput {\n @Field({ nullable: true, description: 'The question to change - a new one when empty.' })\n id?: string\n\n @Field(type => CourseQuestionKind, { description: 'How it is answered.' })\n kind: CourseQuestionKind\n\n @Field({ description: 'What it asks.' })\n text: string\n\n @Field(type => [CourseChoiceInput], { description: 'Its choices.' })\n choices: CourseChoiceInput[]\n\n @Field({ nullable: true, description: 'Why the answer is what it is.' })\n explanation?: string\n}\n\n@ObjectType({ description: 'A choice of a question as a manager reads it - with whether it is right' })\nexport class CourseChoiceKey {\n @Field({ description: 'The choice id.' })\n id: string\n\n @Field({ description: 'What it says.' })\n text: string\n\n @Field({ description: 'Whether it is right.' })\n correct: boolean\n}\n\n@ObjectType({ description: 'A page of courses' })\nexport class CourseList {\n @Field(type => [Course], { description: 'The courses.' })\n items: Course[]\n\n @Field(type => Int, { description: 'How many there are.' })\n total: number\n}\n"]}
@@ -9,8 +9,8 @@ export declare enum CourseUnitKind {
9
9
  LINK = "LINK"
10
10
  }
11
11
  /**
12
- * 단원 (ADR-0194 decision 3) - one part of a version, in order. A video is done played to its end, a PDF or a text after
13
- * it was looked at for its time (a minute when not set); a link is not counted - the server cannot know what was
12
+ * 단원 (ADR-0194 decision 3) - one part of a version, in order. A video is done played to its end, a PDF read to its
13
+ * last page and looked at for its time, a text looked at for its time (a minute when not set); a link is not counted - the server cannot know what was
14
14
  * watched elsewhere. Its file hangs on it through attachment-base (`refType` `CourseUnit`).
15
15
  */
16
16
  export declare class CourseUnit {
@@ -25,6 +25,7 @@ export declare class CourseUnit {
25
25
  body?: string;
26
26
  url?: string;
27
27
  durationSeconds?: number;
28
+ pageCount?: number;
28
29
  minSeconds?: number;
29
30
  createdAt?: Date;
30
31
  updatedAt?: Date;
@@ -17,8 +17,8 @@ var CourseUnitKind;
17
17
  })(CourseUnitKind || (exports.CourseUnitKind = CourseUnitKind = {}));
18
18
  (0, type_graphql_1.registerEnumType)(CourseUnitKind, { name: 'CourseUnitKind', description: 'VIDEO, PDF, MARKDOWN (a text) or LINK (a page elsewhere - its watching is not counted).' });
19
19
  /**
20
- * 단원 (ADR-0194 decision 3) - one part of a version, in order. A video is done played to its end, a PDF or a text after
21
- * it was looked at for its time (a minute when not set); a link is not counted - the server cannot know what was
20
+ * 단원 (ADR-0194 decision 3) - one part of a version, in order. A video is done played to its end, a PDF read to its
21
+ * last page and looked at for its time, a text looked at for its time (a minute when not set); a link is not counted - the server cannot know what was
22
22
  * watched elsewhere. Its file hangs on it through attachment-base (`refType` `CourseUnit`).
23
23
  */
24
24
  let CourseUnit = class CourseUnit {
@@ -77,6 +77,11 @@ tslib_1.__decorate([
77
77
  (0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: "The video's length in seconds, read from the file when it was attached." }),
78
78
  tslib_1.__metadata("design:type", Number)
79
79
  ], CourseUnit.prototype, "durationSeconds", void 0);
80
+ tslib_1.__decorate([
81
+ (0, typeorm_1.Column)({ type: 'int', nullable: true }),
82
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: "A PDF's page count, read from the file when it was attached - every page is to be read." }),
83
+ tslib_1.__metadata("design:type", Number)
84
+ ], CourseUnit.prototype, "pageCount", void 0);
80
85
  tslib_1.__decorate([
81
86
  (0, typeorm_1.Column)({ type: 'int', nullable: true }),
82
87
  (0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: 'How long a PDF or a text is looked at to be done, in seconds - 60 when empty.' }),
@@ -1 +1 @@
1
- {"version":3,"file":"course-unit.js","sourceRoot":"","sources":["../../../server/service/course/course-unit.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, Int, ObjectType, registerEnumType } from 'type-graphql'\nimport { Column, CreateDateColumn, DeleteDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId, UpdateDateColumn } from 'typeorm'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain } from '@things-factory/shell'\n\nimport { CourseVersion } from './course-version'\n\n/** What a unit is: a video, a PDF document, a text in markdown, or a link to elsewhere (not counted). */\nexport enum CourseUnitKind {\n VIDEO = 'VIDEO',\n PDF = 'PDF',\n MARKDOWN = 'MARKDOWN',\n LINK = 'LINK'\n}\n\nregisterEnumType(CourseUnitKind, { name: 'CourseUnitKind', description: 'VIDEO, PDF, MARKDOWN (a text) or LINK (a page elsewhere - its watching is not counted).' })\n\n/**\n * 단원 (ADR-0194 decision 3) - one part of a version, in order. A video is done played to its end, a PDF or a text after\n * it was looked at for its time (a minute when not set); a link is not counted - the server cannot know what was\n * watched elsewhere. Its file hangs on it through attachment-base (`refType` `CourseUnit`).\n */\n@Entity({ name: 'learning_course_units' })\n@Index('ix_learning_course_unit_0', (row: CourseUnit) => [row.domain, row.version, row.seq])\n@ObjectType({ description: 'A unit of a course version - a video, a PDF, a text or a link, in order.' })\nexport class CourseUnit {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unit id.' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'The domain.' })\n domain?: Domain\n\n @RelationId((row: CourseUnit) => row.domain)\n domainId?: string\n\n @ManyToOne(type => CourseVersion)\n @Field(type => CourseVersion, { nullable: true, description: 'The version it is part of.' })\n version?: CourseVersion\n\n @RelationId((row: CourseUnit) => row.version)\n versionId?: string\n\n @Column({ type: 'int' })\n @Field(type => Int, { description: 'Its place in the version, from 1.' })\n seq: number\n\n @Column()\n @Field(type => CourseUnitKind, { description: 'What it is.' })\n kind: CourseUnitKind\n\n @Column()\n @Field({ description: 'What it is called.' })\n name: string\n\n @Column({ type: 'text', nullable: true })\n @Field({ nullable: true, description: 'The text, in markdown - for a MARKDOWN unit.' })\n body?: string\n\n @Column({ length: 2000, nullable: true })\n @Field({ nullable: true, description: 'The address - for a LINK unit.' })\n url?: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: \"The video's length in seconds, read from the file when it was attached.\" })\n durationSeconds?: number\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'How long a PDF or a text is looked at to be done, in seconds - 60 when empty.' })\n minSeconds?: number\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Creation timestamp.' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'Last update timestamp.' })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true, description: 'Soft delete timestamp.' })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'Who made it.' })\n creator?: User\n\n @RelationId((row: CourseUnit) => row.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'Who changed it last.' })\n updater?: User\n\n @RelationId((row: CourseUnit) => row.updater)\n updaterId?: string\n}\n"]}
1
+ {"version":3,"file":"course-unit.js","sourceRoot":"","sources":["../../../server/service/course/course-unit.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, Int, ObjectType, registerEnumType } from 'type-graphql'\nimport { Column, CreateDateColumn, DeleteDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId, UpdateDateColumn } from 'typeorm'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain } from '@things-factory/shell'\n\nimport { CourseVersion } from './course-version'\n\n/** What a unit is: a video, a PDF document, a text in markdown, or a link to elsewhere (not counted). */\nexport enum CourseUnitKind {\n VIDEO = 'VIDEO',\n PDF = 'PDF',\n MARKDOWN = 'MARKDOWN',\n LINK = 'LINK'\n}\n\nregisterEnumType(CourseUnitKind, { name: 'CourseUnitKind', description: 'VIDEO, PDF, MARKDOWN (a text) or LINK (a page elsewhere - its watching is not counted).' })\n\n/**\n * 단원 (ADR-0194 decision 3) - one part of a version, in order. A video is done played to its end, a PDF read to its\n * last page and looked at for its time, a text looked at for its time (a minute when not set); a link is not counted - the server cannot know what was\n * watched elsewhere. Its file hangs on it through attachment-base (`refType` `CourseUnit`).\n */\n@Entity({ name: 'learning_course_units' })\n@Index('ix_learning_course_unit_0', (row: CourseUnit) => [row.domain, row.version, row.seq])\n@ObjectType({ description: 'A unit of a course version - a video, a PDF, a text or a link, in order.' })\nexport class CourseUnit {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unit id.' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'The domain.' })\n domain?: Domain\n\n @RelationId((row: CourseUnit) => row.domain)\n domainId?: string\n\n @ManyToOne(type => CourseVersion)\n @Field(type => CourseVersion, { nullable: true, description: 'The version it is part of.' })\n version?: CourseVersion\n\n @RelationId((row: CourseUnit) => row.version)\n versionId?: string\n\n @Column({ type: 'int' })\n @Field(type => Int, { description: 'Its place in the version, from 1.' })\n seq: number\n\n @Column()\n @Field(type => CourseUnitKind, { description: 'What it is.' })\n kind: CourseUnitKind\n\n @Column()\n @Field({ description: 'What it is called.' })\n name: string\n\n @Column({ type: 'text', nullable: true })\n @Field({ nullable: true, description: 'The text, in markdown - for a MARKDOWN unit.' })\n body?: string\n\n @Column({ length: 2000, nullable: true })\n @Field({ nullable: true, description: 'The address - for a LINK unit.' })\n url?: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: \"The video's length in seconds, read from the file when it was attached.\" })\n durationSeconds?: number\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: \"A PDF's page count, read from the file when it was attached - every page is to be read.\" })\n pageCount?: number\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'How long a PDF or a text is looked at to be done, in seconds - 60 when empty.' })\n minSeconds?: number\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Creation timestamp.' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'Last update timestamp.' })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true, description: 'Soft delete timestamp.' })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'Who made it.' })\n creator?: User\n\n @RelationId((row: CourseUnit) => row.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'Who changed it last.' })\n updater?: User\n\n @RelationId((row: CourseUnit) => row.updater)\n updaterId?: string\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { MaterialDraftMutation } from './material-draft-mutation';
1
2
  import { Course } from './course';
2
3
  import { CourseQuestion } from './course-question';
3
4
  import { CourseUnit } from './course-unit';
@@ -10,5 +11,5 @@ export * from './course-unit';
10
11
  export * from './course-version';
11
12
  export { COURSE_UNIT_REF_TYPE, publishedVersionOf, unitsOf, questionsOf, addDraftedQuestions } from './course-service';
12
13
  export declare const entities: (typeof Course | typeof CourseVersion | typeof CourseUnit | typeof CourseQuestion)[];
13
- export declare const resolvers: (typeof CourseMutation | typeof CourseQuery | typeof CourseVersionFields | typeof CourseUnitFields | typeof CourseQuestionFields)[];
14
+ export declare const resolvers: (typeof MaterialDraftMutation | typeof CourseMutation | typeof CourseQuery | typeof CourseVersionFields | typeof CourseUnitFields | typeof CourseQuestionFields)[];
14
15
  export declare const subscribers: any[];
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.subscribers = exports.resolvers = exports.entities = exports.addDraftedQuestions = exports.questionsOf = exports.unitsOf = exports.publishedVersionOf = exports.COURSE_UNIT_REF_TYPE = void 0;
4
4
  const tslib_1 = require("tslib");
5
+ const material_draft_mutation_1 = require("./material-draft-mutation");
5
6
  const course_1 = require("./course");
6
7
  const course_question_1 = require("./course-question");
7
8
  const course_unit_1 = require("./course-unit");
@@ -19,6 +20,6 @@ Object.defineProperty(exports, "unitsOf", { enumerable: true, get: function () {
19
20
  Object.defineProperty(exports, "questionsOf", { enumerable: true, get: function () { return course_service_1.questionsOf; } });
20
21
  Object.defineProperty(exports, "addDraftedQuestions", { enumerable: true, get: function () { return course_service_1.addDraftedQuestions; } });
21
22
  exports.entities = [course_1.Course, course_version_1.CourseVersion, course_unit_1.CourseUnit, course_question_1.CourseQuestion];
22
- exports.resolvers = [course_query_1.CourseQuery, course_query_1.CourseVersionFields, course_query_1.CourseUnitFields, course_query_1.CourseQuestionFields, course_mutation_1.CourseMutation];
23
+ exports.resolvers = [course_query_1.CourseQuery, course_query_1.CourseVersionFields, course_query_1.CourseUnitFields, course_query_1.CourseQuestionFields, course_mutation_1.CourseMutation, material_draft_mutation_1.MaterialDraftMutation];
23
24
  exports.subscribers = [];
24
25
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/course/index.ts"],"names":[],"mappings":";;;;AAAA,qCAAiC;AACjC,uDAAkD;AAClD,+CAA0C;AAC1C,qDAAgD;AAChD,uDAAkD;AAClD,iDAAyG;AAEzG,mDAAwB;AACxB,4DAAiC;AACjC,wDAA6B;AAC7B,2DAAgC;AAChC,mDAAsH;AAA7G,sHAAA,oBAAoB,OAAA;AAAE,oHAAA,kBAAkB,OAAA;AAAE,yGAAA,OAAO,OAAA;AAAE,6GAAA,WAAW,OAAA;AAAE,qHAAA,mBAAmB,OAAA;AAE/E,QAAA,QAAQ,GAAG,CAAC,eAAM,EAAE,8BAAa,EAAE,wBAAU,EAAE,gCAAc,CAAC,CAAA;AAC9D,QAAA,SAAS,GAAG,CAAC,0BAAW,EAAE,kCAAmB,EAAE,+BAAgB,EAAE,mCAAoB,EAAE,gCAAc,CAAC,CAAA;AACtG,QAAA,WAAW,GAAG,EAAE,CAAA","sourcesContent":["import { Course } from './course'\nimport { CourseQuestion } from './course-question'\nimport { CourseUnit } from './course-unit'\nimport { CourseVersion } from './course-version'\nimport { CourseMutation } from './course-mutation'\nimport { CourseQuery, CourseQuestionFields, CourseUnitFields, CourseVersionFields } from './course-query'\n\nexport * from './course'\nexport * from './course-question'\nexport * from './course-unit'\nexport * from './course-version'\nexport { COURSE_UNIT_REF_TYPE, publishedVersionOf, unitsOf, questionsOf, addDraftedQuestions } from './course-service'\n\nexport const entities = [Course, CourseVersion, CourseUnit, CourseQuestion]\nexport const resolvers = [CourseQuery, CourseVersionFields, CourseUnitFields, CourseQuestionFields, CourseMutation]\nexport const subscribers = []\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/course/index.ts"],"names":[],"mappings":";;;;AAAA,uEAAiE;AACjE,qCAAiC;AACjC,uDAAkD;AAClD,+CAA0C;AAC1C,qDAAgD;AAChD,uDAAkD;AAClD,iDAAyG;AAEzG,mDAAwB;AACxB,4DAAiC;AACjC,wDAA6B;AAC7B,2DAAgC;AAChC,mDAAsH;AAA7G,sHAAA,oBAAoB,OAAA;AAAE,oHAAA,kBAAkB,OAAA;AAAE,yGAAA,OAAO,OAAA;AAAE,6GAAA,WAAW,OAAA;AAAE,qHAAA,mBAAmB,OAAA;AAE/E,QAAA,QAAQ,GAAG,CAAC,eAAM,EAAE,8BAAa,EAAE,wBAAU,EAAE,gCAAc,CAAC,CAAA;AAC9D,QAAA,SAAS,GAAG,CAAC,0BAAW,EAAE,kCAAmB,EAAE,+BAAgB,EAAE,mCAAoB,EAAE,gCAAc,EAAE,+CAAqB,CAAC,CAAA;AAC7H,QAAA,WAAW,GAAG,EAAE,CAAA","sourcesContent":["import { MaterialDraftMutation } from './material-draft-mutation'\nimport { Course } from './course'\nimport { CourseQuestion } from './course-question'\nimport { CourseUnit } from './course-unit'\nimport { CourseVersion } from './course-version'\nimport { CourseMutation } from './course-mutation'\nimport { CourseQuery, CourseQuestionFields, CourseUnitFields, CourseVersionFields } from './course-query'\n\nexport * from './course'\nexport * from './course-question'\nexport * from './course-unit'\nexport * from './course-version'\nexport { COURSE_UNIT_REF_TYPE, publishedVersionOf, unitsOf, questionsOf, addDraftedQuestions } from './course-service'\n\nexport const entities = [Course, CourseVersion, CourseUnit, CourseQuestion]\nexport const resolvers = [CourseQuery, CourseVersionFields, CourseUnitFields, CourseQuestionFields, CourseMutation, MaterialDraftMutation]\nexport const subscribers = []\n"]}
@@ -0,0 +1 @@
1
+ export declare function speechMp3(input: Buffer, signal: AbortSignal): Promise<Buffer>;