Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ angular.module('import').directive('connectionImportErrors', [
*/
patchFailure : '=',

/**
* The DirectoryPatch list sent to patchConnections. It is used to
* map API errors back to import file rows.
*
* @type {DirectoryPatch[]}
*/
patches : '='
}
};

Expand Down Expand Up @@ -114,7 +121,7 @@ angular.module('import').directive('connectionImportErrors', [

/**
* Generate a ImportConnectionError representing any errors associated
* with the row at the given index within the given parse result.
* with the row at the given index within the given patch result.
Comment thread
necouchman marked this conversation as resolved.
*
* @param {ParseResult} parseResult
* The result of parsing the connection import file.
Expand All @@ -131,37 +138,36 @@ angular.module('import').directive('connectionImportErrors', [
* The connection error object associated with the given row in the
* given parse result.
*/
const generateConnectionError = (parseResult, index, row) => {
const generatePatchConnectionError = (parseResult, patches, index, row) => {

// Get the patch associated with the current row
const patch = parseResult.patches[index];
const patch = patches[index];

// The value of a patch is just the Connection object
const connection = patch.value;
const connectionObject = patch.value;

return new ImportConnectionError({

// Add 1 to the provided row to get the position in the file
rowNumber: row + 1,

// Basic connection information - name, group, and protocol.
name: connection.name,
name: connectionObject.name,
group: parseResult.groupPaths[index],
protocol: connection.protocol,
protocol: connectionObject.protocol,

// The human-readable error messages
errors: new DisplayErrorList(
[ ...(parseResult.errors[index] || []) ])
errors: new DisplayErrorList([])
Comment thread
necouchman marked this conversation as resolved.
});
};

// If a new connection patch failure is seen, update the display list
$scope.$watch('patchFailure', function patchFailureChanged(patchFailure) {

const { parseResult } = $scope;
const { parseResult, patches } = $scope;

// Do not attempt to process anything before the data has loaded
if (!patchFailure || !parseResult)
if (!patchFailure || !parseResult || !patches)
return;

// All promises from all translation requests. The scope will not be
Expand All @@ -183,7 +189,7 @@ angular.module('import').directive('connectionImportErrors', [

// Set up the list of connection errors based on the existing parse
// result, with error messages fetched from the patch failure
const connectionErrors = parseResult.patches.reduce(
const connectionErrors = patches.reduce(
(errors, patch, index) => {

// Do not process display REMOVE patches - they are always
Expand All @@ -204,8 +210,8 @@ angular.module('import').directive('connectionImportErrors', [
}

// Generate a connection error for display
const connectionError = generateConnectionError(
parseResult, index, row++);
const connectionError = generatePatchConnectionError(
parseResult, patches, index, row++);

// Add the error associated with the previous REMOVE patch, if
// any, to the error associated with the current patch, if any
Expand Down Expand Up @@ -238,8 +244,52 @@ angular.module('import').directive('connectionImportErrors', [

});

// If a new parse result with errors is seen, update the display list
$scope.$watch('parseResult', function parseResultChanged(parseResult) {
/**
* Generate a ImportConnectionError representing any errors associated
* with the row at the given index within the given parse result.
*
* @param {ParseResult} parseResult
* The result of parsing the connection import file.
*
* @param {Integer} index
* The current row within the patches array, 0-indexed.
*
* @param {Integer} row
* The current row within the original connection, 0-indexed.
* If any REMOVE patches are present, this may be greater than
* the index.
*
* @returns {ImportConnectionError}
* The connection error object associated with the given row in the
* given parse result.
*/
const generateParseConnectionError = (parseResult, index, row) => {

// Get the connection details
const connectionObject = parseResult.connectionObjects[index];

return new ImportConnectionError({

// Physical position in the file
rowNumber: row + 1,

// Basic connection information - name, group, and protocol.
name: connectionObject.name,
group: connectionObject.group,
protocol: connectionObject.protocol,

// Pull parse-time errors from the ImportConnection object
errors: new DisplayErrorList([ ...(connectionObject.errors || []) ])
});
};

// If a new parse result with errors is seen, update the display list.
// Watch hasErrors as well: it may be set after parseResult is assigned
// (e.g. when ensureConnectionGroups fails to resolve a group path).
$scope.$watchGroup(['parseResult', 'parseResult.hasErrors'],
function parseResultChanged() {

const parseResult = $scope.parseResult;

// Do not process if there are no errors in the provided result
if (!parseResult || !parseResult.hasErrors)
Expand All @@ -254,34 +304,21 @@ angular.module('import').directive('connectionImportErrors', [
// entirely - if set, they will be from the previous file and no
// longer relevant.

// The row number for display. Unlike the index, this number will
// skip any REMOVE patches. In other words, this is the index of
// connections within the original import file.
let row = 0;

// Set up the list of connection errors based on the updated parse
// result
const connectionErrors = parseResult.patches.reduce(
(errors, patch, index) => {
// result using connectionObjects.
const connectionErrors = parseResult.connectionObjects.map(
(connectionObject, index) => {

// Do not process display REMOVE patches - they are always
// followed by ADD patches containing the actual content
// (and errors, if any)
if (patch.op === DirectoryPatch.Operation.REMOVE)
return errors;

// Generate a connection error for display
const connectionError = generateConnectionError(
parseResult, index, row++);
// Generate a connection error for display.
// In this new architecture, index and row are identical.
const connectionError = generateParseConnectionError(
parseResult, index, index);

// Go through the errors and check if any are translateable
connectionError.errors.getArray().forEach(
(error, errorIndex) => {
// Go through the errors and check if any are translateable.
// We access the underlying array from the DisplayErrorList.
connectionError.errors.getArray().forEach((error, errorIndex) => {

// If this error is a ParseError, it can be translated.
// NOTE: Generally one would translate error messages in the
// template, but in this case, the connection errors need to
// be raw strings in order to enable sorting and filtering.
if (error instanceof ParseError)

// Fetch the translation and update it when it's ready
Expand All @@ -299,17 +336,14 @@ angular.module('import').directive('connectionImportErrors', [

});

errors.push(connectionError);
return errors;

}, []);
return connectionError;
});

// Once all the translations have been completed, update the
// connectionErrors all in one go, to ensure no excessive reloading
$q.all(translationPromises).then(() => {
$scope.connectionErrors = connectionErrors;
});

});

}];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ angular.module('import').factory('connectionParseService',
['$injector', function connectionParseService($injector) {

// Required types
const Connection = $injector.get('Connection');
const ConnectionImportConfig = $injector.get('ConnectionImportConfig');
const DirectoryPatch = $injector.get('DirectoryPatch');
const ImportConnection = $injector.get('ImportConnection');
const ParseError = $injector.get('ParseError');
const ParseResult = $injector.get('ParseResult');
Expand Down Expand Up @@ -105,19 +103,18 @@ angular.module('import').factory('connectionParseService',
const TreeLookups = template => ({

/**
* A map of all known group paths to the corresponding identifier for
* that group. The is that a user-provided import file might directly
* specify a named group path like "ROOT", "ROOT/parent", or
* "ROOT/parent/child". This field field will map all of the above to
* the identifier of the appropriate group, if defined.
* A map of group identifier to the path of that group, keyed by
* identifier. Paths are of the form "ROOT", "ROOT/parent", or
* "ROOT/parent/child".
*
* @type Object.<String, String>
*/
groupPathsByIdentifier: template.groupPathsByIdentifier || {},

/**
* A map of all known group identifiers to the path of the corresponding
* group. These paths are all of the form "ROOT/parent/child".
* A map of group path to the identifier of that group, keyed by path.
* Used when the import file specifies a group path rather than a
* parentIdentifier.
*
* @type Object.<String, String>
*/
Expand Down Expand Up @@ -166,11 +163,9 @@ angular.module('import').factory('connectionParseService',
// To get the path for the current group, add the name
const currentPath = prefix + group.name;

// Add the current path to the identifier map
lookups.groupPathsByIdentifier[currentPath] = group.identifier;

// Add the current identifier to the path map
lookups.groupIdentifiersByPath[group.identifier] = currentPath;
// Map identifier to path and path to identifier
lookups.groupPathsByIdentifier[group.identifier] = currentPath;
lookups.groupIdentifiersByPath[currentPath] = group.identifier;

// Add each connection to the connection map
_.forEach(group.childConnections,
Expand Down Expand Up @@ -239,9 +234,6 @@ angular.module('import').factory('connectionParseService',

// The identifier for the parent group of this connection
let parentIdentifier;

// The operator to apply for this connection
let op = DirectoryPatch.Operation.ADD;

// If both are specified, the parent group is ambigious
if (providedIdentifier && connection.group) {
Expand Down Expand Up @@ -299,11 +291,14 @@ angular.module('import').factory('connectionParseService',
if (group.endsWith('/'))
group = group.slice(0, -1);

// Collapse duplicate or empty path segments (e.g. "ROOT//Repro5")
group = group.split('/').filter(segment => segment.length).join('/');

// Look up the parent identifier for the specified group path
parentIdentifier = groupPathsByIdentifier[group];
parentIdentifier = groupIdentifiersByPath[group];

// If the group doesn't match anything in the tree
if (!parentIdentifier) {
if (!parentIdentifier && !importConfig.createMissingGroups) {
connection.errors.push(new ParseError({
message: 'No group found named: ' + connection.group,
key: 'IMPORT.ERROR_INVALID_GROUP',
Expand Down Expand Up @@ -578,7 +573,7 @@ angular.module('import').factory('connectionParseService',
.then(({fieldTransformer, treeTransformer}) =>
connectionData.reduce((parseResult, data) => {

const { patches, users, groups, groupPaths } = parseResult;
const { connectionObjects, users, groups, groupPaths } = parseResult;

// Run the array data through each provided transform
let connectionObject = data;
Expand All @@ -596,52 +591,14 @@ angular.module('import').factory('connectionParseService',
if (connectionObject.errors.length)
parseResult.hasErrors = true;

// The value for the patch is a full-fledged Connection
const value = new Connection(connectionObject);

// If a new connection is being created
if (connectionObject.importMode
=== ImportConnection.ImportMode.CREATE)

// Add a patch for creating the connection
patches.push(new DirectoryPatch({
op: DirectoryPatch.Operation.ADD,
path: '/',
value
}));

// The connection is being replaced, and permissions are only being
// added, not replaced
else if (importConfig.existingPermissionMode ===
ConnectionImportConfig.ExistingPermissionMode.PRESERVE)

// Add a patch for replacing the connection
patches.push(new DirectoryPatch({
op: DirectoryPatch.Operation.REPLACE,
path: '/' + connectionObject.identifier,
value
}));

// The connection is being replaced, and permissions are also being
// replaced
else {

// Add a patch for removing the existing connection
patches.push(new DirectoryPatch({
op: DirectoryPatch.Operation.REMOVE,
path: '/' + connectionObject.identifier
}));
// Save the connection details
connectionObjects.push(connectionObject);

// Increment the index for the additional remove patch
// Logic to determine if this connection will later result in 2 patches
if (connectionObject.importMode === ImportConnection.ImportMode.REPLACE &&
importConfig.existingPermissionMode !== ConnectionImportConfig.ExistingPermissionMode.PRESERVE) {
// Increment the index for the additional remove patch (which will be created during import)
index += 1;

// Add a second patch for creating the replacement connection
patches.push(new DirectoryPatch({
op: DirectoryPatch.Operation.ADD,
path: '/',
value
}));

}

// Save the connection group path into the parse result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ <h2>{{'IMPORT.SECTION_HEADER_CONNECTION_IMPORT' | translate}}</h2>
</label>
<span ng-attr-title="{{'IMPORT.HELP_EXISTING_PERMISSION_MODE' | translate}}" class="help"></span>
</li>
<li>
<input type="checkbox"
Comment thread
necouchman marked this conversation as resolved.
id="create-missing-groups" ng-model="importConfig.createMissingGroups" />
<label for="create-missing-groups">
{{'IMPORT.FIELD_HEADER_CREATE_MISSING_GROUPS' | translate}}
</label>
<span ng-attr-title="{{'IMPORT.HELP_CREATE_MISSING_GROUPS' | translate}}" class="help"></span>
</li>
</ul>

</div>
Expand All @@ -76,7 +84,7 @@ <h2>{{'IMPORT.SECTION_HEADER_CONNECTION_IMPORT' | translate}}</h2>
<div ng-show="isLoading()" class="loading"></div>

<!-- Connection specific errors, if there are any -->
<connection-import-errors parse-result="parseResult" patch-failure="patchFailure" />
<connection-import-errors parse-result="parseResult" patch-failure="patchFailure" patches="patches" />


</div>
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ angular.module('import').factory('ConnectionImportConfig', [
this.existingPermissionMode = template.existingPermissionMode
|| ConnectionImportConfig.ExistingPermissionMode.PRESERVE;

/**
* Whether to create connection groups referenced by the import file when
* they do not already exist. When false, unknown group paths are treated
* as parse errors (unless a valid parentIdentifier is set).
*
* @type Boolean
*/
this.createMissingGroups = template.createMissingGroups === true;
};

/**
Expand Down
Loading
Loading