From e0180bbcded9ee5691859b8cd32f8896c85046fb Mon Sep 17 00:00:00 2001
From: Jonas Schlabertz <jonas@schlabertz.de>
Date: Tue, 26 Apr 2022 11:04:02 +0200
Subject: [PATCH] Adds license support for all entities.

---
 API.paw                                       | Bin 28133 -> 28629 bytes
 src/controller/ComponentController.ts         |  29 ++++++++++++++++--
 .../ComponentInformationController.ts         |   5 ++-
 src/controller/ComponentRelationController.ts |   4 ++-
 src/controller/TypeDefinitionController.ts    |   3 +-
 src/entity/Component.ts                       |  16 +++++++---
 src/entity/ComponentInformation.ts            |  14 +++++++--
 src/entity/ComponentRelation.ts               |   7 ++++-
 src/entity/Measurement.ts                     |   7 ++++-
 src/entity/TypeDefinition.ts                  |   6 +++-
 src/middleware/ValidationErrorMiddleware.ts   |  13 +++++++-
 .../1645518654632-SeedRootComponent.ts        |   1 +
 src/services/IngestionService.ts              |   2 +-
 src/util/ContextDefinitions.ts                |  11 +++++--
 src/util/SchemaDefinitions.ts                 |  23 +++++++++++---
 15 files changed, 117 insertions(+), 24 deletions(-)

diff --git a/API.paw b/API.paw
index 23c6fc5900c70514dd3964d73d3551ee600b8be3..18697cc4589c23693eb11a1af634fb2b34a16d3a 100644
GIT binary patch
delta 5238
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
D<MzL%

delta 4908
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

