-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
321 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@kopflos-cms/core": patch | ||
--- | ||
|
||
Added request decorators |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import type { DatasetCore } from '@rdfjs/types' | ||
import { kl } from '../ns.js' | ||
import type { Kopflos, KopflosResponse, ResultEnvelope } from './Kopflos.js' | ||
import type { HandlerArgs } from './handler.js' | ||
import log from './log.js' | ||
|
||
export interface RequestDecorator { | ||
applicable?: (args: HandlerArgs) => boolean | ||
(args: HandlerArgs, next: () => Promise<ResultEnvelope>): Promise<KopflosResponse> | KopflosResponse | ||
} | ||
|
||
export interface DecoratorLookup { | ||
(kopflos: Kopflos, args: HandlerArgs): Promise<RequestDecorator[]> | ||
} | ||
|
||
export const loadDecorators = async ({ env, apis }: Pick<Kopflos<DatasetCore>, 'env' | 'apis'>, args: HandlerArgs) => { | ||
const api = apis.node(args.resourceShape.out(kl.api)) | ||
|
||
const decorators = api.out(kl.decorator) | ||
|
||
const loaded = await Promise.all(decorators.map(async decorator => { | ||
const implNode = decorator.out(env.ns.code.implementedBy) | ||
const impl = await env.load<RequestDecorator>(implNode) | ||
if (!impl) { | ||
log.warn('Decorator has no implementation') | ||
} | ||
if (!impl?.applicable || impl.applicable(args)) { | ||
return impl | ||
} | ||
})) | ||
|
||
return loaded.filter(Boolean) as RequestDecorator[] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import url from 'node:url' | ||
import { createStore } from 'mocha-chai-rdf/store.js' | ||
import { expect } from 'chai' | ||
import type { DatasetCore } from '@rdfjs/types' | ||
import rdf from '@zazuko/env-node' | ||
import { loadDecorators } from '../../lib/decorators.js' | ||
import type { HandlerArgs } from '../../lib/handler.js' | ||
import { createEnv } from '../../lib/env/index.js' | ||
import type { Kopflos, KopflosConfig } from '../../lib/Kopflos.js' | ||
import { ex } from '../../../testing-helpers/ns.js' | ||
import { kl } from '../../ns.js' | ||
import { bar, foo, personOnly } from '../support/decorators.js' | ||
|
||
describe('@kopflos-cms/core/lib/decorators.js', () => { | ||
let kopflos: Pick<Kopflos<DatasetCore>, 'env' | 'apis'> | ||
const config: KopflosConfig = { | ||
baseIri: 'http://localhost:1429/', | ||
sparql: { | ||
default: { | ||
endpointUrl: 'http://localhost:7878/query?union-default-graph', | ||
updateUrl: 'http://localhost:7878/update', | ||
}, | ||
}, | ||
codeBase: url.fileURLToPath(import.meta.url), | ||
} | ||
|
||
beforeEach(createStore(import.meta.url, { | ||
format: 'trig', | ||
})) | ||
|
||
beforeEach(function () { | ||
const apis = this.rdf.graph.has(rdf.ns.rdf.type, kl.Api) | ||
kopflos = { | ||
env: createEnv(config), | ||
apis, | ||
} | ||
}) | ||
|
||
describe('loadDecorators', () => { | ||
context('decorators without implementation', () => { | ||
it('are skipped', async function () { | ||
// given | ||
const args = <HandlerArgs>{ | ||
resourceShape: this.rdf.graph.namedNode(ex.resourceShape), | ||
} | ||
|
||
// when | ||
const decorators = await loadDecorators(kopflos, args) | ||
|
||
// then | ||
expect(decorators).to.be.empty | ||
}) | ||
}) | ||
|
||
context('decorators with implementations', () => { | ||
it('are loaded', async function () { | ||
// given | ||
const args = <HandlerArgs>{ | ||
resourceShape: this.rdf.graph.namedNode(ex.resourceShape), | ||
} | ||
|
||
// when | ||
const decorators = await loadDecorators(kopflos, args) | ||
|
||
// then | ||
expect(decorators).to.contain.all.members([foo, bar]) | ||
}) | ||
}) | ||
|
||
context('decorators with limitations', () => { | ||
it('loads only those passing the check', async function () { | ||
// given | ||
const args = <HandlerArgs>{ | ||
resourceShape: this.rdf.graph.namedNode(ex.resourceShape), | ||
} | ||
|
||
// when | ||
const decorators = await loadDecorators(kopflos, args) | ||
|
||
// then | ||
expect(decorators).to.deep.eq([personOnly]) | ||
}) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.