diff --git a/apps/envited.ascs.digital/common/asset/constants.ts b/apps/envited.ascs.digital/common/asset/constants.ts index 2ae6071e..b5e4a64f 100644 --- a/apps/envited.ascs.digital/common/asset/constants.ts +++ b/apps/envited.ascs.digital/common/asset/constants.ts @@ -2,4 +2,6 @@ export const MANIFEST_FILE = 'manifest.json' export const LICENSE_FILE = 'LICENSE' +export const README_FILE = 'README.md' + export const DOMAIN_METADATA_FILE = 'metadata/domainMetadata.json' diff --git a/apps/envited.ascs.digital/common/constants/errors.ts b/apps/envited.ascs.digital/common/constants/errors.ts index 87a6c14f..f0cf20d5 100644 --- a/apps/envited.ascs.digital/common/constants/errors.ts +++ b/apps/envited.ascs.digital/common/constants/errors.ts @@ -9,6 +9,7 @@ export const ERRORS = { ASSET_INVALID: 'Asset validation failed', ASSET_FILE_NOT_FOUND: 'No valid metadata.json found', FILES_NOT_FOUND: 'File(s) not found', + README_FILE_NOT_FOUND: 'README.md file not found', NOT_ALLOWED_TO_DELETE_ASSET: 'Not allowed to delete asset', MINTED_ASSET_CANNOT_BE_DELETED: 'Minted asset cannot be deleted', } diff --git a/apps/envited.ascs.digital/common/validator/shacl/shacl.test.ts b/apps/envited.ascs.digital/common/validator/shacl/shacl.test.ts index c6bee913..585ad3c1 100644 --- a/apps/envited.ascs.digital/common/validator/shacl/shacl.test.ts +++ b/apps/envited.ascs.digital/common/validator/shacl/shacl.test.ts @@ -5,6 +5,7 @@ describe('common/validator/shacl', () => { it('Should return a valid result', async () => { // when ... we want to validate a asset file const file = 'ZIP' + const validateReadmeStub = jest.fn().mockResolvedValue('FILE_NAME') const validateManifestStub = jest.fn().mockResolvedValue({ conforms: true, data: { @@ -31,6 +32,7 @@ describe('common/validator/shacl', () => { validateDomainMetadata: validateDomainMetadataStub, checkIfAllFilesInManifestExists: checkIfAllFilesInManifestExistsStub, countAmountOfFilesInZip: countAmountOfFilesInZipStub, + validateReadme: validateReadmeStub, })(file as any) expect(validateManifestStub).toHaveBeenCalledWith('ZIP') diff --git a/apps/envited.ascs.digital/common/validator/shacl/shacl.ts b/apps/envited.ascs.digital/common/validator/shacl/shacl.ts index 01493228..469408c8 100644 --- a/apps/envited.ascs.digital/common/validator/shacl/shacl.ts +++ b/apps/envited.ascs.digital/common/validator/shacl/shacl.ts @@ -5,18 +5,18 @@ import { all, equals, has, isEmpty, keys, omit, pipe } from 'ramda' import ValidationReport from 'rdf-validate-shacl/src/validation-report' import { countAmountOfFilesInZip, extractFromFile, read } from '../../archive' -import { MANIFEST_FILE } from '../../asset/constants' +import { MANIFEST_FILE, README_FILE } from '../../asset/constants' import { Manifest } from '../../asset/types' import { getAllManifestLinksAndFormatPaths, getDomainMetadataPath } from '../../asset/validateAndCreateMetadata.utils' import { ERRORS } from '../../constants' import { CONTEXT_DROP_SCHEMAS } from './shacl.constants' import { ContentType, Schema, ValidationSchema } from './shacl.types' import { - addManifestAndReadMeFiles, fetchShaclSchema, formatFilesErrorMessage, loadDataset, parseStreamToDataset, + subtractManifestAndReadMeFiles, validateShacl, } from './shacl.utils' @@ -26,6 +26,7 @@ export const _validateShaclFile = validateDomainMetadata, checkIfAllFilesInManifestExists, countAmountOfFilesInZip, + validateReadme, }: { validateManifest: (file: File) => Promise<{ conforms: boolean; data: any }> validateDomainMetadata: (file: File, manifest: Manifest) => Promise<{ conforms: boolean; data: any }> @@ -34,9 +35,19 @@ export const _validateShaclFile = manifest: Manifest, ) => Promise<{ errors: { error: string }[]; amount: number }> countAmountOfFilesInZip: (file: File) => Promise + validateReadme: (file: File) => Promise }) => async (file: File) => { try { + const readmeExists = await validateReadme(file) + if (!readmeExists) { + return { + isValid: false, + data: {}, + error: ERRORS.README_FILE_NOT_FOUND, + } + } + const { conforms: manifestConforms, data: manifest } = await validateManifest(file) const manifestFiles = await checkIfAllFilesInManifestExists(file, manifest) @@ -49,13 +60,13 @@ export const _validateShaclFile = } const amountOfFilesInZip = await countAmountOfFilesInZip(file) - const allowedAmountOfFiles = addManifestAndReadMeFiles(manifestFiles.amount) + const amountWithoutManifestAndReadme = subtractManifestAndReadMeFiles(amountOfFilesInZip) - if (!equals(amountOfFilesInZip)(allowedAmountOfFiles)) { + if (!equals(amountWithoutManifestAndReadme)(manifestFiles.amount)) { return { isValid: false, data: {}, - error: `${amountOfFilesInZip} files found, should be ${allowedAmountOfFiles} files`, + error: `${amountWithoutManifestAndReadme} files found, should be ${manifestFiles.amount} files`, } } @@ -144,6 +155,22 @@ export const validateManifest = _validateManifest({ validateShaclSchema, }) +export const _validateReadme = + ({ getShaclDataFromZip }: { getShaclDataFromZip: (file: File, fileName: string) => Promise }) => + async (file: File) => { + try { + await getShaclDataFromZip(file, README_FILE) + + return true + } catch { + return false + } + } + +export const validateReadme = _validateReadme({ + getShaclDataFromZip, +}) + export const _validateDomainMetadata = ({ getShaclDataFromZip, @@ -229,6 +256,7 @@ export const validateShaclFile = _validateShaclFile({ validateManifest, checkIfAllFilesInManifestExists, countAmountOfFilesInZip, + validateReadme, }) export const _validateShaclDataWithSchema = diff --git a/apps/envited.ascs.digital/common/validator/shacl/shacl.utils.test.ts b/apps/envited.ascs.digital/common/validator/shacl/shacl.utils.test.ts index 11cd5b9a..c4fa9a80 100644 --- a/apps/envited.ascs.digital/common/validator/shacl/shacl.utils.test.ts +++ b/apps/envited.ascs.digital/common/validator/shacl/shacl.utils.test.ts @@ -75,8 +75,8 @@ describe('common/validator/shacl/shacl.utils', () => { expect(result).toEqual(expected) }) - describe('addManifestAndReadMeFiles', () => { - const result = SUT.addManifestAndReadMeFiles(12) + describe('subtractManifestAndReadMeFiles', () => { + const result = SUT.subtractManifestAndReadMeFiles(16) expect(result).toEqual(14) }) diff --git a/apps/envited.ascs.digital/common/validator/shacl/shacl.utils.ts b/apps/envited.ascs.digital/common/validator/shacl/shacl.utils.ts index b5a8a5c5..17eb75af 100644 --- a/apps/envited.ascs.digital/common/validator/shacl/shacl.utils.ts +++ b/apps/envited.ascs.digital/common/validator/shacl/shacl.utils.ts @@ -1,7 +1,7 @@ import { DatasetCore, Quad } from '@rdfjs/types' import rdf, { DefaultEnv } from '@zazuko/env' import { Dataset } from '@zazuko/env/lib/Dataset' -import { add, join, map, pipe } from 'ramda' +import { flip, join, map, pipe, subtract } from 'ramda' import rdfParser, { RdfParser } from 'rdf-parse' import SHACLValidator from 'rdf-validate-shacl' import { Readable } from 'stream' @@ -66,4 +66,4 @@ export const formatFilesErrorMessage = (errors: { error: string }[]) => (x: string) => `${ERRORS.FILES_NOT_FOUND} - ${x}`, )(errors) -export const addManifestAndReadMeFiles = add(2) +export const subtractManifestAndReadMeFiles = flip(subtract)(2)