mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00

* feat: rootpath for static assets and links1 * fix: static asset handler respects root path * fix: use rootPath for links * tests: fix the tests after adding consuctor params * feat: change matchregex instead of stored URLs * feat: baseUrl for handlebar engine and templates * feat: full baseUrl passed to templates * test: fix integration tests + templates * chore: implement requested changes * docs: Describe TemplateEngine interface changes Co-authored-by: Joachim Van Herwegen <joachimvh@gmail.com>
138 lines
6.0 KiB
TypeScript
138 lines
6.0 KiB
TypeScript
import { DataFactory } from 'n3';
|
|
import type { ResourceIdentifier } from '../../../../src/http/representation/ResourceIdentifier';
|
|
import { TemplatedResourcesGenerator } from '../../../../src/pods/generate/TemplatedResourcesGenerator';
|
|
import type {
|
|
FileIdentifierMapper,
|
|
FileIdentifierMapperFactory,
|
|
ResourceLink,
|
|
} from '../../../../src/storage/mapping/FileIdentifierMapper';
|
|
import { ensureTrailingSlash, trimTrailingSlashes } from '../../../../src/util/PathUtil';
|
|
import { readableToString } from '../../../../src/util/StreamUtil';
|
|
import { HandlebarsTemplateEngine } from '../../../../src/util/templates/HandlebarsTemplateEngine';
|
|
import { mockFileSystem } from '../../../util/Util';
|
|
|
|
const { namedNode } = DataFactory;
|
|
|
|
jest.mock('fs');
|
|
|
|
class DummyFactory implements FileIdentifierMapperFactory {
|
|
public async create(base: string, rootFilePath: string): Promise<FileIdentifierMapper> {
|
|
const trimBase = trimTrailingSlashes(base);
|
|
const trimRoot = trimTrailingSlashes(rootFilePath);
|
|
return {
|
|
async mapFilePathToUrl(filePath: string, isContainer: boolean): Promise<ResourceLink> {
|
|
let path = `${trimBase}${filePath.slice(trimRoot.length)}`;
|
|
const isMetadata = filePath.endsWith('.meta');
|
|
if (isMetadata) {
|
|
path = path.slice(0, -'.meta'.length);
|
|
}
|
|
return {
|
|
identifier: { path: isContainer ? ensureTrailingSlash(path) : path },
|
|
filePath,
|
|
contentType: isContainer ? undefined : 'text/turtle',
|
|
isMetadata,
|
|
};
|
|
},
|
|
} as any;
|
|
}
|
|
}
|
|
|
|
async function genToArray<T>(iterable: AsyncIterable<T>): Promise<T[]> {
|
|
const arr: T[] = [];
|
|
for await (const result of iterable) {
|
|
arr.push(result);
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
describe('A TemplatedResourcesGenerator', (): void => {
|
|
const rootFilePath = '/templates/pod';
|
|
// Using handlebars engine since it's smaller than any possible dummy
|
|
const generator = new TemplatedResourcesGenerator(rootFilePath, new DummyFactory(), new HandlebarsTemplateEngine('http://test.com/'));
|
|
let cache: { data: any };
|
|
const template = '<{{webId}}> a <http://xmlns.com/foaf/0.1/Person>.';
|
|
const location = { path: 'http://test.com/alice/' };
|
|
const webId = 'http://alice/#profile';
|
|
|
|
beforeEach(async(): Promise<void> => {
|
|
cache = mockFileSystem(rootFilePath);
|
|
});
|
|
|
|
it('fills in a template with the given options.', async(): Promise<void> => {
|
|
cache.data = { 'template.hbs': template };
|
|
const result = await genToArray(generator.generate(location, { webId }));
|
|
const identifiers = result.map((res): ResourceIdentifier => res.identifier);
|
|
const id = { path: `${location.path}template` };
|
|
expect(identifiers).toEqual([ location, id ]);
|
|
|
|
const { representation } = result[1];
|
|
expect(representation.binary).toBe(true);
|
|
expect(representation.metadata.contentType).toBe('text/turtle');
|
|
await expect(readableToString(representation.data)).resolves
|
|
.toBe(`<${webId}> a <http://xmlns.com/foaf/0.1/Person>.`);
|
|
});
|
|
|
|
it('creates the necessary containers.', async(): Promise<void> => {
|
|
cache.data = { container: { container: { 'template.hbs': template }}};
|
|
const result = await genToArray(generator.generate(location, { webId }));
|
|
const identifiers = result.map((res): ResourceIdentifier => res.identifier);
|
|
const id = { path: `${location.path}container/container/template` };
|
|
expect(identifiers).toEqual([
|
|
location,
|
|
{ path: `${location.path}container/` },
|
|
{ path: `${location.path}container/container/` },
|
|
id,
|
|
]);
|
|
|
|
const { representation } = result[3];
|
|
await expect(readableToString(representation.data)).resolves
|
|
.toBe(`<${webId}> a <http://xmlns.com/foaf/0.1/Person>.`);
|
|
});
|
|
|
|
it('copies the file stream directly if no template extension is found.', async(): Promise<void> => {
|
|
cache.data = { noTemplate: template };
|
|
const result = await genToArray(generator.generate(location, { webId }));
|
|
const identifiers = result.map((res): ResourceIdentifier => res.identifier);
|
|
const id = { path: `${location.path}noTemplate` };
|
|
expect(identifiers).toEqual([ location, id ]);
|
|
|
|
const { representation } = result[1];
|
|
expect(representation.binary).toBe(true);
|
|
expect(representation.metadata.contentType).toBe('text/turtle');
|
|
await expect(readableToString(representation.data)).resolves.toEqual(template);
|
|
});
|
|
|
|
it('adds metadata from .meta files.', async(): Promise<void> => {
|
|
const meta = '<> <pre:has> "metadata".';
|
|
cache.data = { '.meta': meta, container: { 'template.meta': meta, template }};
|
|
|
|
// Not using options since our dummy template generator generates invalid turtle
|
|
const result = await genToArray(generator.generate(location, { webId }));
|
|
const identifiers = result.map((res): ResourceIdentifier => res.identifier);
|
|
expect(identifiers).toEqual([
|
|
location,
|
|
{ path: `${location.path}container/` },
|
|
{ path: `${location.path}container/template` },
|
|
]);
|
|
// Root has the 1 raw metadata triple (with <> changed to its identifier) and content-type
|
|
const rootMetadata = result[0].representation.metadata;
|
|
expect(rootMetadata.identifier.value).toBe(location.path);
|
|
expect(rootMetadata.quads()).toHaveLength(2);
|
|
expect(rootMetadata.get(namedNode('pre:has'))?.value).toBe('metadata');
|
|
expect(rootMetadata.contentType).toBe('text/turtle');
|
|
|
|
// Container has no metadata triples besides content-type
|
|
const contMetadata = result[1].representation.metadata;
|
|
expect(contMetadata.identifier.value).toBe(`${location.path}container/`);
|
|
expect(contMetadata.quads()).toHaveLength(1);
|
|
expect(contMetadata.contentType).toBe('text/turtle');
|
|
|
|
// Document has the 1 raw metadata triple (with <> changed to its identifier) and content-type
|
|
const docMetadata = result[2].representation.metadata;
|
|
expect(docMetadata.identifier.value).toBe(`${location.path}container/template`);
|
|
expect(docMetadata.quads()).toHaveLength(2);
|
|
expect(docMetadata.get(namedNode('pre:has'))?.value).toBe('metadata');
|
|
expect(docMetadata.contentType).toBe('text/turtle');
|
|
});
|
|
});
|