mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Emit container pub event on PUT.
Closes https://github.com/solid/community-server/issues/612
This commit is contained in:
committed by
Joachim Van Herwegen
parent
6edc255707
commit
c3cff553e3
@@ -200,13 +200,12 @@ export class DataAccessorBasedStore implements ResourceStore {
|
||||
// Solid, §5.4: "When a contained resource is deleted, the server MUST also delete the associated auxiliary
|
||||
// resources"
|
||||
// https://solid.github.io/specification/protocol#deleting-resources
|
||||
const deleted = [];
|
||||
const deleted = [ identifier ];
|
||||
if (!this.auxiliaryStrategy.isAuxiliaryIdentifier(identifier)) {
|
||||
const auxiliaries = this.auxiliaryStrategy.getAuxiliaryIdentifiers(identifier);
|
||||
deleted.push(...await this.safelyDeleteAuxiliaryResources(auxiliaries));
|
||||
}
|
||||
|
||||
deleted.unshift(...await this.accessor.deleteResource(identifier));
|
||||
await this.accessor.deleteResource(identifier);
|
||||
return deleted;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { Patch } from '../ldp/http/Patch';
|
||||
import type { Representation } from '../ldp/representation/Representation';
|
||||
import type { RepresentationPreferences } from '../ldp/representation/RepresentationPreferences';
|
||||
import type { ResourceIdentifier } from '../ldp/representation/ResourceIdentifier';
|
||||
import type { IdentifierStrategy } from '../util/identifiers/IdentifierStrategy';
|
||||
import type { Conditions } from './Conditions';
|
||||
import type { ResourceStore } from './ResourceStore';
|
||||
|
||||
@@ -14,37 +13,10 @@ import type { ResourceStore } from './ResourceStore';
|
||||
export class MonitoringStore<T extends ResourceStore = ResourceStore>
|
||||
extends EventEmitter implements ResourceStore {
|
||||
private readonly source: T;
|
||||
private readonly identifierStrategy: IdentifierStrategy;
|
||||
|
||||
public constructor(source: T, identifierStrategy: IdentifierStrategy) {
|
||||
public constructor(source: T) {
|
||||
super();
|
||||
this.source = source;
|
||||
this.identifierStrategy = identifierStrategy;
|
||||
}
|
||||
|
||||
public async addResource(container: ResourceIdentifier, representation: Representation,
|
||||
conditions?: Conditions): Promise<ResourceIdentifier> {
|
||||
const identifier = await this.source.addResource(container, representation, conditions);
|
||||
|
||||
// Both the container contents and the resource itself have changed
|
||||
this.emit('changed', container);
|
||||
this.emit('changed', identifier);
|
||||
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public async deleteResource(identifier: ResourceIdentifier,
|
||||
conditions?: Conditions): Promise<ResourceIdentifier[]> {
|
||||
const modified = await this.source.deleteResource(identifier, conditions);
|
||||
|
||||
// Both the container contents and the resource itself have changed
|
||||
if (!this.identifierStrategy.isRootContainer(identifier)) {
|
||||
const container = this.identifierStrategy.getParentContainer(identifier);
|
||||
this.emit('changed', container);
|
||||
}
|
||||
this.emit('changed', identifier);
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
public async getRepresentation(identifier: ResourceIdentifier, preferences: RepresentationPreferences,
|
||||
@@ -52,17 +24,32 @@ export class MonitoringStore<T extends ResourceStore = ResourceStore>
|
||||
return this.source.getRepresentation(identifier, preferences, conditions);
|
||||
}
|
||||
|
||||
public async modifyResource(identifier: ResourceIdentifier, patch: Patch,
|
||||
public async addResource(container: ResourceIdentifier, representation: Representation,
|
||||
conditions?: Conditions): Promise<ResourceIdentifier> {
|
||||
const identifier = await this.source.addResource(container, representation, conditions);
|
||||
this.emitChanged([ container, identifier ]);
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public async deleteResource(identifier: ResourceIdentifier,
|
||||
conditions?: Conditions): Promise<ResourceIdentifier[]> {
|
||||
const modified = await this.source.modifyResource(identifier, patch, conditions);
|
||||
this.emit('changed', identifier);
|
||||
return modified;
|
||||
return this.emitChanged(await this.source.deleteResource(identifier, conditions));
|
||||
}
|
||||
|
||||
public async setRepresentation(identifier: ResourceIdentifier, representation: Representation,
|
||||
conditions?: Conditions): Promise<ResourceIdentifier[]> {
|
||||
const modified = await this.source.setRepresentation(identifier, representation, conditions);
|
||||
this.emit('changed', identifier);
|
||||
return modified;
|
||||
return this.emitChanged(await this.source.setRepresentation(identifier, representation, conditions));
|
||||
}
|
||||
|
||||
public async modifyResource(identifier: ResourceIdentifier, patch: Patch,
|
||||
conditions?: Conditions): Promise<ResourceIdentifier[]> {
|
||||
return this.emitChanged(await this.source.modifyResource(identifier, patch, conditions));
|
||||
}
|
||||
|
||||
private emitChanged(identifiers: ResourceIdentifier[]): typeof identifiers {
|
||||
for (const identifier of identifiers) {
|
||||
this.emit('changed', identifier);
|
||||
}
|
||||
return identifiers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +63,6 @@ export interface DataAccessor {
|
||||
* https://solid.github.io/specification/protocol#deleting-resources
|
||||
*
|
||||
* @param identifier - Resource to delete.
|
||||
*
|
||||
* @returns Identifiers of resources that were possibly modified.
|
||||
*/
|
||||
deleteResource: (identifier: ResourceIdentifier) => Promise<ResourceIdentifier[]>;
|
||||
deleteResource: (identifier: ResourceIdentifier) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -117,15 +117,12 @@ export class FileDataAccessor implements DataAccessor {
|
||||
/**
|
||||
* Removes the corresponding file/folder (and metadata file).
|
||||
*/
|
||||
public async deleteResource(identifier: ResourceIdentifier): Promise<ResourceIdentifier[]> {
|
||||
public async deleteResource(identifier: ResourceIdentifier): Promise<void> {
|
||||
const link = await this.resourceMapper.mapUrlToFilePath(identifier);
|
||||
const metadataLink = await this.getMetadataLink(link.identifier);
|
||||
const stats = await this.getStats(link.filePath);
|
||||
const modified: ResourceIdentifier[] = [ identifier ];
|
||||
|
||||
try {
|
||||
await fsPromises.unlink(metadataLink.filePath);
|
||||
modified.push(metadataLink.identifier);
|
||||
await fsPromises.unlink((await this.getMetadataLink(link.identifier)).filePath);
|
||||
} catch (error: unknown) {
|
||||
// Ignore if it doesn't exist
|
||||
if (!isSystemError(error) || error.code !== 'ENOENT') {
|
||||
@@ -140,8 +137,6 @@ export class FileDataAccessor implements DataAccessor {
|
||||
} else {
|
||||
throw new NotFoundHttpError();
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -83,14 +83,13 @@ export class InMemoryDataAccessor implements DataAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
public async deleteResource(identifier: ResourceIdentifier): Promise<ResourceIdentifier[]> {
|
||||
public async deleteResource(identifier: ResourceIdentifier): Promise<void> {
|
||||
const { parent, name } = this.getParentEntry(identifier);
|
||||
if (!parent.entries[name]) {
|
||||
throw new NotFoundHttpError();
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete parent.entries[name];
|
||||
return [ identifier ];
|
||||
}
|
||||
|
||||
private isDataEntry(entry: CacheEntry): entry is DataEntry {
|
||||
|
||||
@@ -134,10 +134,9 @@ export class SparqlDataAccessor implements DataAccessor {
|
||||
/**
|
||||
* Removes all graph data relevant to the given identifier.
|
||||
*/
|
||||
public async deleteResource(identifier: ResourceIdentifier): Promise<ResourceIdentifier[]> {
|
||||
public async deleteResource(identifier: ResourceIdentifier): Promise<void> {
|
||||
const { name, parent } = this.getRelatedNames(identifier);
|
||||
await this.sendSparqlUpdate(this.sparqlDelete(name, parent));
|
||||
return [ identifier ];
|
||||
return this.sendSparqlUpdate(this.sparqlDelete(name, parent));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,8 +41,7 @@ export class SparqlUpdatePatchHandler extends PatchHandler {
|
||||
const op = patch.algebra;
|
||||
this.validateUpdate(op);
|
||||
|
||||
await this.applyPatch(identifier, op);
|
||||
return [ identifier ];
|
||||
return this.applyPatch(identifier, op);
|
||||
}
|
||||
|
||||
private isDeleteInsert(op: Algebra.Operation): op is Algebra.DeleteInsert {
|
||||
@@ -109,7 +108,7 @@ export class SparqlUpdatePatchHandler extends PatchHandler {
|
||||
/**
|
||||
* Apply the given algebra operation to the given identifier.
|
||||
*/
|
||||
private async applyPatch(identifier: ResourceIdentifier, op: Algebra.Operation): Promise<void> {
|
||||
private async applyPatch(identifier: ResourceIdentifier, op: Algebra.Operation): Promise<ResourceIdentifier[]> {
|
||||
const store = new Store<BaseQuad>();
|
||||
try {
|
||||
// Read the quads of the current representation
|
||||
@@ -134,7 +133,8 @@ export class SparqlUpdatePatchHandler extends PatchHandler {
|
||||
this.logger.debug(`${store.size} quads will be stored to ${identifier.path}.`);
|
||||
|
||||
// Write the result
|
||||
await this.source.setRepresentation(identifier, new BasicRepresentation(store.match() as Readable, INTERNAL_QUADS));
|
||||
const patched = new BasicRepresentation(store.match() as Readable, INTERNAL_QUADS);
|
||||
return this.source.setRepresentation(identifier, patched);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user