diff --git a/apis/core/bootstrap/shapes/cube-project.ts b/apis/core/bootstrap/shapes/cube-project.ts index af9ab29f4..d7e89519b 100644 --- a/apis/core/bootstrap/shapes/cube-project.ts +++ b/apis/core/bootstrap/shapes/cube-project.ts @@ -1,5 +1,5 @@ import { cc, sh1, shape, editor } from '@cube-creator/core/namespace' -import { dash, dcterms, hydra, rdf, rdfs, schema, sh } from '@tpluscode/rdf-ns-builders' +import { dash, dcterms, hydra, rdf, rdfs, schema, sh, xsd } from '@tpluscode/rdf-ns-builders' import { turtle } from '@tpluscode/rdf-string' import $rdf from 'rdf-ext' @@ -22,6 +22,7 @@ const csvCubeShape = turtle` ${sh.ignoredProperties} ( ${rdfs.label} ${schema.maintainer} + ${cc.isHiddenCube} ${rdf.type} ${generatedProperties} ) ; @@ -49,6 +50,7 @@ const existingCubeShape = turtle` ${sh.ignoredProperties} ( ${rdfs.label} ${schema.maintainer} + ${cc.isHiddenCube} ${rdf.type} ${generatedProperties} ) ; @@ -95,6 +97,7 @@ const importedCubeShape = turtle` ${sh.ignoredProperties} ( ${rdfs.label} ${schema.maintainer} + ${cc.isHiddenCube} ${rdf.type} ${generatedProperties} ) ; @@ -144,6 +147,16 @@ const projectProperties = ({ xoneAlternatives = [] }: { xoneAlternatives?: unkno ${hydra.collection} ; ${sh.order} 20 ; ] ; + ${sh.property} [ + ${sh.name} "Hide this cube?" ; + ${sh.description} "Hidden cubes are only visible in *visualize* for logged-in users" ; + ${sh.path} ${cc.isHiddenCube} ; + ${sh.datatype} ${xsd.boolean} ; + ${sh.defaultValue} ${true} ; + ${sh.minCount} 1 ; + ${sh.maxCount} 1 ; + ${sh.order} 21 ; + ] ; ${sh.xone} ( ${xoneAlternatives} ) ;` export const CubeProjectShape = turtle` diff --git a/apis/core/lib/domain/cube-projects/create.ts b/apis/core/lib/domain/cube-projects/create.ts index ded7dccd9..52f7ac67d 100644 --- a/apis/core/lib/domain/cube-projects/create.ts +++ b/apis/core/lib/domain/cube-projects/create.ts @@ -1,6 +1,8 @@ import type { NamedNode } from '@rdfjs/types' +import $rdf from 'rdf-ext' import { GraphPointer } from 'clownface' -import { dcterms, rdfs, schema } from '@tpluscode/rdf-ns-builders' +import { isLiteral } from 'is-graph-pointer' +import { dcterms, rdfs, schema, xsd } from '@tpluscode/rdf-ns-builders' import { cc } from '@cube-creator/core/namespace' import * as Project from '@cube-creator/model/Project' import * as Dataset from '@cube-creator/model/Dataset' @@ -13,6 +15,8 @@ import { cubeNamespaceAllowed } from '../organization/query' import { createImportJob } from '../job/create' import { exists } from './queries' +const xsdTrue = $rdf.literal('true', xsd.boolean) + interface CreateProjectCommand { projectsCollection: GraphPointer resource: GraphPointer @@ -23,10 +27,11 @@ interface CreateProjectCommand { interface CreateProjectResource extends Omit { label: string maintainer: NamedNode + isHiddenCube: boolean projectNode: GraphPointer } -async function createCsvProjectResource({ user, projectNode, store, label, maintainer, resource }: CreateProjectResource) { +async function createCsvProjectResource({ user, projectNode, store, label, maintainer, isHiddenCube, resource }: CreateProjectResource) { const cubeIdentifier = resource.out(dcterms.identifier).value if (!cubeIdentifier) { throw new Error('Missing cube identifier name') @@ -45,6 +50,7 @@ async function createCsvProjectResource({ user, projectNode, store, label, maint creator: user, label, maintainer, + isHiddenCube, cubeIdentifier, sourceKind, }) @@ -60,7 +66,7 @@ async function createCsvProjectResource({ user, projectNode, store, label, maint return { project, dataset } } -async function createImportProjectResources({ resource, user, projectNode, store, label, maintainer }: CreateProjectResource) { +async function createImportProjectResources({ resource, user, projectNode, store, label, maintainer, isHiddenCube }: CreateProjectResource) { const sourceCube = resource.out(cc['CubeProject/sourceCube']).term if (sourceCube?.termType !== 'NamedNode') { throw new Error('Missing cube identifier') @@ -91,6 +97,7 @@ async function createImportProjectResources({ resource, user, projectNode, store creator: user, label, maintainer, + isHiddenCube, sourceCube, sourceEndpoint, sourceGraph, @@ -124,6 +131,11 @@ export async function createProject({ if (!maintainer || maintainer.termType !== 'NamedNode') { throw new DomainError('Missing organization or not a named node') } + const hiddenCube = resource.out(cc.isHiddenCube) + if (!isLiteral(hiddenCube, xsd.boolean)) { + throw new DomainError('Missing flag isHiddenCube or not a boolean') + } + const isHiddenCube = xsdTrue.equals(hiddenCube.term) let project: Project.Project let dataset: Dataset.Dataset @@ -140,6 +152,7 @@ export async function createProject({ store, label, maintainer, + isHiddenCube, resource, })) } else if (isImportProject) { @@ -150,6 +163,7 @@ export async function createProject({ resource, label, maintainer, + isHiddenCube, })) } else { throw new error.BadRequest(`Unexpected value of ${cc.projectSourceKind.value}`) diff --git a/apis/core/lib/domain/cube-projects/import.ts b/apis/core/lib/domain/cube-projects/import.ts index 0c20f319d..d6b6e9f68 100644 --- a/apis/core/lib/domain/cube-projects/import.ts +++ b/apis/core/lib/domain/cube-projects/import.ts @@ -5,8 +5,9 @@ import $rdf from 'rdf-ext' import { cc } from '@cube-creator/core/namespace' import { Files } from '@cube-creator/express/multipart' import { createMinimalProject, Project } from '@cube-creator/model/Project' -import { dcterms, rdfs, schema, rdf } from '@tpluscode/rdf-ns-builders/strict' +import { dcterms, rdfs, schema, rdf, xsd } from '@tpluscode/rdf-ns-builders/strict' import clownface, { GraphPointer } from 'clownface' +import { isLiteral } from 'is-graph-pointer' import { obj } from 'through2' import TermSet from '@rdfjs/term-set' import { Organization } from '@rdfine/schema' @@ -16,6 +17,8 @@ import * as id from '../identifiers' import { ResourceStore } from '../../ResourceStore' import { exists } from './queries' +const xsdTrue = $rdf.literal('true', xsd.boolean) + interface ImportProject { projectsCollection: GraphPointer resource: GraphPointer @@ -97,12 +100,18 @@ export async function importProject({ if (!maintainer) { throw new BadRequest('Missing organization') } + const hiddenCube = resource.out(cc.isHiddenCube) + if (!isLiteral(hiddenCube, xsd.boolean)) { + throw new DomainError('Missing flag isHiddenCube or not a boolean') + } + const isHiddenCube = xsdTrue.equals(hiddenCube.term) const projectNode = await store.createMember(projectsCollection.term, id.cubeProject(label)) const project = createMinimalProject(projectNode, { creator: user, maintainer, + isHiddenCube, label, }) diff --git a/apis/core/lib/domain/cube-projects/update.ts b/apis/core/lib/domain/cube-projects/update.ts index 0fcf5f474..d7f245495 100644 --- a/apis/core/lib/domain/cube-projects/update.ts +++ b/apis/core/lib/domain/cube-projects/update.ts @@ -1,8 +1,9 @@ import type { NamedNode } from '@rdfjs/types' +import $rdf from 'rdf-ext' import { GraphPointer } from 'clownface' import { DomainError } from '@cube-creator/api-errors' import { cc } from '@cube-creator/core/namespace' -import { dcterms, rdfs, schema } from '@tpluscode/rdf-ns-builders' +import { dcterms, rdfs, schema, xsd } from '@tpluscode/rdf-ns-builders' import { CsvProject, ImportProject, Project } from '@cube-creator/model' import type { Organization } from '@rdfine/schema' import type { Dictionary } from '@rdfine/prov' @@ -11,6 +12,8 @@ import { ResourceStore } from '../../ResourceStore' import { cubeNamespaceAllowed } from '../organization/query' import { exists, previouslyPublished } from './queries' +const xsdTrue = $rdf.literal('true', xsd.boolean) + interface UpdateProjectCommand { resource: GraphPointer store: ResourceStore @@ -23,6 +26,7 @@ export async function updateProject({ const project = await store.getResource(resource.term) project.rename(resource.out(rdfs.label).value) + project.isHiddenCube = xsdTrue.equals(resource.out(cc.isHiddenCube).term) const maintainer = project.updateMaintainer(resource.out(schema.maintainer).term) let currentCube: NamedNode diff --git a/apis/core/lib/domain/job/create.ts b/apis/core/lib/domain/job/create.ts index 4f352947b..2b1a86283 100644 --- a/apis/core/lib/domain/job/create.ts +++ b/apis/core/lib/domain/job/create.ts @@ -76,12 +76,14 @@ export async function createPublishJob({ const metadata = await store.getResource(project.dataset) + const targetGraph = project.isHiddenCube ? organization.hiddenGraph : organization.publishGraph + const jobPointer = await store.createMember(jobCollection.term, id.job(jobCollection)) const job = Job.createPublish(jobPointer, { project: projectPointer, name: 'Publish job', revision: project.nextRevision, - publishGraph: organization.publishGraph, + publishGraph: targetGraph, status: metadata?.pointer.out(schema.creativeWorkStatus).term, publishedTo: metadata?.pointer.out(schema.workExample).term, }) diff --git a/apis/core/test/domain/cube-projects/create.test.ts b/apis/core/test/domain/cube-projects/create.test.ts index c5962e2bc..47b70f08b 100644 --- a/apis/core/test/domain/cube-projects/create.test.ts +++ b/apis/core/test/domain/cube-projects/create.test.ts @@ -52,6 +52,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(dcterms.identifier, 'ubd/28') .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) // when @@ -73,6 +74,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(dcterms.identifier, 'ubd/28') .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) // when @@ -130,6 +132,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(dcterms.identifier, 'ubd/28') .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) // when @@ -155,6 +158,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(dcterms.identifier, 'ubd/28') .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) // when @@ -205,6 +209,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(dcterms.identifier, 'ubd/28') .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) // when @@ -222,6 +227,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(schema.maintainer, organization.id) .addOut(dcterms.identifier, 'ubd/28') + .addOut(cc.isHiddenCube, true) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) // when @@ -239,6 +245,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(schema.maintainer, organization.id) .addOut(dcterms.identifier, 'ubd/28') + .addOut(cc.isHiddenCube, true) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) // when @@ -255,6 +262,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(schema.maintainer, organization.id) .addOut(dcterms.identifier, 'ubd/28') + .addOut(cc.isHiddenCube, true) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) // when @@ -271,6 +279,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(schema.maintainer, organization.id) .addOut(dcterms.identifier, 'ubd/28') + .addOut(cc.isHiddenCube, true) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) // when @@ -287,6 +296,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(schema.maintainer, organization.id) .addOut(dcterms.identifier, 'ubd/28') + .addOut(cc.isHiddenCube, true) .addOut(cc.publishGraph, $rdf.namedNode('http://example.com/published-cube')) .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) @@ -318,6 +328,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) .addOut(dcterms.identifier, 'ubd/28') + .addOut(cc.isHiddenCube, true) .addOut(schema.maintainer, organization.id) // when @@ -350,6 +361,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) .addOut(dcterms.identifier, 'ubd/28') + .addOut(cc.isHiddenCube, true) .addOut(schema.maintainer, organization.id) // when @@ -388,6 +400,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) .addOut(dcterms.identifier, 'ubd/28') + .addOut(cc.isHiddenCube, true) .addOut(schema.maintainer, organization.id) // when @@ -435,6 +448,7 @@ describe('domain/cube-projects/create', () => { .addOut(rdfs.label, 'Foo bar project') .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) .addOut(dcterms.identifier, 'ubd/28') + .addOut(cc.isHiddenCube, true) .addOut(schema.maintainer, organization.id) // when @@ -486,6 +500,7 @@ describe('domain/cube-projects/create', () => { .addOut(cc['CubeProject/sourceCube'], $rdf.namedNode('http://example.cube/')) .addOut(cc['CubeProject/sourceEndpoint'], $rdf.namedNode('http://example.endpoint/')) .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) // when const { project } = await createProject({ resource, store, projectsCollection, user }) @@ -503,6 +518,7 @@ describe('domain/cube-projects/create', () => { .addOut(cc['CubeProject/sourceCube'], $rdf.namedNode('http://example.cube/')) .addOut(cc['CubeProject/sourceEndpoint'], $rdf.namedNode('http://example.endpoint/')) .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) // when const { project } = await createProject({ resource, store, projectsCollection, user }) @@ -517,6 +533,7 @@ describe('domain/cube-projects/create', () => { .namedNode('') .addOut(rdfs.label, 'Import project') .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) .addOut(cc['CubeProject/sourceEndpoint'], $rdf.namedNode('http://example.endpoint/')) .addOut(cc.projectSourceKind, cc['projectSourceKind/ExistingCube']) @@ -533,6 +550,7 @@ describe('domain/cube-projects/create', () => { .namedNode('') .addOut(rdfs.label, 'Import project') .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) .addOut(cc['CubeProject/sourceCube'], $rdf.literal('http://example.cube/')) .addOut(cc['CubeProject/sourceEndpoint'], $rdf.namedNode('http://example.endpoint/')) .addOut(cc.projectSourceKind, cc['projectSourceKind/ExistingCube']) @@ -550,6 +568,7 @@ describe('domain/cube-projects/create', () => { .namedNode('') .addOut(rdfs.label, 'Import project') .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) .addOut(cc['CubeProject/sourceCube'], $rdf.namedNode('http://example.cube/')) .addOut(cc.projectSourceKind, cc['projectSourceKind/ExistingCube']) @@ -566,6 +585,7 @@ describe('domain/cube-projects/create', () => { .namedNode('') .addOut(rdfs.label, 'Import project') .addOut(schema.maintainer, organization.id) + .addOut(cc.isHiddenCube, true) .addOut(cc['CubeProject/sourceCube'], $rdf.namedNode('http://example.cube/')) .addOut(cc['CubeProject/sourceEndpoint'], $rdf.namedNode('http://example.endpoint/')) .addOut(cc.publishGraph, $rdf.namedNode('http://example.com/published-cube')) diff --git a/apis/core/test/domain/cube-projects/import.test.ts b/apis/core/test/domain/cube-projects/import.test.ts index d2ff8d806..2cbd894d2 100644 --- a/apis/core/test/domain/cube-projects/import.test.ts +++ b/apis/core/test/domain/cube-projects/import.test.ts @@ -32,6 +32,7 @@ describe('@cube-creator/core-api/lib/domain/cube-projects/import', () => { resource = blankNode() .addOut(rdfs.label, 'UBD Imported') .addOut(schema.maintainer, ex.Bafu) + .addOut(cc.isHiddenCube, true) const organization = namedNode(ex.Bafu) .addOut(rdf.type, schema.Organization) .addOut(cc.namespace, $rdf.namedNode('https://test.ld.admin.ch/org/')) diff --git a/apis/core/test/domain/cube-projects/update.test.ts b/apis/core/test/domain/cube-projects/update.test.ts index f4c5970ca..62a4da241 100644 --- a/apis/core/test/domain/cube-projects/update.test.ts +++ b/apis/core/test/domain/cube-projects/update.test.ts @@ -55,6 +55,7 @@ describe('domain/cube-projects/update', () => { .node(id) .addOut(rdfs.label, 'Created name') .addOut(schema.maintainer, bafu.id) + .addOut(cc.isHiddenCube, true) .addOut(dcterms.identifier, 'cube') .addOut(cc.projectSourceKind, cc['projectSourceKind/CSV']) } @@ -101,6 +102,23 @@ describe('domain/cube-projects/update', () => { expect(editedProject.pointer.out(rdfs.label).term?.value).to.eq('Edited name') }) + it('updates isHiddenCube', async () => { + // given + const resource = projectPointer(project.term) + resource + .deleteOut(cc.isHiddenCube) + .addOut(cc.isHiddenCube, false) + + // when + const editedProject = await updateProject({ + resource, + store, + }) + + // then + expect(editedProject.pointer.out(cc.isHiddenCube).term?.value).to.eq('false') + }) + describe('when maintainer changes', () => { let editedProject: Project @@ -360,6 +378,7 @@ describe('domain/cube-projects/update', () => { .node(id) .addOut(rdfs.label, 'Created name') .addOut(schema.maintainer, bafu.id) + .addOut(cc.isHiddenCube, true) .addOut(cc['CubeProject/sourceCube'], $rdf.namedNode('http://external.cube')) .addOut(cc['CubeProject/sourceEndpoint'], $rdf.namedNode('http://external.cube/query')) .addOut(cc.projectSourceKind, cc['projectSourceKind/ExistingCube']) diff --git a/apis/core/test/domain/job/create.test.ts b/apis/core/test/domain/job/create.test.ts index 47b483e0e..2a22104bf 100644 --- a/apis/core/test/domain/job/create.test.ts +++ b/apis/core/test/domain/job/create.test.ts @@ -27,6 +27,7 @@ describe('domain/job/create', () => { maintainer: organization, cubeIdentifier: 'test-cube', dataset: $rdf.namedNode('myDataset'), + isHiddenCube: false, }) const tableCollection = namedNode('myTables') const csvMapping = namedNode('myCsvMapping') @@ -131,4 +132,30 @@ describe('domain/job/create', () => { await expect(promise).rejectedWith(DomainError) }) }) + + describe('createPublishJob for hiddenCube', () => { + let queries: Pick + + beforeEach(() => { + queries = { + getCubeTable: sinon.stub().resolves($rdf.namedNode('observations')), + } + + if (!organization.pointer.has(cc.publishGraph).value) { + organization.pointer.addOut(cc.publishGraph, $rdf.namedNode('publishGraph')) + } + project.isHiddenCube = true + }) + + it('creates a job resource', async () => { + // when + const job = await createPublishJob({ resource: jobCollection.term, store, queries }) + + // then + expect(job.has(rdf.type, cc.PublishJob).values.length).to.eq(1) + expect(job.out(cc.project).value).to.eq('myProject') + + expect(job.out(cc.publishGraph).term).to.deep.eq($rdf.namedNode('publishGraph/hidden')) + }) + }) }) diff --git a/cli/lib/commands/publish.ts b/cli/lib/commands/publish.ts index e8d4a8292..79c8216d1 100644 --- a/cli/lib/commands/publish.ts +++ b/cli/lib/commands/publish.ts @@ -29,7 +29,7 @@ export default runner.create({ const { publishStore, job: jobUri } = options const Hydra = variable.get('apiClient') - const { job, namespace, cubeIdentifier, cubeCreatorVersion } = await getJob(jobUri, Hydra) + const { job, namespace, cubeIdentifier, cubeCreatorVersion, isHiddenCube } = await getJob(jobUri, Hydra) if (options.to === 'filesystem' && !variable.has('targetFile')) { variable.set('targetFile', tempy.file()) @@ -59,6 +59,7 @@ export default runner.create({ variable.set('revision', job.revision) variable.set('namespace', namespace) variable.set('cubeIdentifier', cubeIdentifier) + variable.set('isHiddenCube', isHiddenCube) logger.info(`Publishing cube <${cubeIdentifier}>`) }, async after(options, variables) { @@ -77,6 +78,7 @@ async function getJob(jobUri: string, Hydra: HydraClient): Promise<{ namespace: string cubeIdentifier: string cubeCreatorVersion: string | undefined | null + isHiddenCube: boolean }> { const jobResource = await Hydra.loadResource(jobUri) const cubeCreatorVersion = jobResource.response?.xhr.headers.get('x-cube-creator') @@ -105,5 +107,6 @@ async function getJob(jobUri: string, Hydra: HydraClient): Promise<{ namespace: datasetResource.representation?.root?.hasPart[0].id.value, cubeIdentifier, cubeCreatorVersion, + isHiddenCube: project.isHiddenCube, } } diff --git a/cli/lib/publish/hiddenCube.ts b/cli/lib/publish/hiddenCube.ts new file mode 100644 index 000000000..96f77013b --- /dev/null +++ b/cli/lib/publish/hiddenCube.ts @@ -0,0 +1,25 @@ +import type { Context } from 'barnard59-core/lib/Pipeline' +import $rdf from 'rdf-ext' +import through2 from 'through2' +import clownface from 'clownface' +import { cc } from '@cube-creator/core/namespace' + +export function inject(this: Pick) { + const isHiddenCube = this.variables.get('isHiddenCube') + const cubeNamespace = this.variables.get('namespace') + const revision = this.variables.get('revision') + + const cubeId = $rdf.namedNode(`${cubeNamespace}/${revision}`) + + const dataset = $rdf.dataset() + clownface({ dataset }) + .node(cubeId) + .addOut(cc.isHiddenCube, !!isHiddenCube) + + return through2.obj( + (chunk, enc, cb) => cb(null, chunk), + function (done) { + dataset.forEach(this.push.bind(this)) + done() + }) +} diff --git a/cli/lib/variables.ts b/cli/lib/variables.ts index e72a51abe..cde95a76b 100644 --- a/cli/lib/variables.ts +++ b/cli/lib/variables.ts @@ -39,5 +39,6 @@ declare module 'barnard59-core' { originalValueQuads: DatasetExt cubeCreatorVersion: string cliVersion: string + isHiddenCube: boolean } } diff --git a/cli/pipelines/publish.ttl b/cli/pipelines/publish.ttl index 22d39e94e..1f2160029 100644 --- a/cli/pipelines/publish.ttl +++ b/cli/pipelines/publish.ttl @@ -49,6 +49,7 @@ :steps [ :stepList ( <#loadCube> <#countInputQuads> <#injectCubeRevision> + <#injectIsHiddenCube> <#injectObservedBy> <#injectSoftwareVersions> ) ] @@ -245,6 +246,11 @@ _:get a code:EcmaScript ] ; code:arguments ( "jobUri"^^:VariableName ) . +<#injectIsHiddenCube> + a :Step ; + code:implementedBy [ code:link ; + a code:EcmaScript ] . + <#injectSoftwareVersions> a :Step ; code:implementedBy [ code:link ; diff --git a/e2e-tests/csv-source/delete.hydra b/e2e-tests/csv-source/delete.hydra index 849979c5b..350fcb051 100644 --- a/e2e-tests/csv-source/delete.hydra +++ b/e2e-tests/csv-source/delete.hydra @@ -27,7 +27,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "Delete Source Test Project" ; dcterms:identifier "delete-csv-test-cube" ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 201 diff --git a/e2e-tests/csv-source/get-csv.hydra b/e2e-tests/csv-source/get-csv.hydra index 43d95bbbb..23901e767 100644 --- a/e2e-tests/csv-source/get-csv.hydra +++ b/e2e-tests/csv-source/get-csv.hydra @@ -27,7 +27,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "GetCSV Test Project" ; dcterms:identifier "get-csv-test-cube" ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 201 diff --git a/e2e-tests/csv-source/upload.hydra b/e2e-tests/csv-source/upload.hydra index ca544b5a0..a6358f230 100644 --- a/e2e-tests/csv-source/upload.hydra +++ b/e2e-tests/csv-source/upload.hydra @@ -27,7 +27,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "Upload Test Project" ; dcterms:identifier "upload-test-cube" ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 201 diff --git a/e2e-tests/cube-projects/create-invalid.hydra b/e2e-tests/cube-projects/create-invalid.hydra index aaaf6035c..bc3810b25 100644 --- a/e2e-tests/cube-projects/create-invalid.hydra +++ b/e2e-tests/cube-projects/create-invalid.hydra @@ -19,7 +19,8 @@ With Class api:EntryPoint { prefix schema: <> cc:projectSourceKind ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 @@ -32,7 +33,8 @@ With Class api:EntryPoint { prefix cc: prefix schema: <> cc:projectSourceKind ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 @@ -48,7 +50,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "" ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 @@ -65,7 +68,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "Test Project" ; cc:namespace ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 @@ -84,7 +88,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "Test Project" ; dcterms:identifier "ubd/28" ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 @@ -103,7 +108,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "Test Project" ; dcterms:identifier "example/px-cube" ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 @@ -123,7 +129,8 @@ With Class api:EntryPoint { rdfs:label "Test Project" ; CubeProject:sourceCube ; CubeProject:sourceEndpoint ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 @@ -143,7 +150,8 @@ With Class api:EntryPoint { rdfs:label "Test Project" ; CubeProject:sourceCube ; CubeProject:sourceEndpoint ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 @@ -163,7 +171,8 @@ With Class api:EntryPoint { rdfs:label "Test Project" ; CubeProject:sourceCube ; CubeProject:sourceEndpoint ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 diff --git a/e2e-tests/cube-projects/create.hydra b/e2e-tests/cube-projects/create.hydra index bac0a9cbc..8b3ddd622 100644 --- a/e2e-tests/cube-projects/create.hydra +++ b/e2e-tests/cube-projects/create.hydra @@ -26,7 +26,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "Test Project" ; dcterms:identifier "test-cube" ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 201 @@ -41,6 +42,7 @@ With Class api:EntryPoint { Expect Property schema:maintainer Expect Property dcterms:identifier Expect Property cc:export + Expect Property cc:isHiddenCube Expect Link cc:projectDetails { Expect Property schema:hasPart } @@ -73,7 +75,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "Test Project" ; dcterms:identifier "test-cube" ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 400 diff --git a/e2e-tests/cube-projects/delete.hydra b/e2e-tests/cube-projects/delete.hydra index df7b15a23..3f890aec8 100644 --- a/e2e-tests/cube-projects/delete.hydra +++ b/e2e-tests/cube-projects/delete.hydra @@ -25,7 +25,8 @@ With Class api:EntryPoint { <> cc:projectSourceKind ; rdfs:label "Deleted Test Project" ; dcterms:identifier "delete-test-cube" ; - schema:maintainer . + schema:maintainer ; + cc:isHiddenCube true . ``` } => { Expect Status 201 diff --git a/e2e-tests/cube-projects/update.hydra b/e2e-tests/cube-projects/update.hydra index f368d1062..30e688afc 100644 --- a/e2e-tests/cube-projects/update.hydra +++ b/e2e-tests/cube-projects/update.hydra @@ -35,7 +35,8 @@ With Class cc:CubeProject { cc:dataset ; cc:jobCollection ; cc:latestPublishedRevision 1 ; - cc:projectSourceKind . + cc:projectSourceKind ; + cc:isHiddenCube true . ``` } => { Expect Status 200 diff --git a/packages/core/namespace.ts b/packages/core/namespace.ts index 39ca5c27c..ff54c8c99 100644 --- a/packages/core/namespace.ts +++ b/packages/core/namespace.ts @@ -83,7 +83,8 @@ type CubeCreatorProperty = 'export' | 'projectDetails' | 'validationReport' | - 'batchMapping' + 'batchMapping' | + 'isHiddenCube' type OtherTerms = 'dash' | diff --git a/packages/model/Organization.ts b/packages/model/Organization.ts index 89ef0195e..f83fa319e 100644 --- a/packages/model/Organization.ts +++ b/packages/model/Organization.ts @@ -1,4 +1,5 @@ import type { DatasetCore, NamedNode, Term } from '@rdfjs/types' +import $rdf from 'rdf-ext' import { Organization, OrganizationMixin as SchemaOrganizationMixin } from '@rdfine/schema' import { Constructor, namespace, property, ResourceIdentifier } from '@tpluscode/rdfine' import { cc } from '@cube-creator/core/namespace' @@ -13,6 +14,7 @@ interface CreateIdentifier { interface OrganizationEx { publishGraph: NamedNode + readonly hiddenGraph: NamedNode namespace: NamedNode dataset?: NamedNode accessURL: NamedNode @@ -31,6 +33,10 @@ export function OrganizationMixin(base: Base): Mixin { @property.literal({ path: lindasSchema.datasetNextDateModified, type: Date }) plannedNextUpdate?: Date + + @property.literal({ path: cc.isHiddenCube, datatype: xsd.boolean, type: Boolean }) + isHiddenCube!: boolean } return Impl @@ -104,7 +108,7 @@ export function ProjectMixin(base: Base): Mixin { ProjectMixin.appliesTo = cc.CubeProject -type MinimalFields = 'creator' | 'label' | 'maintainer' +type MinimalFields = 'creator' | 'label' | 'maintainer' | 'isHiddenCube' export const createMinimalProject = initializer(ProjectMixin) type CsvProjectMandatoryFields = MinimalFields | 'cubeIdentifier' | 'sourceKind' diff --git a/packages/model/package.json b/packages/model/package.json index ebbb71073..3c3181c4c 100644 --- a/packages/model/package.json +++ b/packages/model/package.json @@ -12,14 +12,15 @@ "@rdfine/shacl": "^0.8.5", "@tpluscode/rdf-ns-builders": "^1.0.0", "@tpluscode/rdfine": "^0.5.19", + "@types/rdf-ext": "^1.3.8", "is-uri": "^1.2.0", "uri-template": "^1.0.1" }, "devDependencies": { "@cube-creator/testing": "^0.1.21", - "@types/clownface": "^1", + "@types/clownface": "^1", "@types/is-uri": "^1", - "@rdfjs/types": "^1.1.0", +"@rdfjs/types": "^1.1.0", "alcaeus": "^2", "chai": "^4.3.4", "mocha": "^10"