diff --git a/package-lock.json b/package-lock.json index 5d4a492f2..d397a0c63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3017,6 +3017,40 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@nestjs/schematics/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nestjs/schematics/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nestjs/schematics/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -3256,6 +3290,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "optional": true, "engines": { "node": ">=14" diff --git a/src/published-data/dto/update-published-data.v4.dto.ts b/src/published-data/dto/update-published-data.v4.dto.ts index ad15dcee9..b82194a33 100644 --- a/src/published-data/dto/update-published-data.v4.dto.ts +++ b/src/published-data/dto/update-published-data.v4.dto.ts @@ -6,50 +6,97 @@ import { IsOptional, IsString, } from "class-validator"; -import { PartialType } from "@nestjs/swagger"; +import { + ApiProperty, + ApiPropertyOptional, + ApiTags, + PartialType, +} from "@nestjs/swagger"; import { PublishedDataStatus } from "../interfaces/published-data.interface"; +import { OwnableDto } from "src/common/dto/ownable.dto"; -export class UpdatePublishedDataV4Dto { - /** - * A name or title by which a resource is known. This field has the semantics of Dublin Core - * [dcmi:title](https://www.dublincore.org/specifications/dublin-core/dcmi-terms/terms/title/) - * and [DataCite title](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/title/). - */ +@ApiTags("publishedData") +export class UpdatePublishedDataV4Dto extends OwnableDto { + @ApiProperty({ + type: String, + required: true, + description: + "A name or title by which a resource is known. This field has the semantics of Dublin Core" + + " [dcmi:title](https://www.dublincore.org/specifications/dublin-core/dcmi-terms/terms/title/)" + + " and [DataCite title](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/title/).", + }) @IsString() readonly title: string; - /** - * A brief description of the resource and the context in which the resource was created. This field has the semantics of - * [DataCite description](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/description/) - * with [Abstract](https://datacite-metadata-schema.readthedocs.io/en/4.6/appendices/appendix-1/descriptionType/#abstract). - */ + @ApiProperty({ + type: String, + required: true, + description: + "A brief description of the resource and the context in which the resource was created. This field has the semantics" + + " of [DataCite description](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/description/)" + + " with [Abstract descriptionType](https://datacite-metadata-schema.readthedocs.io/en/4.6/appendices/appendix-1/descriptionType/#abstract).", + }) @IsString() readonly abstract: string; - /** - * Array of one or more Dataset persistent identifier (pid) values that make up the published data. - */ + @ApiProperty({ + type: [String], + required: false, + description: + "Array of one or more datasets' persistent identifier values that" + + " are part of this published data record.", + }) @IsArray() @IsString({ each: true }) readonly datasetPids: string[]; - /** - * Time when doi is successfully registered - */ + @ApiPropertyOptional({ + type: [String], + description: + "Array of one or more proposal identifier values that " + + "are part of this published data record.", + }) + @IsOptional() + @IsArray() + @IsString({ each: true }) + readonly proposalIds?: string[]; + + @ApiPropertyOptional({ + type: [String], + description: + "Array of one or more samples identifier values that " + + "are part of this published data record.", + }) + @IsOptional() + @IsArray() + @IsString({ each: true }) + readonly sampleIds?: string[]; + + @ApiProperty({ + type: Date, + required: false, + description: "Time when doi is successfully registered with registrar", + }) @IsDateString() @IsOptional() readonly registeredTime?: Date; - /** - * Indication of position in publication workflow e.g. registred, private, public - */ + @ApiProperty({ + enum: PublishedDataStatus, + description: + "Indication of position in publication workflow e.g. registred, private, public", + }) @IsEnum(PublishedDataStatus) @IsOptional() readonly status?: string; - /** - * JSON object containing the metadata. This will cover most optional fields of the DataCite schema, and will require a mapping from metadata subfields to DataCite Schema definitions. - */ + @ApiProperty({ + type: Object, + required: false, + default: {}, + description: + "JSON object containing the metadata. This will cover most optional fields of the DataCite schema, and will require a mapping from metadata subfields to DataCite Schema definitions", + }) @IsObject() @IsOptional() readonly metadata?: Record; diff --git a/src/published-data/published-data.v4.controller.ts b/src/published-data/published-data.v4.controller.ts index 6ed23c5c0..b5e18223f 100644 --- a/src/published-data/published-data.v4.controller.ts +++ b/src/published-data/published-data.v4.controller.ts @@ -96,6 +96,7 @@ export class PublishedDataV4Controller { async create( @Body() createPublishedDataDto: CreatePublishedDataV4Dto, ): Promise { + console.log("published data v4 create"); return this.publishedDataService.create(createPublishedDataDto); } diff --git a/src/published-data/schemas/published-data.schema.ts b/src/published-data/schemas/published-data.schema.ts index 264f264cf..e3cd1b9d1 100644 --- a/src/published-data/schemas/published-data.schema.ts +++ b/src/published-data/schemas/published-data.schema.ts @@ -1,10 +1,10 @@ import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; import { ApiProperty } from "@nestjs/swagger"; import { Document } from "mongoose"; -import { QueryableClass } from "src/common/schemas/queryable.schema"; import { v4 as uuidv4 } from "uuid"; import { PublishedDataStatus } from "../interfaces/published-data.interface"; import crypto from "crypto"; +import { OwnableClass } from "src/common/schemas/ownable.schema"; export type PublishedDataDocument = PublishedData & Document; @@ -15,7 +15,7 @@ export type PublishedDataDocument = PublishedData & Document; }, timestamps: true, }) -export class PublishedData extends QueryableClass { +export class PublishedData extends OwnableClass { @Prop({ type: String, unique: true, @@ -102,18 +102,38 @@ export class PublishedData extends QueryableClass { @ApiProperty({ type: [String], - required: true, + required: false, description: - "Array of one or more Dataset persistent identifier (pid) values that" + - " make up the published data.", + "Array of one or more datasets' persistent identifier values that" + + " are part of the published data record.", }) - @Prop({ type: [String], required: true }) + @Prop({ type: [String], required: false }) datasetPids: string[]; + @ApiProperty({ + type: [String], + required: false, + description: + "Array of one or more proposals identifier values that" + + " are part of this published data record.", + }) + @Prop({ type: [String], required: false }) + proposalIds: string[]; + + @ApiProperty({ + type: [String], + required: false, + description: + "Array of one or more samples identifier values that" + + " are part of this published data record.", + }) + @Prop({ type: [String], required: false }) + sampleIds: string[]; + @ApiProperty({ type: Date, required: false, - description: "Time when doi is successfully registered", + description: "Time when doi is successfully registered with registrar", }) @Prop({ type: Date, index: true, required: false }) registeredTime?: Date; diff --git a/test/PublishedData.js b/test/PublishedData_V3.js similarity index 90% rename from test/PublishedData.js rename to test/PublishedData_V3.js index e8a1cb89c..e38ce3a9c 100644 --- a/test/PublishedData.js +++ b/test/PublishedData_V3.js @@ -5,7 +5,6 @@ const sandbox = require("sinon").createSandbox(); let accessTokenArchiveManager = null, accessTokenAdminIngestor = null, - idOrigDatablock = null, pid = null, pidnonpublic = null, @@ -28,7 +27,7 @@ const nonpublictestdataset = { ownerGroup: "examplenonpublicgroup", }; -describe("1600: PublishedData: Test of access to published data", () => { +describe("1600: PublishedData: Test of access to published data V3", () => { before(async () => { db.collection("Dataset").deleteMany({}); db.collection("PublishedData").deleteMany({}); @@ -58,23 +57,53 @@ describe("1600: PublishedData: Test of access to published data", () => { .expect(TestData.EntryCreatedStatusCode) .expect("Content-Type", /json/) .then((res) => { - res.body.should.have.property("affiliation").and.equal(publishedData.affiliation); - res.body.should.have.property("creator").and.deep.equal(publishedData.creator); - res.body.should.have.property("publisher").and.equal(publishedData.publisher); - res.body.should.have.property("publicationYear").and.equal(publishedData.publicationYear); + res.body.should.have + .property("affiliation") + .and.equal(publishedData.affiliation); + res.body.should.have + .property("creator") + .and.deep.equal(publishedData.creator); + res.body.should.have + .property("publisher") + .and.equal(publishedData.publisher); + res.body.should.have + .property("publicationYear") + .and.equal(publishedData.publicationYear); res.body.should.have.property("title").and.equal(publishedData.title); res.body.should.have.property("url").and.equal(publishedData.url); - res.body.should.have.property("abstract").and.equal(publishedData.abstract); - res.body.should.have.property("dataDescription").and.equal(publishedData.dataDescription); - res.body.should.have.property("resourceType").and.equal(publishedData.resourceType); - res.body.should.have.property("numberOfFiles").and.equal(publishedData.numberOfFiles); - res.body.should.have.property("sizeOfArchive").and.equal(publishedData.sizeOfArchive); - res.body.should.have.property("pidArray").and.deep.equal(publishedData.pidArray); - res.body.should.have.property("authors").and.deep.equal(publishedData.authors); - res.body.should.have.property("scicatUser").and.equal(publishedData.scicatUser); - res.body.should.have.property("thumbnail").and.equal(publishedData.thumbnail); - res.body.should.have.property("relatedPublications").and.deep.equal(publishedData.relatedPublications); - res.body.should.have.property("downloadLink").and.equal(publishedData.downloadLink); + res.body.should.have + .property("abstract") + .and.equal(publishedData.abstract); + res.body.should.have + .property("dataDescription") + .and.equal(publishedData.dataDescription); + res.body.should.have + .property("resourceType") + .and.equal(publishedData.resourceType); + res.body.should.have + .property("numberOfFiles") + .and.equal(publishedData.numberOfFiles); + res.body.should.have + .property("sizeOfArchive") + .and.equal(publishedData.sizeOfArchive); + res.body.should.have + .property("pidArray") + .and.deep.equal(publishedData.pidArray); + res.body.should.have + .property("authors") + .and.deep.equal(publishedData.authors); + res.body.should.have + .property("scicatUser") + .and.equal(publishedData.scicatUser); + res.body.should.have + .property("thumbnail") + .and.equal(publishedData.thumbnail); + res.body.should.have + .property("relatedPublications") + .and.deep.equal(publishedData.relatedPublications); + res.body.should.have + .property("downloadLink") + .and.equal(publishedData.downloadLink); res.body.should.have.property("status").and.equal(publishedData.status); doi = encodeURIComponent(res.body["doi"]); }); @@ -149,7 +178,7 @@ describe("1600: PublishedData: Test of access to published data", () => { .get("/api/v3/PublishedData/" + doi) .set("Accept", "application/json") .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) - .expect(TestData.SuccessfulGetStatusCode) + .expect(TestData.SuccessfulPostStatusCode) .expect("Content-Type", /json/) .then((res) => { res.body.should.have.property("status").and.equal("registered"); @@ -216,14 +245,18 @@ describe("1600: PublishedData: Test of access to published data", () => { it("0066: should fetch published data with filter", async () => { const filter = { where: { creator: "New Creator" } }; await request(appUrl) - .get(`/api/v3/PublishedData?filter=${encodeURIComponent(JSON.stringify(filter))}`) + .get( + `/api/v3/PublishedData?filter=${encodeURIComponent(JSON.stringify(filter))}`, + ) .set("Accept", "application/json") .set({ Authorization: `Bearer ${accessTokenAdminIngestor}` }) .expect(TestData.SuccessfulGetStatusCode) .expect("Content-Type", /json/) .then((res) => { res.body.length.should.equal(1); - res.body[0].should.have.property("creator").and.deep.equal(["New Creator"]); + res.body[0].should.have + .property("creator") + .and.deep.equal(["New Creator"]); res.body[0].should.have.property("thumbnail"); }); return request(appUrl) diff --git a/test/PublishedDataV4.js b/test/PublishedData_V4.js similarity index 98% rename from test/PublishedDataV4.js rename to test/PublishedData_V4.js index 131cb82db..201a41b6a 100644 --- a/test/PublishedDataV4.js +++ b/test/PublishedData_V4.js @@ -38,7 +38,7 @@ const nonpublictestdataset = { ownerGroup: "examplenonpublicgroup", }; -describe("1600: PublishedDataV4: Test of access to published data v4 endpoints", () => { +describe("1610: PublishedDataV4: Test of access to published data v4 endpoints", () => { before(async () => { db.collection("Dataset").deleteMany({}); db.collection("PublishedData").deleteMany({}); @@ -100,7 +100,9 @@ describe("1600: PublishedDataV4: Test of access to published data v4 endpoints", .expect(TestData.EntryCreatedStatusCode) .expect("Content-Type", /json/) .then((res) => { - res.body.should.have.property("title").and.be.string; + res.body.should.have + .property("title") + .and.be.string(publishedData.title); res.body.should.have.property("metadata"); res.body.metadata.should.have.property("publisher"); res.body.should.have.property("status").and.equal(defaultStatus); diff --git a/test/TestData.js b/test/TestData.js index aa6a59de9..63bdcbf71 100644 --- a/test/TestData.js +++ b/test/TestData.js @@ -1353,6 +1353,7 @@ const TestData = { landingPage: "doi.ess.eu/detail/", }, datasetPids: [], + ownerGroup: "admin", }, InstrumentCorrect1: {