GUACAMOLE-926: Translate to API patches in patch service.

This commit is contained in:
James Muehlner
2023-02-04 02:05:17 +00:00
parent a6af634d86
commit cbb44efb2b
2 changed files with 124 additions and 27 deletions

View File

@@ -31,6 +31,7 @@ angular.module('import').factory('connectionParseService',
// Required types // Required types
const Connection = $injector.get('Connection'); const Connection = $injector.get('Connection');
const DirectoryPatch = $injector.get('DirectoryPatch');
const ParseError = $injector.get('ParseError'); const ParseError = $injector.get('ParseError');
const TranslatableMessage = $injector.get('TranslatableMessage'); const TranslatableMessage = $injector.get('TranslatableMessage');
@@ -124,6 +125,62 @@ angular.module('import').factory('connectionParseService',
return deferredGroupLookups.promise; return deferredGroupLookups.promise;
} }
/**
* Returns a promise that will resolve to a transformer function that will
* take an object that may a "group" field, replacing it if present with a
* "parentIdentifier". If both a "group" and "parentIdentifier" field are
* present on the provided object, or if no group exists at the specified
* path, the function will throw a ParseError describing the failure.
*
* @returns {Promise.<Function<Object, Object>>}
* A promise that will resolve to a function that will transform a
* "group" field into a "parentIdentifier" field if possible.
*/
function getGroupTransformer() {
return getGroupLookups().then(lookups => connection => {
// If there's no group to translate, do nothing
if (!connection.group)
return;
// If both are specified, the parent group is ambigious
if (connection.parentIdentifier)
throw new ParseError({
message: 'Only one of group or parentIdentifier can be set',
key: 'CONNECTION_IMPORT.ERROR_AMBIGUOUS_PARENT_GROUP'
});
// Look up the parent identifier for the specified group path
const identifier = lookups[connection.group];
// If the group doesn't match anything in the tree
if (!identifier)
throw new ParseError({
message: 'No group found named: ' + connection.group,
key: 'CONNECTION_IMPORT.ERROR_INVALID_GROUP',
variables: { GROUP: connection.group }
});
// Set the parent identifier now that it's known
return {
...connection,
parentIdentifier: identifier
};
});
}
// Translate a given javascript object to a full-fledged Connection
const connectionTransformer = connection => new Connection(connection);
// Translate a Connection object to a patch requesting the creation of said
// Connection
const patchTransformer = connection => new DirectoryPatch({
op: 'add',
path: '/',
value: connection
});
/** /**
* Convert a provided CSV representation of a connection list into a JSON * Convert a provided CSV representation of a connection list into a JSON
* string to be submitted to the PATCH REST endpoint. The returned JSON * string to be submitted to the PATCH REST endpoint. The returned JSON
@@ -173,13 +230,28 @@ angular.module('import').factory('connectionParseService',
// The header row - an array of string header values // The header row - an array of string header values
const header = parsedData[0]; const header = parsedData[0];
return connectionCSVService.getCSVTransformer(header).then( return $q.all({
csvTransformer : connectionCSVService.getCSVTransformer(header),
groupTransformer : getGroupTransformer()
})
// If the transformer was successfully generated, apply it to the // Transform the rows from the CSV file to an array of API patches
// data rows .then(({csvTransformer, groupTransformer}) => connectionData.map(
// TODO: Also apply the group -> parentIdentifier transform dataRow => {
csvTransformer => connectionData.map(csvTransformer)
); // Translate the raw CSV data to a javascript object
let connectionObject = csvTransformer(dataRow);
// Translate the group on the object to a parentIdentifier
connectionObject = groupTransformer(connectionObject);
// Translate to a full-fledged Connection
const connection = connectionTransformer(connectionObject);
// Finally, translate to a patch for creating the connection
return patchTransformer(connection);
}));
}; };
@@ -203,14 +275,26 @@ angular.module('import').factory('connectionParseService',
// Check that the data is the correct format, and not empty // Check that the data is the correct format, and not empty
const checkError = performBasicChecks(connectionData); const checkError = performBasicChecks(connectionData);
if (checkError) if (checkError) {
return $q.defer().reject(checkError); const deferred = $q.defer();
deferred.reject(checkError);
return deferred.promise;
}
// Convert to an array of Connection objects and return // Transform the data from the YAML file to an array of API patches
const deferredConnections = $q.defer(); return getGroupTransformer().then(
deferredConnections.resolve( groupTransformer => parsedData.map(connectionObject => {
parsedData.map(connection => new Connection(connection)));
return deferredConnections.promise; // Translate the group on the object to a parentIdentifier
connectionObject = groupTransformer(connectionObject);
// Translate to a full-fledged Connection
const connection = connectionTransformer(connectionObject);
// Finally, translate to a patch for creating the connection
return patchTransformer(connection);
}));
}; };
@@ -234,14 +318,26 @@ angular.module('import').factory('connectionParseService',
// Check that the data is the correct format, and not empty // Check that the data is the correct format, and not empty
const checkError = performBasicChecks(connectionData); const checkError = performBasicChecks(connectionData);
if (checkError) if (checkError) {
return $q.defer().reject(checkError); const deferred = $q.defer();
deferred.reject(checkError);
return deferred.promise;
}
// Convert to an array of Connection objects and return // Transform the data from the YAML file to an array of API patches
const deferredConnections = $q.defer(); return getGroupTransformer().then(
deferredConnections.resolve( groupTransformer => parsedData.map(connectionObject => {
parsedData.map(connection => new Connection(connection)));
return deferredConnections.promise; // Translate the group on the object to a parentIdentifier
connectionObject = groupTransformer(connectionObject);
// Translate to a full-fledged Connection
const connection = connectionTransformer(connectionObject);
// Finally, translate to a patch for creating the connection
return patchTransformer(connection);
}));
}; };

View File

@@ -197,11 +197,12 @@
"ERROR_EMPTY_FILE": "The provided file is empty", "ERROR_EMPTY_FILE": "The provided file is empty",
"ERROR_INVALID_CSV_HEADER": "ERROR_INVALID_CSV_HEADER":
"Invalid CSV Header \"{HEADER}\" is neither an attribute or parameter", "Invalid CSV Header \"{HEADER}\" is neither an attribute or parameter",
"ERROR_INVALID_GROUP": "No group matching \"{GROUP}\" found",
"ERROR_INVALID_FILE_TYPE": "ERROR_INVALID_FILE_TYPE":
"Invalid import file type \"{TYPE}\"", "Invalid import file type \"{TYPE}\"",
"ERROR_NO_FILE_SUPPLIED": "Please select a file to import", "ERROR_NO_FILE_SUPPLIED": "Please select a file to import",
"ERROR_REQUIRED_GROUP": "ERROR_AMBIGUOUS_PARENT_GROUP":
"Either group or parentIdentifier must be specified, but not both", "Both group and parentIdentifier may be not specified at the same time",
"ERROR_REQUIRED_PROTOCOL": "ERROR_REQUIRED_PROTOCOL":
"No connection protocol found in the provided file", "No connection protocol found in the provided file",
"ERROR_REQUIRED_NAME": "ERROR_REQUIRED_NAME":