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 zcmaEQoAK&>#tC9lnW+q5z*YdJ7#JKNbf)S?19nDbUPeAf5k^r)Nk$b$RYna)O-4ON zGe#>$JH{}^aK;G6XvUb$QH&p$nLQc;H~X?0F!Qft_{^}5VI6}c1WxYZkQO#=aBDDa zFm2$1LgNPa$-6i_CbMwHPEO{WV93SD%}~h5(_q=))!^IU8Rg^aomv@|m{Xd1nSqyq zkAa_&pHYw@Zy}>VgZDy4p$4DHyo%C>jA9HM7cvMnFgI9S0xObY*th~@H=``WI!1X$ z1%~Ae%fa^gHJCQ|Hv~*B;3{WS-~58>Ib*#xqYgt6!}$iwhM<Pf25Xo-`iw>ld5ah> zGhAt~ZLnL!Xv}ER5Zn;b-~_S3oZ;R=2AKxl1_ub=8sq}&1|66S>=`z$7Z7E1U|7!R z#OTcE!mymtjnSRajnR$K3j!IIGx{?uXHZ@aava0*hOh?XhVX`nhR6ovhNy<<hNy<9 zh8PH(T*zz17&UnfuMT78=9|2~7`b#}lyWkYQ}c>bC(q<lXZL}!FY=o+2{26N5Qt+E zV4R#L@Yagajj;~R);5TRAhIF3!MGu%A+;e5Y-u`*rM-e_Oiad`zX~2fvrmyXEH$|# zzX)Ng>*PPew>d%4mer8k;5qq$NQj^l<7&n=U`x0fOdIkV!Z*8$7Bhks6*ZJLcy2x@ zwu{lxiSZ>!4Z}Ldx1b1vBoziphUJW3!Q$Z1X{ZH<O<jX=gK>jtLp?Yup-E`-9*OJB zU{j|y%xLi3JV)jP6PP=<VL^lE=3My(h@DFtRy25S{-yxsu5DP~;JLY8X$zy}I;Q)m zRx>?EvU)q%${kRvccNIGqmmCXd{4vv2G7Y)RQ&`c8P+j#Fsx(dV&(=J(!jOZS<Rjm z?4ZXDPa8ZpcWa+#=3mDmiEQQMOnqs7(}rIthELXSVzOg&W64I1K9*vTxe(mQ$OUp; zBO`YsBM&GB8yR^~qA=JfopHtH-A2xg%rW{}lm8h{k<g0K*NIWe%uCBJ%1tcE%+G_x z;!Hk8El&(#qZlQf7^U3Q#NyJT)ZEm(5+voqz8JzrlP~hSOuk}rPQ@ZQImy%@#Z1@C zIK^Do#K<C5*CNq0RX5Sh+}PC8FxAM&Fm3WN(_{fBmgz9x2!o<|v!$5<BR5ZjWh0|( zBcptS=jIag?~MHGSlLj5tjbbW)U=UN3pvahj2juXCx5UJ+kD7U2Wp0HBcpzU=jNYQ z>lj^}SpC3Otz!*BHj807YZO=<oY)!}%|Xs+WVC?9c_X7GvK^aW+jug{f}Lm6$Y|H# z2`w;Kb6NAD1=Hj}J7rKpV69?U$6CW$3o^TbYjdmJdv=Jw5*itkK&j6yAL_{TM#fB# zBi#=&iaW7ofHW|yW6MEy<m8K<B9h^ajKwflm7uulpJxduwXp3)O)YFk!Dc}{)(pz+ zjf^dgjIEH=(uR^+Huyv^F>Tq*<txd^9;2_N6Qfix`Gd3QWE(#<W~~_g$w_|hqBzrz zCT5btlXTQEQxsTra(-?>ejaKv6TlF>$nUcGwci?MNNCPzWSrIDxp`4g1T-|~H!?14 z@Z8KAG7}n6%NrS2!Xt`3n>`m6QM*II5yf7?u#UZoy&4o&4P2Ywhvu-<bINlr<lM%& zgL4<>9?pH7CpoWi-sHT^d5`k}=OfN<od3C)xLCN@xcIpgxRkh5xYW2bxU{%*xb(OT zxQw`Fb1mUo#&wpbmS+;r6rO23Gk9k4EazFnvyNv2&sLu8JUe-I^Bmzh&U2FIG|v^D z>pVAkZu30h733A>73CG@mE@J?oqQ`wsXmrBo;QOxi+3XbKLG}TIDrI#>jG~C-U)mV z_$2T}kWr9LkVBA5kY7+xP*_k@P)<-$P+3q_P*2cM&{)t^&`vO0Fjp{Nuu!mAuvD;I zuu`yEuvV~Muu-sCuvM^Kuv4&Guvf5OaH8O3!Ks4N1-A?C6g(t&MDVqUl1PKdcTt{t zQ9e-tQ6W(gQAJS|Q8iIbQEgFOQFqY*(O}U~(QwfO(L&K;(NfWJ(Mr*3(OS`Z(MHi` z(Z`~1MBj;tiro-<EB0ROqu6J$ui{MNtm5qAT;e?9eBv77hT<mTX5tp&j^aV$A>v`; z5#mweG2(IJ3F1lODdNY(&x>Ca{~-|}QJ*W3FHtB_EKw@aB+)9-F3}~?Bhe=@U1FBR z9Eo`n%O$QzT$8vVaZBQk#65`z5|1RFNIa8xA@NG$jl?^N4-%gwzDRtN_#yF2;*Z2X zNd`$FNoh%0Nf*h5QgTwpQl?VoQkGKIQV~+AQdv?tQh8FvQl(PmQk7CoQhid>rDjRZ zsh653wOneI)EcREQro2tNF9<oB6Upagw!di%TiaR{zzYwel7i0`n~i=>CZAuGW;?^ zG9ohKGLkaVGAc5<GG;OsGFCD+GIlZ!GM+LKGEp)yGI25qGD$KiGHEgyGW9ZzGF>t~ zGMi;i$efZnBXdsXg3Mi+2QrUjp2|Fzc`5T(ww_IvQ<htnS5{0`T~<?8TUJ+AU)E68 zSk_e5T-H){k?d;OwX#>_TjXcT&z7GnKVN>K{5tuK@|)$i$?uTgC4Wx-y8JEqJM#DB zpUeM{|0VxN{+|Ma0+RxZ0-FMd0+&L8LZw2r!XiapMI}WQMKwhYMJ+{hMJq)cMSDd@ zMQ6qEdc_3AWW`j)bj1S2M#W~uR>gM3PQ`A;Ud4XJiHegIe=0F4u_$RPO;cK}v{q@o z(nh7tN(Yn<D;-rjp>#^=jM7!58%np7?kGJ~`lj?l>6g+UrGLr{%1p{E%52IU$|=gZ z%K6IER5(;*RpeC^Rg_g!Rg6?jRm@eaRBTl2RNPhSy;OWu{8YkKT2$IpI#jw;dQ|#U zCa6qOnW8dHWroTul{qT&R2HZ#Qdy$1Ol5`2DwQ=V>r^(VoKU%_a#`h<YPjleH32mt zH4!y2H3>CUH4QZ_HC;7*HA6LTwGg#%wMeySwG_2dwQ{vewQ99mwR*KiwPv+ewRW|q zYVXuOsEgOD=c~7<x2boicd7TNFHzs9zD<3H`Y!eT>Ic;is~=TAqkdWaj{1G|hw6{j z->AP=|ET_1{f`E_2B!wM2CoLchM<P9hO~x?hMI=2Mv_K~Mw&*3MwUjoMwLd5M!iO( zMzcnb#$=7D8q+mqYRuMHqOn<HtHySXof^9}_G;|cIH*y7SmTbyQ;p}Ee45Ids+#JW znwr|07Mix2_L`2GZkisNUYb6dp_&nzQJOKDshSy@S(-VTrJ9R0muN22T%oy2bB*RY z%?+BHG`DDO)7+uCOLLFrKFtG~hcu699@9Lbc}nw)<~hwLnr}7VYl&$UYkksY*XGpb z*5=jb*Ot+i*H*08R?$||*3dT8Hq*Ayw$irIcGV8i4%3d%j?#|Nj?+%iPSQ@%F3_&j zuGU_py<K~!_HOOH+WWQ7XrI@<sC`BIn)VIthuTlHpJ~6){;0#G!=l5c!=b~a!=uBe zBcLOsBcfBK)2!2~vqqOkS5a44S5;SCS5wza*HYJ7*G|_#x86zDTh~uFKsQJ?TDL>D zOSeb2Pj`auB;6^x({yL(&eENuJ5P6k?jqeKy32G|=&sUTqq|ObgYG8XExHGFPwAe~ z{j3+D_felspF^KZpGTihUs_*DUqxR{UqfGC-%#IJ-&EgR-&NmFKTtndKU6<XKT$tf zKUF_Zzfiwezf`}jUVpXzTK)C<8}&EqZ`I$fzf*s={$Bn4`Umw7>mSuWu76VhwEkKB z^ZFO{FY8~`zpnpU|BL=N16hMAgU^N>hFpd`hWv(thU$hUhL(obhIWR|hHi$QhTet| zhDnCmhIxhshDC<eh7E>IhAoC|hW&=K4CfloH(X@6#BiD63d3!N_4^GE8on_6Yxv)Y z$%xg6-AKep+(^<$#z@{s(MZck*GS*U(8$Ut-6+c_$0*OJ(5S?y%&5Ys+Njp3-l);2 z*{Id1-Kf*3$EeR}g3%<SDMr(bW*F@>I%IUj=(Xu|)30VT&DNQ1Fxzal&1{F+QL__f zr_9cpT`;?3cH8Wc*%Py8^=2>3UYUJ1XEJ9sXE*0G=P~Cq7cdtx7cn<6w>7snPcyGJ zuQhKlZ#Hi=pJYDWe5Uzq^9AOM&6k<4FyCmt#eAFj4)cTNN6e3zpD@2@e#iX2`9t$3 z=FiMun7=arZ2rgmpM|Q0m4%Iky@iv7i$$PCh((x1q(zKHoJG1tmPL+5eV#?RMTbR~ zMUO?l#YBrK7Sk<eTFkbXYsqZMW65V}YPrC2tL1jfU6y+-_gkK^yl8pZ@~Y)6%e$5j zEFW3EwtQ##!Sa*kZ!1140V^RZ5i2n(2`ecp87ny}1uG>hZL0{YXscMOc&j9<6st6= z46AIbT&sMmLaSn{Qmb;SN~@ZBt2(O&t0t=!t2V0+tGQOotX5c^x7M*<Wxe0}p!E^! z<JKpwuUX%;zHNQa`l0n>>o?Z#tv_0Sw*F(oYr}6NXd_}HW+Q1MV<TsyV54NyZ8ODY zn$2EYSz9Ap6I*jzD_a{|Pg@^bKifdt5Zf@@c-th~6x%f0eA_v;^KBQ}F1D>-X1l_6 zmF*ha^|l*rH`{Kt-EO<ncDL<b+XJ?TY>(I;vpr#Z%Jz)yL)%xjZ|sEa3hX}Ev)Z%U zbJ_FS^V`eV%iAm3tJtgCYuX#xo7$V(TiQF>2iu3*hucTl$Joc)C)uair`c!NpR>Pi zf75}%A={zGq0XVvp~Yc>!%T+-4vXs@mO89(Smm(C;i$uLhj)(5j;xLxj@*vCj#7@Y zj`EI5j;fC8js}j#j;4<0jt-8wjs=cIjwO!ej+Ktpj<t>rj!lj&j%|(|j$MvDj(v_3 z9Va_Zb)4=v({Z-rT*vi}I~;d8K6J8kdgS!o>8H~lr~l53&V0^-&ce=O&XUg3&h;wJ z>du<Z+Ri4<iOwm`Y0eqW+0J>+1<pmzrOxHfmCn`9wa)d<jn2)^ZO$FeUCuquea;h{ zCpoWh-srs9`If7JYo8mZo1B}1o3fjln}(aIo0Xf5o1L4po12@bo3~qtTew@KTeMq> zTe@4OTee$?TdiAzTeDlMTf1AQ+oXE8DQ>&n4cuMb-QB(1eck=tW8CB26WvqX)7>-O zi`+}y%iSy8o7^Y6Pj#Q}KFfWM`+WCB?n~U4xv%hG^WgUo^sw+)<+0!6pvMu9;~pnH zu6f+_xb1Pz<Dti6k2fCgJwAGT_W0w;>&fpa=qchU<|*kZ<0<E<;Hl)<>e=Tx!Lxq5 zm$;XXm!6lQmx-5|m$R3LmzS51SD;sjSGZTCSCUt%SGrfGSCLn#SGiZESCiLzuT5TC zytaAm^xEyU*K5DmA+IA|$GlE>o$@;4b<XR8*JZD(Ue~>DdfoQA>viAjt=BiNAKvob zHQv8`_<aO@M0~`3q<l1dOnt0;Y<=u~T<U$?eY|{peByl4eR6#Ad<uMue5!rwd>VY3 ze7b$6`ONg0?K973fzKkJB|htYcKGb_dFb=a=ZDX4pMSm#zP!EyzCymDz7oDtzRJF8 zz8bz-zQ(=@zRA9+zUjVMzPY~nzJ<OezGc1@zE!?8zIDD0zD>TZzU{u9zTLjPzWu)S z6MdKXuJv8-do7?Z;7wpgU~OQ1U{hdgV0++{z?p%w1Lp=V3S1hvB5+mU=D=-%I|6qF z9u7Pfcp~sr;N>8OAm$*}Aod`xAf6z;Ab}v^AkiT4Aju%<AlV@KAjKe+AhjTkAgv&s zAiW@iAiE&<AkUzJptHgG!7agU!JWZ9!F~0?vxDaaF9=>7yexP{@W$X>!Fz)D1s@1L z6nrH3Z1A1n`@s)`9|u1Rei8gC_)YM;5XKO$5S|d@5RVYA5Z{o1kf4zGkfe~5ko1tO zkeraxkcyD1keZOzkZB<^LS}``4VfRZC}e5K@{pAwt3x?Mg+fI_twX1Ut`1!rx*>FP z=+@BsL!n1QkB6QLJsWyH^hW6I(7U1cLtljc4E-JYH;f^SIgBlgGmJZoH;g|lKddmU zDy$}Kaky2ue|TVcNO*X7WO!P5W_WgZUU*@6ad=I5eRyMdb9hhq-0=C~3&WR$FAHB8 zz9xKK_=fOJ5z-MV5o!^>kP$y7CI~IW-U4C3$jHB&OVfFn`Qv<iUGkGlLBj!{5rfH7 zvl=EhW{FHz$yS@(nxn8eD_fdzvRAgk<fS>U1*Mr)nQfW9nZuY<nJbz5nP*R4nCk)n 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