mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
refactor: Add isContainerPath function
This commit is contained in:
parent
1073c2ff4c
commit
75e4f73c3f
@ -12,7 +12,13 @@ import { MethodNotAllowedHttpError } from '../util/errors/MethodNotAllowedHttpEr
|
|||||||
import { NotFoundHttpError } from '../util/errors/NotFoundHttpError';
|
import { NotFoundHttpError } from '../util/errors/NotFoundHttpError';
|
||||||
import { NotImplementedError } from '../util/errors/NotImplementedError';
|
import { NotImplementedError } from '../util/errors/NotImplementedError';
|
||||||
import { UnsupportedHttpError } from '../util/errors/UnsupportedHttpError';
|
import { UnsupportedHttpError } from '../util/errors/UnsupportedHttpError';
|
||||||
import { ensureTrailingSlash, getParentContainer, trimTrailingSlashes } from '../util/PathUtil';
|
import {
|
||||||
|
ensureTrailingSlash,
|
||||||
|
getParentContainer,
|
||||||
|
isContainerIdentifier,
|
||||||
|
isContainerPath,
|
||||||
|
trimTrailingSlashes,
|
||||||
|
} from '../util/PathUtil';
|
||||||
import { parseQuads } from '../util/QuadUtil';
|
import { parseQuads } from '../util/QuadUtil';
|
||||||
import { generateResourceQuads } from '../util/ResourceUtil';
|
import { generateResourceQuads } from '../util/ResourceUtil';
|
||||||
import { CONTENT_TYPE, HTTP, LDP, RDF } from '../util/UriConstants';
|
import { CONTENT_TYPE, HTTP, LDP, RDF } from '../util/UriConstants';
|
||||||
@ -93,7 +99,7 @@ export class DataAccessorBasedStore implements ResourceStore {
|
|||||||
|
|
||||||
// When a POST method request targets a non-container resource without an existing representation,
|
// When a POST method request targets a non-container resource without an existing representation,
|
||||||
// the server MUST respond with the 404 status code.
|
// the server MUST respond with the 404 status code.
|
||||||
if (!parentMetadata && !container.path.endsWith('/')) {
|
if (!parentMetadata && !isContainerIdentifier(container)) {
|
||||||
throw new NotFoundHttpError();
|
throw new NotFoundHttpError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +110,7 @@ export class DataAccessorBasedStore implements ResourceStore {
|
|||||||
const newID = this.createSafeUri(container, representation.metadata, parentMetadata);
|
const newID = this.createSafeUri(container, representation.metadata, parentMetadata);
|
||||||
|
|
||||||
// Write the data. New containers will need to be created if there is no parent.
|
// Write the data. New containers will need to be created if there is no parent.
|
||||||
await this.writeData(newID, representation, newID.path.endsWith('/'), !parentMetadata);
|
await this.writeData(newID, representation, isContainerIdentifier(newID), !parentMetadata);
|
||||||
|
|
||||||
return newID;
|
return newID;
|
||||||
}
|
}
|
||||||
@ -128,7 +134,7 @@ export class DataAccessorBasedStore implements ResourceStore {
|
|||||||
if (oldMetadata && isContainer !== this.isExistingContainer(oldMetadata)) {
|
if (oldMetadata && isContainer !== this.isExistingContainer(oldMetadata)) {
|
||||||
throw new ConflictHttpError('Input resource type does not match existing resource type.');
|
throw new ConflictHttpError('Input resource type does not match existing resource type.');
|
||||||
}
|
}
|
||||||
if (isContainer !== identifier.path.endsWith('/')) {
|
if (isContainer !== isContainerIdentifier(identifier)) {
|
||||||
throw new UnsupportedHttpError('Containers should have a `/` at the end of their path, resources should not.');
|
throw new UnsupportedHttpError('Containers should have a `/` at the end of their path, resources should not.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +178,7 @@ export class DataAccessorBasedStore implements ResourceStore {
|
|||||||
* @param identifier - Identifier that needs to be checked.
|
* @param identifier - Identifier that needs to be checked.
|
||||||
*/
|
*/
|
||||||
protected async getNormalizedMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
|
protected async getNormalizedMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
|
||||||
const hasSlash = identifier.path.endsWith('/');
|
const hasSlash = isContainerIdentifier(identifier);
|
||||||
try {
|
try {
|
||||||
return await this.accessor.getMetadata(identifier);
|
return await this.accessor.getMetadata(identifier);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
@ -312,7 +318,7 @@ export class DataAccessorBasedStore implements ResourceStore {
|
|||||||
isContainer = this.isExistingContainer(metadata);
|
isContainer = this.isExistingContainer(metadata);
|
||||||
} catch {
|
} catch {
|
||||||
const slug = suffix ?? metadata.get(HTTP.slug)?.value;
|
const slug = suffix ?? metadata.get(HTTP.slug)?.value;
|
||||||
isContainer = Boolean(slug?.endsWith('/'));
|
isContainer = Boolean(slug && isContainerPath(slug));
|
||||||
}
|
}
|
||||||
return isContainer;
|
return isContainer;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
decodeUriPathComponents,
|
decodeUriPathComponents,
|
||||||
encodeUriPathComponents,
|
encodeUriPathComponents,
|
||||||
ensureTrailingSlash,
|
ensureTrailingSlash,
|
||||||
|
isContainerIdentifier,
|
||||||
trimTrailingSlashes,
|
trimTrailingSlashes,
|
||||||
} from '../util/PathUtil';
|
} from '../util/PathUtil';
|
||||||
import type { FileIdentifierMapper, ResourceLink } from './FileIdentifierMapper';
|
import type { FileIdentifierMapper, ResourceLink } from './FileIdentifierMapper';
|
||||||
@ -74,7 +75,7 @@ export class ExtensionBasedMapper implements FileIdentifierMapper {
|
|||||||
let filePath = this.getAbsolutePath(path);
|
let filePath = this.getAbsolutePath(path);
|
||||||
|
|
||||||
// Container
|
// Container
|
||||||
if (identifier.path.endsWith('/')) {
|
if (isContainerIdentifier(identifier)) {
|
||||||
this.logger.debug(`URL ${identifier.path} points to the container ${filePath}`);
|
this.logger.debug(`URL ${identifier.path} points to the container ${filePath}`);
|
||||||
return {
|
return {
|
||||||
identifier,
|
identifier,
|
||||||
|
@ -12,6 +12,7 @@ import { ConflictHttpError } from '../../util/errors/ConflictHttpError';
|
|||||||
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
|
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
|
||||||
import { isSystemError } from '../../util/errors/SystemError';
|
import { isSystemError } from '../../util/errors/SystemError';
|
||||||
import { UnsupportedMediaTypeHttpError } from '../../util/errors/UnsupportedMediaTypeHttpError';
|
import { UnsupportedMediaTypeHttpError } from '../../util/errors/UnsupportedMediaTypeHttpError';
|
||||||
|
import { isContainerIdentifier } from '../../util/PathUtil';
|
||||||
import { parseQuads, pushQuad, serializeQuads } from '../../util/QuadUtil';
|
import { parseQuads, pushQuad, serializeQuads } from '../../util/QuadUtil';
|
||||||
import { generateContainmentQuads, generateResourceQuads } from '../../util/ResourceUtil';
|
import { generateContainmentQuads, generateResourceQuads } from '../../util/ResourceUtil';
|
||||||
import { CONTENT_TYPE, DCTERMS, POSIX, RDF, XSD } from '../../util/UriConstants';
|
import { CONTENT_TYPE, DCTERMS, POSIX, RDF, XSD } from '../../util/UriConstants';
|
||||||
@ -62,10 +63,10 @@ export class FileDataAccessor implements DataAccessor {
|
|||||||
public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
|
public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
|
||||||
const link = await this.resourceMapper.mapUrlToFilePath(identifier);
|
const link = await this.resourceMapper.mapUrlToFilePath(identifier);
|
||||||
const stats = await this.getStats(link.filePath);
|
const stats = await this.getStats(link.filePath);
|
||||||
if (!identifier.path.endsWith('/') && stats.isFile()) {
|
if (!isContainerIdentifier(identifier) && stats.isFile()) {
|
||||||
return this.getFileMetadata(link, stats);
|
return this.getFileMetadata(link, stats);
|
||||||
}
|
}
|
||||||
if (identifier.path.endsWith('/') && stats.isDirectory()) {
|
if (isContainerIdentifier(identifier) && stats.isDirectory()) {
|
||||||
return this.getDirectoryMetadata(link, stats);
|
return this.getDirectoryMetadata(link, stats);
|
||||||
}
|
}
|
||||||
throw new NotFoundHttpError();
|
throw new NotFoundHttpError();
|
||||||
@ -131,9 +132,9 @@ export class FileDataAccessor implements DataAccessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!identifier.path.endsWith('/') && stats.isFile()) {
|
if (!isContainerIdentifier(identifier) && stats.isFile()) {
|
||||||
await fsPromises.unlink(link.filePath);
|
await fsPromises.unlink(link.filePath);
|
||||||
} else if (identifier.path.endsWith('/') && stats.isDirectory()) {
|
} else if (isContainerIdentifier(identifier) && stats.isDirectory()) {
|
||||||
await fsPromises.rmdir(link.filePath);
|
await fsPromises.rmdir(link.filePath);
|
||||||
} else {
|
} else {
|
||||||
throw new NotFoundHttpError();
|
throw new NotFoundHttpError();
|
||||||
|
@ -5,7 +5,7 @@ import type { NamedNode } from 'rdf-js';
|
|||||||
import { RepresentationMetadata } from '../../ldp/representation/RepresentationMetadata';
|
import { RepresentationMetadata } from '../../ldp/representation/RepresentationMetadata';
|
||||||
import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier';
|
import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier';
|
||||||
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
|
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
|
||||||
import { ensureTrailingSlash } from '../../util/PathUtil';
|
import { ensureTrailingSlash, isContainerIdentifier } from '../../util/PathUtil';
|
||||||
import { generateContainmentQuads, generateResourceQuads } from '../../util/ResourceUtil';
|
import { generateContainmentQuads, generateResourceQuads } from '../../util/ResourceUtil';
|
||||||
import type { DataAccessor } from './DataAccessor';
|
import type { DataAccessor } from './DataAccessor';
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ export class InMemoryDataAccessor implements DataAccessor {
|
|||||||
|
|
||||||
public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
|
public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
|
||||||
const entry = this.getEntry(identifier);
|
const entry = this.getEntry(identifier);
|
||||||
if (this.isDataEntry(entry) === identifier.path.endsWith('/')) {
|
if (this.isDataEntry(entry) === isContainerIdentifier(identifier)) {
|
||||||
throw new NotFoundHttpError();
|
throw new NotFoundHttpError();
|
||||||
}
|
}
|
||||||
return this.generateMetadata(identifier, entry);
|
return this.generateMetadata(identifier, entry);
|
||||||
|
@ -23,7 +23,7 @@ import { ConflictHttpError } from '../../util/errors/ConflictHttpError';
|
|||||||
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
|
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
|
||||||
import { UnsupportedHttpError } from '../../util/errors/UnsupportedHttpError';
|
import { UnsupportedHttpError } from '../../util/errors/UnsupportedHttpError';
|
||||||
import { UnsupportedMediaTypeHttpError } from '../../util/errors/UnsupportedMediaTypeHttpError';
|
import { UnsupportedMediaTypeHttpError } from '../../util/errors/UnsupportedMediaTypeHttpError';
|
||||||
import { ensureTrailingSlash, getParentContainer } from '../../util/PathUtil';
|
import { ensureTrailingSlash, getParentContainer, isContainerIdentifier } from '../../util/PathUtil';
|
||||||
import { generateResourceQuads } from '../../util/ResourceUtil';
|
import { generateResourceQuads } from '../../util/ResourceUtil';
|
||||||
import { CONTENT_TYPE, LDP } from '../../util/UriConstants';
|
import { CONTENT_TYPE, LDP } from '../../util/UriConstants';
|
||||||
import { toNamedNode } from '../../util/UriUtil';
|
import { toNamedNode } from '../../util/UriUtil';
|
||||||
@ -81,7 +81,7 @@ export class SparqlDataAccessor implements DataAccessor {
|
|||||||
*/
|
*/
|
||||||
public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
|
public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
|
||||||
const name = namedNode(identifier.path);
|
const name = namedNode(identifier.path);
|
||||||
const query = identifier.path.endsWith('/') ?
|
const query = isContainerIdentifier(identifier) ?
|
||||||
this.sparqlConstructContainer(name) :
|
this.sparqlConstructContainer(name) :
|
||||||
this.sparqlConstruct(this.getMetadataNode(name));
|
this.sparqlConstruct(this.getMetadataNode(name));
|
||||||
const stream = await this.sendSparqlConstruct(query);
|
const stream = await this.sendSparqlConstruct(query);
|
||||||
|
@ -58,3 +58,15 @@ export const getParentContainer = (id: ResourceIdentifier): ResourceIdentifier =
|
|||||||
|
|
||||||
return { path: parentPath };
|
return { path: parentPath };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the path corresponds to a container path (ending in a /).
|
||||||
|
* @param path - Path to check.
|
||||||
|
*/
|
||||||
|
export const isContainerPath = (path: string): boolean => path.endsWith('/');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the identifier corresponds to a container identifier.
|
||||||
|
* @param identifier - Identifier to check.
|
||||||
|
*/
|
||||||
|
export const isContainerIdentifier = (identifier: ResourceIdentifier): boolean => isContainerPath(identifier.path);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user