This commit is contained in:
Tibo De Peuter 2025-03-07 18:31:58 +01:00
parent 38acfa6a4a
commit 197d1d9ae2
13 changed files with 372 additions and 120 deletions

View file

@ -35,7 +35,21 @@ import { Language } from '../content/language.js';
* groups:
* type: array
* items:
* $ref: '#/components/schemas/Group'
* type: string
* description: ID of a group
* links:
* type: object
* properties:
* self:
* type: string
* description: Path to the assignment
* example: '/assignment/0'
* submissions:
* type: array
* items:
* type: string
* description: Path to the submissions for this assignment
* example: '/assignment/0/submissions'
* required:
* - within
* - id

View file

@ -2,6 +2,10 @@ import { Entity, Enum, ManyToOne } from '@mikro-orm/core';
import { Student } from '../users/student.entity.js';
import { Class } from './class.entity.js';
/**
* @swagger
* tags: [Class]
*/
@Entity()
export class ClassJoinRequest {
@ManyToOne({

View file

@ -9,6 +9,35 @@ import { v4 } from 'uuid';
import { Teacher } from '../users/teacher.entity.js';
import { Student } from '../users/student.entity.js';
/**
* @swagger
* tags:
* name: Class
* description: API for managing classes
* components:
* schemas:
* Class:
* type: object
* properties:
* classId:
* type: integer
* format: int8
* displayName:
* type: string
* teachers:
* type: array
* items:
* type: string
* description: The id of a teacher
* students:
* type: array
* items:
* type: string
* description: The id of a student
* required:
* - teachers
* - students
*/
@Entity()
export class Class {
@PrimaryKey()

View file

@ -1,6 +1,28 @@
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core';
import { LearningObject } from './learning-object.entity.js';
/**
* @swagger
* components:
* schemas:
* Attachment:
* type: object
* properties:
* learningObject:
* $ref: '#/components/schemas/LearningObject'
* sequenceNumber:
* type: integer
* mimeType:
* type: string
* content:
* type: string
* format: binary
* required:
* - learningObject
* - sequenceNumber
* - mimeType
* - content
*/
@Entity()
export class Attachment {
@ManyToOne({

View file

@ -1,3 +1,23 @@
/**
* @swagger
* components:
* schemas:
* Language:
* type: string
* enum:
* - nl
* - fr
* - en
* - de
* parameters:
* Language:
* in: query
* name: language
* description: Language of the content
* required: false
* schema:
* $ref: '#/components/schemas/Language'
*/
export enum Language {
Dutch = 'nl',
French = 'fr',

View file

@ -12,6 +12,80 @@ import { Language } from './language.js';
import { Attachment } from './attachment.entity.js';
import { Teacher } from '../users/teacher.entity.js';
/**
* @swagger
* tags:
* name: LearningObject
* description: API for managing learning objects
* components:
* schemas:
* LearningObject:
* type: object
* properties:
* hruid:
* type: string
* language:
* $ref: '#/components/schemas/Language'
* version:
* type: string
* default: '1'
* admins:
* type: array
* items:
* $ref: '#/components/schemas/Teacher'
* title:
* type: string
* description:
* type: string
* contentType:
* type: string
* keywords:
* type: array
* items:
* type: string
* targetAges:
* type: array
* items:
* type: integer
* nullable: true
* teacherExclusive:
* type: boolean
* default: false
* skosConcepts:
* type: array
* items:
* type: string
* educationalGoals:
* type: array
* items:
* $ref: '#/components/schemas/EducationalGoal'
* copyright:
* type: string
* default: ''
* license:
* type: string
* default: ''
* difficulty:
* type: integer
* nullable: true
* estimatedTime:
* type: integer
* returnValue:
* $ref: '#/components/schemas/ReturnValue'
* available:
* type: boolean
* default: true
* contentLocation:
* type: string
* nullable: true
* attachments:
* type: array
* items:
* $ref: '#/components/schemas/Attachment'
* content:
* type: string
* format: binary
*/
@Entity()
export class LearningObject {
@PrimaryKey({ type: 'string' })
@ -101,6 +175,18 @@ export class LearningObject {
content!: Buffer;
}
/**
* @swagger
* components:
* schemas:
* EducationalGoal:
* type: object
* properties:
* source:
* type: string
* id:
* type: string
*/
@Embeddable()
export class EducationalGoal {
@Property({ type: 'string' })
@ -110,6 +196,22 @@ export class EducationalGoal {
id!: string;
}
/**
* @swagger
* components:
* schemas:
* ReturnValue:
* type: object
* properties:
* callbackUrl:
* type: string
* format: uri
* callbackSchema:
* type: string
* required:
* - callbackUrl
* - callbackSchema
*/
@Embeddable()
export class ReturnValue {
@Property({ type: 'string' })

View file

@ -11,6 +11,46 @@ import {
import { Language } from './language.js';
import { Teacher } from '../users/teacher.entity.js';
/**
* @swagger
* tags:
* name: LearningPath
* description: API for managing learning paths
* components:
* schemas:
* LearningPath:
* type: object
* required:
* - hruid
* - language
* - admins
* - title
* - description
* - image
* properties:
* hruid:
* type: string
* description: Human readable identifier
* language:
* description: Language of the learning path
* schema:
* $ref: '#/components/schemas/Language'
* admins:
* type: array
* items:
* $ref: '#/components/schemas/Teacher'
* title:
* type: string
* description:
* type: string
* image:
* type: string
* nodes:
* type: array
* items:
* schema:
* $ref: '#/components/schemas/LearningPathNode'
*/
@Entity()
export class LearningPath {
@PrimaryKey({ type: 'string' })

View file

@ -2,6 +2,23 @@ import { Collection, Entity, ManyToMany } from '@mikro-orm/core';
import { User } from './user.entity.js';
import { Class } from '../classes/class.entity.js';
/**
* @swagger
* tags:
* name: Teacher
* description: API for managing teachers
* components:
* schemas:
* Teacher:
* type: object
* required:
* - classes
* properties:
* classes:
* type: array
* items:
* $ref: '#/components/schemas/Class'
*/
@Entity()
export class Teacher extends User {
@ManyToMany(() => {

View file

@ -1,7 +1,40 @@
/**
* @swagger
* components:
* parameters:
* id:
* in: path
* name: id
* schema:
* type: string
* description: The id of the class
* required: true
* example: 0
*/
import express from 'express';
const router = express.Router();
// Root endpoint used to search objects
/**
* @swagger
* /class:
* get:
* summary: Get a list of classes
* tags: [Class]
* responses:
* 200:
* description: A list of classes
* content:
* application/json:
* schema:
* type: object
* properties:
* classes:
* type: array
* items:
* type: string
* example: '0'
*/
router.get('/', (req, res) => {
res.json({
classes: ['0', '1'],
@ -9,6 +42,22 @@ router.get('/', (req, res) => {
});
// Information about an class with id 'id'
/**
* @swagger
* /class/{id}:
* get:
* summary: Get a class by id
* tags: [Class]
* parameters:
* - $ref: '#/components/parameters/id'
* responses:
* 200:
* description: A class
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Class'
*/
router.get('/:id', (req, res) => {
res.json({
id: req.params.id,

View file

@ -1,3 +1,10 @@
/**
* @swagger
* tags:
* name: LearningObject
* description: API for managing learning objects
*/
import express from 'express';
import {
getAllLearningObjects,
@ -8,20 +15,67 @@ const router = express.Router();
// DWENGO learning objects
// Queries: hruid(path), full, language
// Route to fetch list of learning objects based on hruid of learning path
// Route 1: list of object hruids
// Example 1: http://localhost:3000/learningObject?hruid=un_artificiele_intelligentie
// Route 2: list of object data
// Example 2: http://localhost:3000/learningObject?full=true&hruid=un_artificiele_intelligentie
/**
* @swagger
* /learningObject:
* get:
* summary: Get a list of learning objects
* tags: [LearningObject]
* parameters:
* - in: query
* name: hruid
* schema:
* type: string
* description:
* The hruid of the learning path to get learning objects from
* example: un_artificiele_intelligentie
* - in: query
* name: full
* description: Whether to return full object data
* - $ref: '#/components/parameters/Language'
* responses:
* 200:
* description: A list of learning objects
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: '#/components/schemas/LearningObject'
* 400:
* description: HRUID query is required
* 500:
* description: Internal server error
*/
router.get('/', getAllLearningObjects);
// Parameter: hruid of learning object
// Query: language
// Route to fetch data of one learning object based on its hruid
// Example: http://localhost:3000/learningObject/un_ai7
/**
* @swagger
* /learningObject/{hruid}:
* get:
* summary: Get a learning object by hruid
* tags: [LearningObject]
* parameters:
* - in: path
* name: hruid
* schema:
* type: string
* required: true
* description: The hruid of the learning object
* example: un_ai7
* - $ref: '#/components/parameters/Language'
* responses:
* 200:
* description: A learning object
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/LearningObject"
* 400:
* description: HRUID parameter is required
* 500:
* description: Internal server error
*/
router.get('/:hruid', getLearningObject);
export default router;

View file

@ -2,6 +2,10 @@ import express from 'express';
const router = express.Router();
// Root endpoint used to search objects
/**
* @swagger
* /question
*/
router.get('/', (req, res) => {
res.json({
questions: ['0', '1'],

View file

@ -1,9 +1,11 @@
import { fetchWithLogging } from '../util/apiHelper.js';
import { DWENGO_API_BASE } from '../config.js';
import {
LearningPath,
LearningPathResponse,
} from '../interfaces/learningPath.js';
import {
LearningPath
} from '../entities/content/learning-path.entity.js';
import { getLogger, Logger } from '../logging/initalize.js';
const logger: Logger = getLogger();

105
package-lock.json generated
View file

@ -56,7 +56,6 @@
"ts-node": "^10.9.2",
"tsx": "^4.19.3",
"typescript": "^5.7.3",
"typescript-json-schema": "^0.65.1",
"vitest": "^3.0.6"
}
},
@ -6355,13 +6354,6 @@
"version": "1.0.1",
"license": "MIT"
},
"node_modules/path-equal": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz",
"integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==",
"dev": true,
"license": "MIT"
},
"node_modules/path-exists": {
"version": "4.0.0",
"dev": true,
@ -8296,103 +8288,6 @@
"typescript": ">=4.8.4 <5.8.0"
}
},
"node_modules/typescript-json-schema": {
"version": "0.65.1",
"resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.65.1.tgz",
"integrity": "sha512-tuGH7ff2jPaUYi6as3lHyHcKpSmXIqN7/mu50x3HlYn0EHzLpmt3nplZ7EuhUkO0eqDRc9GqWNkfjgBPIS9kxg==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"@types/json-schema": "^7.0.9",
"@types/node": "^18.11.9",
"glob": "^7.1.7",
"path-equal": "^1.2.5",
"safe-stable-stringify": "^2.2.0",
"ts-node": "^10.9.1",
"typescript": "~5.5.0",
"yargs": "^17.1.1"
},
"bin": {
"typescript-json-schema": "bin/typescript-json-schema"
}
},
"node_modules/typescript-json-schema/node_modules/@types/node": {
"version": "18.19.79",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.79.tgz",
"integrity": "sha512-90K8Oayimbctc5zTPHPfZloc/lGVs7f3phUAAMcTgEPtg8kKquGZDERC8K4vkBYkQQh48msiYUslYtxTWvqcAg==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/typescript-json-schema/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/typescript-json-schema/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/typescript-json-schema/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/typescript-json-schema/node_modules/typescript": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/typescript-json-schema/node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true,
"license": "MIT"
},
"node_modules/undici-types": {
"version": "6.20.0",
"license": "MIT"