GUACAMOLE-926: Allow updating objects via directory patch.

This commit is contained in:
James Muehlner
2023-04-17 21:57:30 +00:00
parent d9bb38eb65
commit d0876cdc71
2 changed files with 77 additions and 11 deletions

View File

@@ -59,7 +59,7 @@ angular.module('rest').factory('DirectoryPatch', [function defineDirectoryPatch(
this.path = template.path || '/'; this.path = template.path || '/';
/** /**
* The object being added, or undefined if deleting. * The object being added/replaced, or undefined if deleting.
* *
* @type {DirectoryObject} * @type {DirectoryObject}
*/ */
@@ -77,6 +77,11 @@ angular.module('rest').factory('DirectoryPatch', [function defineDirectoryPatch(
*/ */
ADD : 'add', ADD : 'add',
/**
* Replaces (updates) the specified object from the relation.
*/
REPLACE : 'replace',
/** /**
* Removes the specified object from the relation. * Removes the specified object from the relation.
*/ */

View File

@@ -478,18 +478,18 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
/** /**
* Applies the given object patches, updating the underlying directory * Applies the given object patches, updating the underlying directory
* accordingly. This operation supports addition and removal of objects * accordingly. This operation supports addition, replacement, and removal of
* through the "add" and "remove" patch operation. The path of each patch * objects through the "add", "replace", or "remove" patch operations. The
* operation is of the form "/ID" where ID is the identifier of the object * path of each patch operation is of the form "/ID" where ID is the
* being modified. In the case of object creation, the identifier is * identifier of the object being modified. In the case of object creation,
* ignored, as the identifier will be automatically provided. This operation * the identifier is ignored, as the identifier will be automatically
* is atomic. * provided. This operation is atomic.
* *
* @param patches * @param patches
* The patches to apply for this request. * The patches to apply for this request.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while adding, updating, or removing objects. * If an error occurs while adding, replacing, or removing objects.
* *
* @return * @return
* A response describing the outcome of each patch. Only the identifier * A response describing the outcome of each patch. Only the identifier
@@ -523,8 +523,9 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
"executed."); "executed.");
// Keep a list of all objects that have been successfully // Keep a list of all objects that have been successfully
// added or removed // added, replaced, or removed
Collection<InternalType> addedObjects = new ArrayList<>(); Collection<InternalType> addedObjects = new ArrayList<>();
Collection<InternalType> replacedObjects = new ArrayList<>();
Collection<String> removedIdentifiers = new ArrayList<>(); Collection<String> removedIdentifiers = new ArrayList<>();
// A list of all responses associated with the successful // A list of all responses associated with the successful
@@ -590,7 +591,56 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
} }
// Append each identifier to the list, to be removed atomically else if (op == APIPatch.Operation.replace) {
// The identifier of the object to be replaced
String identifier = path.substring(1);
InternalType original = null;
try {
// Fetch the object to be updated
original = directory.get(identifier);
// Apply the changes to the original object
translator.applyExternalChanges(
original, patch.getValue());
// Update the directory
directory.update(original);
replacedObjects.add(original);
// Add a success outcome describing the replacement
APIPatchOutcome response = new APIPatchOutcome(
op, identifier, path);
patchOutcomes.add(response);
}
catch (GuacamoleException | RuntimeException | Error e) {
failed = true;
fireDirectoryFailureEvent(
DirectoryEvent.Operation.UPDATE,
identifier, original, e);
// Attempt to generate an API Patch error using the
// caught exception
APIPatchError patchError = createPatchFailure(
op, identifier, path, e);
if (patchError != null)
patchOutcomes.add(patchError);
// If an unexpected failure occurs, fall through to
// the standard API error handling
else
throw e;
}
}
else if (op == APIPatch.Operation.remove) { else if (op == APIPatch.Operation.remove) {
String identifier = path.substring(1); String identifier = path.substring(1);
@@ -633,7 +683,7 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
else { else {
throw new GuacamoleUnsupportedException( throw new GuacamoleUnsupportedException(
"Unsupported patch operation \"" + op + "\". " "Unsupported patch operation \"" + op + "\". "
+ "Only add and remove are supported."); + "Only add, replace, and remove are supported.");
} }
@@ -666,6 +716,17 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
} }
// Fire directory success events for each updated object
Iterator<InternalType> updatedIterator = replacedObjects.iterator();
while (updatedIterator.hasNext()) {
InternalType internal = updatedIterator.next();
fireDirectorySuccessEvent(
DirectoryEvent.Operation.UPDATE,
internal.getIdentifier(), internal);
}
// Fire directory success events for each removed object // Fire directory success events for each removed object
Iterator<String> removedIterator = removedIdentifiers.iterator(); Iterator<String> removedIterator = removedIdentifiers.iterator();
while (removedIterator.hasNext()) { while (removedIterator.hasNext()) {