mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
fix: Make SimpleResourceStore behaviour closer to expected
This commit is contained in:
32
src/ldp/operations/SimplePutOperationHandler.ts
Normal file
32
src/ldp/operations/SimplePutOperationHandler.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Operation } from './Operation';
|
||||
import { OperationHandler } from './OperationHandler';
|
||||
import { ResourceStore } from '../../storage/ResourceStore';
|
||||
import { ResponseDescription } from './ResponseDescription';
|
||||
import { UnsupportedHttpError } from '../../util/errors/UnsupportedHttpError';
|
||||
|
||||
/**
|
||||
* Handles PUT {@link Operation}s.
|
||||
* Calls the setRepresentation function from a {@link ResourceStore}.
|
||||
*/
|
||||
export class SimplePutOperationHandler extends OperationHandler {
|
||||
private readonly store: ResourceStore;
|
||||
|
||||
public constructor(store: ResourceStore) {
|
||||
super();
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
public async canHandle(input: Operation): Promise<void> {
|
||||
if (input.method !== 'PUT') {
|
||||
throw new UnsupportedHttpError('This handler only supports PUT operations.');
|
||||
}
|
||||
if (typeof input.body !== 'object') {
|
||||
throw new UnsupportedHttpError('PUT operations require a body.');
|
||||
}
|
||||
}
|
||||
|
||||
public async handle(input: Operation): Promise<ResponseDescription> {
|
||||
await this.store.setRepresentation(input.target, input.body!);
|
||||
return { identifier: input.target };
|
||||
}
|
||||
}
|
||||
@@ -42,10 +42,12 @@ export class SimpleResourceStore implements ResourceStore {
|
||||
*/
|
||||
public async addResource(container: ResourceIdentifier, representation: Representation): Promise<ResourceIdentifier> {
|
||||
const containerPath = this.parseIdentifier(container);
|
||||
const newPath = `${ensureTrailingSlash(containerPath)}${this.index}`;
|
||||
this.checkPath(containerPath);
|
||||
const newID = { path: `${ensureTrailingSlash(container.path)}${this.index}` };
|
||||
const newPath = this.parseIdentifier(newID);
|
||||
this.index += 1;
|
||||
this.store[newPath] = await this.copyRepresentation(representation);
|
||||
return { path: `${this.base}${newPath}` };
|
||||
return newID;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,6 +56,7 @@ export class SimpleResourceStore implements ResourceStore {
|
||||
*/
|
||||
public async deleteResource(identifier: ResourceIdentifier): Promise<void> {
|
||||
const path = this.parseIdentifier(identifier);
|
||||
this.checkPath(path);
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete this.store[path];
|
||||
}
|
||||
@@ -68,6 +71,7 @@ export class SimpleResourceStore implements ResourceStore {
|
||||
*/
|
||||
public async getRepresentation(identifier: ResourceIdentifier): Promise<Representation> {
|
||||
const path = this.parseIdentifier(identifier);
|
||||
this.checkPath(path);
|
||||
return this.generateRepresentation(path);
|
||||
}
|
||||
|
||||
@@ -79,7 +83,7 @@ export class SimpleResourceStore implements ResourceStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the stored Representation with the new one for the given identifier.
|
||||
* Puts the given data in the given location.
|
||||
* @param identifier - Identifier to replace.
|
||||
* @param representation - New Representation.
|
||||
*/
|
||||
@@ -89,22 +93,35 @@ export class SimpleResourceStore implements ResourceStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips the base from the identifier and checks if it is in the store.
|
||||
* Strips the base from the identifier and checks if it is valid.
|
||||
* @param identifier - Incoming identifier.
|
||||
*
|
||||
* @throws {@link NotFoundHttpError}
|
||||
* If the identifier is not in the store.
|
||||
* If the identifier doesn't start with the base ID.
|
||||
*
|
||||
* @returns A string representing the relative path.
|
||||
*/
|
||||
private parseIdentifier(identifier: ResourceIdentifier): string {
|
||||
const path = identifier.path.slice(this.base.length);
|
||||
if (!this.store[path] || !identifier.path.startsWith(this.base)) {
|
||||
if (!identifier.path.startsWith(this.base)) {
|
||||
throw new NotFoundHttpError();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the relative path is in the store.
|
||||
* @param identifier - Incoming identifier.
|
||||
*
|
||||
* @throws {@link NotFoundHttpError}
|
||||
* If the path is not in the store.
|
||||
*/
|
||||
private checkPath(path: string): void {
|
||||
if (!this.store[path]) {
|
||||
throw new NotFoundHttpError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the Representation by draining the original data stream and creating a new one.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user