diff --git a/src/controller/ComponentController.ts b/src/controller/ComponentController.ts
index 2d77b2a..587993f 100644
--- a/src/controller/ComponentController.ts
+++ b/src/controller/ComponentController.ts
@@ -107,6 +107,9 @@ export default class ComponentController extends BaseController {
         const topic = request.body.topic;
         const parentComponentId: string = request.body.parentComponentId || Component.rootId;
         const measurementTargetIds: string[] = request.body.measurementTargets || [];
+        const componentLicense: string = request.body.componentLicense;
+        const informationLicense: string = request.body.informationLicense;
+        const measurementLicense: string = request.body.measurementLicense;
 
         this.componentRepository.findOne(parentComponentId, { relations: ["isComponentOf"] }).then(async (parentComponent) => {
             if(!parentComponent) {
@@ -157,7 +160,7 @@ export default class ComponentController extends BaseController {
             let childComponent: Component;
 
             try {
-                childComponent = Component.create(informationName, comment, topic, measurementTargets, type, metadata);
+                childComponent = Component.create(informationName, comment, topic, measurementTargets, type, metadata, componentLicense, informationLicense, measurementLicense);
             } catch(error) {
                 // Verification of information schema failed.
                 logger.error(`information verification failed: ${error}`);
@@ -165,9 +168,31 @@ export default class ComponentController extends BaseController {
                 response.send();
                 return;
             }
+
+            let relationLicense: string;
+
+            if(request.body.parentComponentId) {
+                if(request.body.relationLicense) {
+                    relationLicense = request.body.relationLicense;
+                } else {
+                    response.status(400);
+                    this.setJSONLDResponseType(response);
+                    response.send({
+                        "@context": {
+                            "message": "https://schema.org/error"
+                        }, 
+                        "message": "License URL for parent relation not set."
+                    });
+                    return;
+                }
+            } else {
+                // This relation is a relation to the root component which is
+                // internal only and thus does not need a license.
+                relationLicense = "";
+            }
             
             await this.componentRepository.save(childComponent);
-            const relation = Component.addSubComponent(parentComponent, childComponent);
+            const relation = Component.addSubComponent(parentComponent, childComponent, relationLicense);
             await this.componentRelationRepository.save(relation);
             const childComponentJsonLd = await childComponent.toJSONLD();
             this.setJSONLDResponseType(response);
diff --git a/src/controller/ComponentInformationController.ts b/src/controller/ComponentInformationController.ts
index 333c3a5..a2274e3 100644
--- a/src/controller/ComponentInformationController.ts
+++ b/src/controller/ComponentInformationController.ts
@@ -75,6 +75,7 @@ export default class ComponentInformationController extends BaseController {
 
     createNewVersion = async (request: Request, response: Response) => {
         const oldVersionId = request.params.oldVersionId;
+
         this.componentInformationRepository.findOne(oldVersionId, { relations: ["component", "nextVersion"] }).then(async (oldVersionInformation) => {
             if (!oldVersionInformation) {
                 logger.error("Cannot find information with id: ", request.params.oldVersionId);
@@ -98,6 +99,8 @@ export default class ComponentInformationController extends BaseController {
             const metadata = request.body.metadata;
             const topic = request.body.topic;
             const measurementTargetIds: string[] = request.body.measurementTargets || [];
+            const informationLicense: string = request.body.informationLicense;
+            const measurementLicense: string = request.body.measurementLicense;
 
             // First check if the topic is already taken.
             const currentInformationWithTopic: ComponentInformation[] = await ComponentInformation.findCurrentVersionForTopic(topic, this.componentInformationRepository);
@@ -148,7 +151,7 @@ export default class ComponentInformationController extends BaseController {
                 }
             }
 
-            const newInformation = new ComponentInformation(informationName, measurementTargets, comment, topic, type, metadata);
+            const newInformation = new ComponentInformation(informationName, measurementTargets, comment, topic, informationLicense, measurementLicense, type, metadata);
             ComponentInformation.linkNewVersion(oldVersionInformation, newInformation);
             await this.componentInformationRepository.save(oldVersionInformation);
             const newInformationJsonLd = newInformation.toJSONLD();
diff --git a/src/controller/ComponentRelationController.ts b/src/controller/ComponentRelationController.ts
index 4e9d8b3..5362763 100644
--- a/src/controller/ComponentRelationController.ts
+++ b/src/controller/ComponentRelationController.ts
@@ -113,7 +113,9 @@ export default class ComponentRelationController extends BaseController {
         let newRelation: ComponentRelation | undefined;
 
         if(newParentComponent) {
-            newRelation = Component.addSubComponent(newParentComponent, component);
+            const relationLicense: string = request.body.relationLicense;
+
+            newRelation = Component.addSubComponent(newParentComponent, component, relationLicense);
             newRelation.from = creationDate;
         }
 
diff --git a/src/controller/TypeDefinitionController.ts b/src/controller/TypeDefinitionController.ts
index f4a2676..dede4f2 100644
--- a/src/controller/TypeDefinitionController.ts
+++ b/src/controller/TypeDefinitionController.ts
@@ -69,7 +69,8 @@ export default class TypeDefinitionController extends BaseController {
             name: request.body.name,
             comment: comment,
             context: request.body.context,
-            schema: schema
+            schema: schema,
+            license: request.body.license
         }).then(() => {
             return this.repository.findOneOrFail({ name: request.body.name });
         }).then((newDefinition) => {
diff --git a/src/entity/Component.ts b/src/entity/Component.ts
index 53c6882..90aab33 100644
--- a/src/entity/Component.ts
+++ b/src/entity/Component.ts
@@ -1,5 +1,6 @@
 import { 
     PrimaryGeneratedColumn, 
+    Column,
     CreateDateColumn, 
     Entity,
     Repository,
@@ -39,6 +40,9 @@ export default class Component {
     })
     dateCreated!: Date;
 
+    @Column()
+    license!: string;
+
     // Sub/Parent Component Relation
 
     @OneToMany(() => ComponentRelation, relation => relation.child, {
@@ -154,7 +158,7 @@ export default class Component {
             .getOne();
     }
 
-    static create(name: string, comment: string, topic: string, measurementTargets: Component[], type: TypeDefinition, data: Record<string, unknown>): Component {
+    static create(name: string, comment: string, topic: string, measurementTargets: Component[], type: TypeDefinition, data: Record<string, unknown>, componentLicense: string, informationLicense: string, measurementLicense: string): Component {
         // Create a component with an initial information object attached to it.
         if (!type.validateData(data)) {
             throw new Error("Information does not fulfill type definition schema requirements.");
@@ -171,13 +175,14 @@ export default class Component {
             targets = measurementTargets;
         }
 
-        const information = new ComponentInformation(name, targets, comment, topic, type, data);
+        const information = new ComponentInformation(name, targets, comment, topic,informationLicense, measurementLicense , type, data);
         component.information = [information];
+        component.license = componentLicense;
         return component;
     }
 
-    static addSubComponent(parent: Component, child: Component): ComponentRelation {
-        return new ComponentRelation(parent, child);
+    static addSubComponent(parent: Component, child: Component, relationLicense: string): ComponentRelation {
+        return new ComponentRelation(parent, child, relationLicense);
     }
 
     toJSONLD(): NodeObject {
@@ -185,7 +190,8 @@ export default class Component {
             "@context": ContextDefinitions.component,
             "@type": "Component",
             "identifier": { "@id": `${config.baseURL}/component/${this.id.toString()}`},
-            "dateCreated": this.dateCreated.toISOString()
+            "dateCreated": this.dateCreated.toISOString(),
+            "license": this.license
         };
 
         if (this.isComponentOf) {
diff --git a/src/entity/ComponentInformation.ts b/src/entity/ComponentInformation.ts
index 8aec7d2..26d3641 100644
--- a/src/entity/ComponentInformation.ts
+++ b/src/entity/ComponentInformation.ts
@@ -47,6 +47,12 @@ export default class ComponentInformation {
     @Column()
     topic: string;
 
+    @Column()
+    informationLicense!: string;
+
+    @Column()
+    measurementLicense!: string;
+
     // Versioning Relation
 
     @OneToOne(() => ComponentInformation, component => component.previousVersion, {
@@ -80,13 +86,15 @@ export default class ComponentInformation {
     
     // Constructor
 
-    constructor(name: string, measurementTargets: Component[], comment: string, topic: string, type: TypeDefinition, metadata: Record<string, unknown>) {
+    constructor(name: string, measurementTargets: Component[], comment: string, topic: string, informationLicense: string, measurementLicense: string, type: TypeDefinition, metadata: Record<string, unknown>) {
         this.name = name;
         this.measurementTargets = measurementTargets;
         this.comment = comment;
         this.metadata = metadata;
         this.type = type;
         this.topic = topic;
+        this.informationLicense = informationLicense;
+        this.measurementLicense = measurementLicense;
     }
 
     // Database Queries
@@ -166,7 +174,9 @@ export default class ComponentInformation {
             "dateCreated": this.dateCreated.toISOString(),
             "name": this.name,
             "comment": this.comment,
-            "metadata": this.type.toJSONLD(this.metadata)
+            "metadata": this.type.toJSONLD(this.metadata),
+            "informationLicense": this.informationLicense,
+            "measurementLicense": this.measurementLicense
         };
 
         return document;
diff --git a/src/entity/ComponentRelation.ts b/src/entity/ComponentRelation.ts
index 6b67b54..76540f9 100644
--- a/src/entity/ComponentRelation.ts
+++ b/src/entity/ComponentRelation.ts
@@ -30,6 +30,9 @@ export default class ComponentRelation {
     })
     to?: Date;
 
+    @Column()
+    license!: string;
+
     // Relations
 
     @ManyToOne(() => Component, component => component.subComponents)
@@ -40,9 +43,10 @@ export default class ComponentRelation {
 
     // Initializer
 
-    constructor(parent: Component, child: Component) {
+    constructor(parent: Component, child: Component, license: string) {
         this.parent = parent;
         this.child = child;
+        this.license = license;
     }
 
     static find(filter: string | undefined, pageSize: number, page: number, repository: Repository<ComponentRelation>): Promise<ComponentRelation[]> {
@@ -80,6 +84,7 @@ export default class ComponentRelation {
         const document: NodeObject = {
             "@context": ContextDefinitions.componentRelation,
             "@type": "ComponentRelation",
+            "license": this.license,
             "identifier": { "@id": `${config.baseURL}/relation/${this.id.toString()}`},
             "from": this.from.toISOString(),
             "to": null,
diff --git a/src/entity/Measurement.ts b/src/entity/Measurement.ts
index 22a01bd..277471f 100644
--- a/src/entity/Measurement.ts
+++ b/src/entity/Measurement.ts
@@ -28,6 +28,9 @@ export default class Measurement {
     @Column({ type: "jsonb", nullable: true })
     metadata?: unknown;
 
+    @Column()
+    license!: string;
+
     // Component Relation
 
     @ManyToOne(() => ComponentInformation, information => information.measurements, { nullable: false })
@@ -48,8 +51,9 @@ export default class Measurement {
 
     // Constructor
 
-    constructor(timestamp: Date, value: unknown, valueType: TypeDefinition, metadata: unknown | undefined, metadataType: TypeDefinition | undefined, componentInformation: ComponentInformation) {
+    constructor(timestamp: Date, license: string, value: unknown, valueType: TypeDefinition, metadata: unknown | undefined, metadataType: TypeDefinition | undefined, componentInformation: ComponentInformation) {
         this.dateCreated = timestamp;
+        this.license = license;
         this.value = value;
         this.valueType = valueType;
         this.metadata = metadata;
@@ -117,6 +121,7 @@ export default class Measurement {
             "@context": ContextDefinitions.measurement(this.valueType.context, this.metadataType?.context),
             "identifier": { "@id": `${config.baseURL}/measurement/${this.id.toString()}` },
             "dateCreated": this.dateCreated.toISOString(),
+            "license": this.license,
             "value": this.value
         };
 
diff --git a/src/entity/TypeDefinition.ts b/src/entity/TypeDefinition.ts
index b7112bf..c458db8 100644
--- a/src/entity/TypeDefinition.ts
+++ b/src/entity/TypeDefinition.ts
@@ -36,6 +36,9 @@ export default class TypeDefinition {
     })
     context: Record<string, unknown>;
 
+    @Column()
+    license!: string;
+
     // Relations
 
     @OneToMany(() => ComponentInformation, information => information.type)
@@ -47,11 +50,12 @@ export default class TypeDefinition {
     @OneToMany(() => Measurement, measurement => measurement.metadataType)
     isTypeOfMeasurementMetadata?: Measurement;
 
-    constructor(name: string, comment: string, schema: Record<string, unknown>, context: Record<string, unknown>) {
+    constructor(name: string, comment: string, schema: Record<string, unknown>, context: Record<string, unknown>, license: string) {
         this.name = name;
         this.comment = comment;
         this.schema = schema;
         this.context = context;
+        this.license = license;
     }
 
     static findByName(name: string, repository: Repository<TypeDefinition>): Promise<TypeDefinition | undefined> {
diff --git a/src/middleware/ValidationErrorMiddleware.ts b/src/middleware/ValidationErrorMiddleware.ts
index c64b9d6..f430086 100644
--- a/src/middleware/ValidationErrorMiddleware.ts
+++ b/src/middleware/ValidationErrorMiddleware.ts
@@ -8,6 +8,17 @@ export default (request: Request, response: Response, next: NextFunction): void
         return;
     }
 
-    response.status(400).send({ errors: result.array() });
+    response.status(400);
+    response.type("application/ld+json");
+    response.send(
+        result.array().map((error) => {
+            return {
+                "@context": {
+                    "message": "https://schema.org/error"
+                }, 
+                "message": error.msg
+            };
+        }) 
+    );
     return;
 };
diff --git a/src/migration/1645518654632-SeedRootComponent.ts b/src/migration/1645518654632-SeedRootComponent.ts
index cb7efd1..8d6020d 100644
--- a/src/migration/1645518654632-SeedRootComponent.ts
+++ b/src/migration/1645518654632-SeedRootComponent.ts
@@ -11,6 +11,7 @@ export class SeedRootComponent1645518654632 implements MigrationInterface {
         const repository = await queryRunner.connection.getRepository(Component);
         const rootComponent = new Component();
         rootComponent.id = Component.rootId;
+        rootComponent.license = "";
         await repository.save(rootComponent);
     }
 
diff --git a/src/services/IngestionService.ts b/src/services/IngestionService.ts
index 339ef3f..555541d 100644
--- a/src/services/IngestionService.ts
+++ b/src/services/IngestionService.ts
@@ -128,7 +128,7 @@ class IngestionService {
                 }
 
                 const information: ComponentInformation = linkedInformation[0];
-                const measurement = new Measurement(new Date(messageContent.timestamp), messageContent.value, valueType, metadata, metadataType, information);
+                const measurement = new Measurement(new Date(messageContent.timestamp), information.measurementLicense, messageContent.value, valueType, metadata, metadataType, information);
                 measurement.targets = information.measurementTargets;
 
                 this.measurementRepository.save(measurement);
diff --git a/src/util/ContextDefinitions.ts b/src/util/ContextDefinitions.ts
index 9009e76..c2bc4d9 100644
--- a/src/util/ContextDefinitions.ts
+++ b/src/util/ContextDefinitions.ts
@@ -1,25 +1,30 @@
 const component = {
     "id": { "@id": "https://schema.org/url", "@type": "@id"},
-    "dateCreated": "https://schema.org/DateTime"
+    "dateCreated": "https://schema.org/DateTime",
+    "license": "https://schema.org/license"
 };
 
 const componentRelation = {
     "id": { "@id": "https://schema.org/url", "@type": "@id"},
     "from": "https://schema.org/DateTime",
-    "to": "https://schema.org/DateTime"
+    "to": "https://schema.org/DateTime",
+    "license": "https://schema.org/license"
 };
 
 const information = {
     "id": { "@id": "https://schema.org/url", "@type": "@id"},
     "dateCreated": "https://schema.org/DateTime",
     "name": "https://schema.org/name",
-    "comment": "http://schema.org/comment"
+    "comment": "http://schema.org/comment",
+    "informationLicense": "https://schema.org/license",
+    "measurementLicense": "https://schema.org/license"
 };
 
 const measurement = function(valueContext: unknown, metadataContext: unknown | undefined): Record<string, unknown> {
     const result: Record<string, unknown> = {
         "id": { "@id": "https://schema.org/url", "@type": "@id"},
         "dateCreated": "https://schema.org/DateTime",
+        "license": "https://schema.org/license",
         "value": valueContext
     };
 
diff --git a/src/util/SchemaDefinitions.ts b/src/util/SchemaDefinitions.ts
index f0bbdcd..11db23e 100644
--- a/src/util/SchemaDefinitions.ts
+++ b/src/util/SchemaDefinitions.ts
@@ -1,4 +1,4 @@
-import { Schema } from "express-validator";
+import { Schema, ParamSchema } from "express-validator";
 
 const paginationSchema: Schema = {
     page: {
@@ -15,6 +15,12 @@ const paginationSchema: Schema = {
     }
 };
 
+const licenseSchema: ParamSchema = {
+    in: ["body"],
+    isURL: true,
+    errorMessage: "No valid license URL set."
+};
+
 const filterQuerySchema: Schema = {
     filter: {
         in: ["query"],
@@ -87,7 +93,8 @@ const createRelationSchema: Schema = {
         in: ["body"],
         errorMessage: "New Parent ID is not set.",
         isUUID: true
-    }
+    },
+    relationLicense: licenseSchema
 };
 
 const getInformationSchema: Schema = {
@@ -143,7 +150,9 @@ const createInformationSchema: Schema = {
         isString: true,
         errorMessage: "Measurement targets must be UUIDs.",
         optional: true
-    }
+    },
+    "informationLicense": licenseSchema,
+    "measurementLicense": licenseSchema
 };
 
 const createInformationVersionSchema: Schema = {
@@ -181,6 +190,11 @@ const createComponentSchema: Schema = {
         errorMessage: "Parent ID not set.",
         isUUID: true,
         optional: true
+    },
+    componentLicense: licenseSchema,
+    relationLicense: {
+        ...licenseSchema,
+        optional: true
     }
 };
 
@@ -218,7 +232,8 @@ const createTypeDefinitionBaseSchema: Schema = {
         in: ["body"],
         errorMessage: "No schema definition set.",
         isObject: true
-    }
+    },
+    license: licenseSchema
 };
 
 const createTypeDefinitionURLContextSchema: Schema = {
-- 
GitLab