"use strict"; /** * Licensed Materials - Property of IBM * IBM Cognos Products: Cognos Analytics * Copyright IBM Corp. 2017, 2018 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['q', 'underscore', 'doT', 'bi/admin/nls/StringResource', 'bi/commons/ui/AccessibleView', 'bi/admin/account/services/SecurityObjectSelectorAdaptor', 'bi/admin/account/ui/SecurityObjectExplorerView', 'bacontentnav/ui/dialogs/NameCollisionDialog'], function (Q, _, dot, StringResource, SecurityObjectSelectorPane, SecurityObjectSelectorAdaptor, SecurityObjectExplorerView, NameCollisionDialog) { 'use strict'; //NOSONAR: meant to be strict var SecurityObjectExplorerCopyMoveView = SecurityObjectSelectorPane.extend({ showBreadcrumbs: true, defaultTypes: ['namespaceFolder', 'group', 'role', 'account'], _breadCrumbs: null, _namespaceWritePermission: true, _accountExplorer: null, listAdaptor: null, title: '', multiSelect: false, targetLocation: {}, init: function init(options) { SecurityObjectExplorerCopyMoveView.inherited('init', this, arguments); var cognosNamespaceOnly = options.cognosNamespaceOnly ? options.cognosNamespaceOnly : false; var listAdaptor = this._getNewSecurityObjectSelectorAdaptor({ glassContext: this.glassContext, allowedSelectionTypes: options.allowedSelectionTypes, cognosNamespaceOnly: cognosNamespaceOnly, hideFilter: true }); this.explorerView = this._getNewSecurityObjectExplorerView({ glassContext: this.glassContext, showBreadcrumbs: true, hideSearch: options.hideSearch, includeToolbar: true, type: options.type, listAdaptor: listAdaptor, parent: this, hidePaging: true }); }, _getNewSecurityObjectExplorerView: function _getNewSecurityObjectExplorerView(options) { return new SecurityObjectExplorerView(options); }, _getNewSecurityObjectSelectorAdaptor: function _getNewSecurityObjectSelectorAdaptor(options) { return new SecurityObjectSelectorAdaptor(options); }, render: function render() { var deferred = Q.defer(); this.explorerView.$el = this.$el; this.explorerView.render(this.$el).done(function () { this._renderSelectionTitle(); this.bindEvents(); this.targetLocation = this.explorerView._accountExplorer.getCurrentPath(); //reload the listView in order to readjust its flex box so it does not get overlapped by the footer this.explorerView.reloadList().done(function () { deferred.resolve(); }); }.bind(this)); return deferred.promise; }, _renderSelectionTitle: function _renderSelectionTitle() { var $explorerHeader = $(''); var sep = $('
', { 'class': 'separator' }); $explorerHeader.append(sep); var $title = $('
', { 'class': 'selectDestination' }).text(StringResource.get('selectDestination')); $explorerHeader.append($title); $('.dialogContent').prepend($explorerHeader); //Need to force the heights for the copy move dialog to render properly $('.dialogContent').addClass('admin_copyMoveDialogContent'); $('.dialogContentHeader').next().css({ "display": "flex", "flex-direction": "column", "height": "100%" }); $('.dataTables_wrapper').css({ "height": "100%" }); $('.dataTables_scroll').css({ "height": "100%" }); }, _renderDestinationLebel: function _renderDestinationLebel(destName) { var destination = StringResource.get('destination') + ' ' + destName; $('.copy-move-destinantion-label').text(destination); }, getPathStringFromObjectSearchPath: function getPathStringFromObjectSearchPath(object) { var folderArray; if (object.type === 'namespaceFolder') { folderArray = object.searchPath.split('/'); return this._convertCognosSearchPathSyntaxToTreePathSyntax(folderArray, folderArray.length - 1); } else { folderArray = object.searchPath.split(':'); var pathString = ""; for (var i = 1; i < folderArray.length - 1; i++) { pathString = pathString + "/" + folderArray[i]; } return pathString; } }, getPathStringFromTargetLoc: function getPathStringFromTargetLoc() { var folderArray = this.targetLocation.searchPath.split('/'); return this._convertCognosSearchPathSyntaxToTreePathSyntax(folderArray, folderArray.length); }, _convertCognosSearchPathSyntaxToTreePathSyntax: function _convertCognosSearchPathSyntaxToTreePathSyntax(searchPathElementsArray, numberOfLevels) { var pathString = ""; for (var i = 1; i < numberOfLevels; i++) { var folderName = searchPathElementsArray[i].replace('namespaceFolder[@name=\"', ''); folderName = folderName.replace('\"]', ''); folderName = folderName.replace('namespaceFolder[@name=\'', ''); folderName = folderName.replace('\']', ''); pathString = pathString + "/" + folderName; } return pathString; }, bindEvents: function bindEvents() { this.$el.on('com.ibm.admin.listItemHighlighted', function (e, obj) { if (obj.type === 'namespaceFolder') { var highlightedDestination = this.explorerView.getSelectedObjects(); this._renderDestinationLebel(obj.defaultName); this.targetLocation = highlightedDestination[0]; } }.bind(this)); this.explorerView.listAdaptor.on('pathChanged', function (path) { var $destinationEl = $('.copy-move-destinantion-label'); if (!$destinationEl.length) { $destinationEl = $($.parseHTML('
')); } if (path.length === 1) { if ($destinationEl.length) { $destinationEl.text(''); } this.dialog.disableButton('copy'); this.dialog.disableButton('move'); } else if (path.length === 2) { this.dialog.enableButton('copy'); this.dialog.enableButton('move'); var destination = StringResource.get('destination') + ' ' + _.last(path).defaultName; $destinationEl.text(destination); this.$('.bi-admin-account-list.bi-admin-flexcontent').after($destinationEl[0]); this.targetLocation = _.last(path); } else if (path.length > 2) { this._renderDestinationLebel(_.last(path).defaultName); this.targetLocation = _.last(path); } if (this.getPathStringFromTargetLoc() === this.getPathStringFromObjectSearchPath(this.inputObjects[0]) || this._isTargetDirectoryRoot(path) || this._isSourceAndTargetBothCognosOrTenantRoot(this.inputObjects[0].ancestors)) { this.dialog.disableButton('move'); } else { this.dialog.enableButton('move'); } }.bind(this)); }, /** * Determines if both source and target are the same location when it comes to Cognos root, i.e.: * Cognos root/ tenant ns root to Cognos root/ tenant ns root * @param {*} ancestors ancesters of source object * @returns {boolean} */ _isSourceAndTargetBothCognosOrTenantRoot: function _isSourceAndTargetBothCognosOrTenantRoot(ancestors) { var targetFolderLocationArray = this.targetLocation.searchPath.split('/'); if (targetFolderLocationArray.length !== 1 && this.targetLocation.id !== 'xOg__') { //Means we are not trying to move to Cognos root or tenant ns folder root return false; } var ancestor = ancestors[ancestors.length - 1]; if (ancestor.id === this.explorerView._accountExplorer.tenantNsFolderId) { return true; } return false; }, /** * Determines if target is directory root * @param {*} path - array of folders split for target searchPath * @returns {boolean} */ _isTargetDirectoryRoot: function _isTargetDirectoryRoot(path) { //Don't show if in Directory root location if (path.length === 1 && path[0].type === 'directory') { return true; } return false; }, //Called by the copy dialog when it asks the view for the button spec getButtonSpec: function getButtonSpec(options) { var spec = []; if (options.viewOptions.type === 'copyMoveDialog') { spec.push({ 'text': StringResource.get('copyTo'), 'handler': this.copy.bind(this), 'type': 'primary copy', 'defaultId': 'copyButton' }, { 'text': StringResource.get('moveTo'), 'handler': this.move.bind(this), 'type': 'primary move', 'defaultId': 'moveButton' }); } spec.push('cancel'); return spec; }, _getURLForCopyMoveRequest: function _getURLForCopyMoveRequest(operationType, sourceId, targetId) { var url; if (operationType === 'copy') { url = 'v1/namespaces/' + targetId + '/items?recursive=true&source=' + sourceId; } else if (operationType === 'move') { // for move, we have to check for tenantNamespaceFolder when moving objects to xOg__ // For copy this is taken care of by the server: // https://github.ibm.com/BusinessAnalytics/ba-admin/blob/8dc2760c1f7b5cffe9ab42356ac32571a095f1ae/ // admin-common-service/src/main/java/com/ibm/bi/admin/commons/filters/CognosNsPathOverrideFilter.java#L65 if (targetId === 'xOg__' && this.explorerView._accountExplorer.tenantNsFolderId) { targetId = this.explorerView._accountExplorer.tenantNsFolderId; } url = 'v1/namespaces/' + sourceId + '?parent=' + targetId; } return url; }, _doInitialCopyMoveRequests: function _doInitialCopyMoveRequests(operationType, sourceId, targetI, url) { var actionPromise = {}; if (operationType === 'copy') { actionPromise = this.makeCopyRequest(url); } else if (operationType === 'move') { actionPromise = this.makeMoveRequest(url); } return actionPromise; }, copy: function copy(a) { var aPromises = this._handleCopyMoveRequests('copy'); Q.allSettled(aPromises).then(function (r) { this.dialog.remove(); this.glassContext.appController.showToast(StringResource.get('copySuccess'), { 'type': 'success' }); this.parent.refresh(); }.bind(this), function (e) { this.dialog.remove(); this.glassContext.appController.showToast(StringResource.get('copyError'), { 'type': 'error' }); }.bind(this)); }, _replace: function _replace(url, index) { if (this.operationType === 'copy') { return this.makeCopyRequest(url + '&updateAction=replace').then(function (response) { this.trackPromises[index].resolve(); }.bind(this)); } else if (this.operationType === 'move') { return this.makeMoveRequest(url + '&updateAction=replace').then(function (response) { this.trackPromises[index].resolve(); }.bind(this)); } }, _handleNameConflict: function _handleNameConflict(error, url, count, defaultName, index) { if (error.requestInfo.jqXHR.responseJSON.errors[0].errorCode === 'cmNameConflict') { count = count + 1; this._keepBoth(count, url, defaultName, index); } }, _keepBoth: function _keepBoth(count, url, defaultName, index) { this.count = count; /*Keeps both objects in the collision by renaming the new object*/ if (this.operationType === 'copy') { this.makeCopyRenameRequest(url, count, defaultName).then(function (response) { this.trackPromises[index].resolve(); }.bind(this), function (error) { this._handleNameConflict(error, url, count, defaultName, index); }.bind(this)); } else if (this.operationType === 'move') { this.makeMoveRenameRequest(url, count, defaultName).then(function (response) { this.trackPromises[index].resolve(); }.bind(this), function (error) { this._handleNameConflict(error, url, count, defaultName, index); }.bind(this)); } }, _skip: function _skip() { /*Closes the dialog without doing anything*/ var deferred = Q.defer(); deferred.resolve(); return deferred.promise; }, _handleCopyMoveRequests: function _handleCopyMoveRequests(operationType) { this.operationType = operationType; var executionPromises = []; var itemsSelected = this.inputObjects; this.trackPromises = []; _.each(itemsSelected, function (item, index, list) { var url = this._getURLForCopyMoveRequest(operationType, item.id, this.targetLocation.id); executionPromises[index] = this._doInitialCopyMoveRequests(operationType, item.id, this.targetLocation.id, url); this.trackPromises[index] = _.clone(executionPromises[index]); this.trackPromises[index] = Q.defer(); this.trackPromises[index].itemId = item.id; this.trackPromises[index].defaultName = item.defaultName; this.trackPromises[index].url = url; }.bind(this)); Promise.all(executionPromises.map(function (promise) { return promise.reflect(); })).each(function (promise, index, length) { if (promise.isFulfilled()) { this.trackPromises[index].resolve(); } else { var errorResponse = promise.reason().jqXHR.responseJSON; if (errorResponse.errors[0].errorCode === 'cmNameConflict' || this.getPathStringFromTargetLoc() === this.getPathStringFromObjectSearchPath(this.inputObjects[0])) { var nCDialog = new NameCollisionDialog('nameCollision', StringResource.get('nameCollision', { 'nameOfItem': this.targetLocation.defaultName }), StringResource.get('nameCollisionMessage')); var itemUrl = this.trackPromises[index].url; nCDialog.create(function () { this._replace(itemUrl, index); }.bind(this), function () { this._keepBoth(1, itemUrl, this.trackPromises[index].defaultName, index); }.bind(this), this._skip.bind(this), 'copy', this.inputObjects[0].defaultName); nCDialog.open(); } else { this.glassContext.appController.showErrorMessage(errorResponse.errors[0].messages[0], StringResource.get('copyError')); this.trackPromises[index].resolve(); } } }.bind(this)); var pObjs = []; _.each(this.trackPromises, function (item, index, list) { pObjs[index] = item.promise; }.bind(this)); return pObjs; }, move: function move(a) { var aPromises = this._handleCopyMoveRequests('move'); Q.allSettled(aPromises).then(function (r) { this._refreshAccountListPane(); this.dialog.remove(); this.glassContext.appController.showToast(StringResource.get('moveSuccess'), { 'type': 'success' }); this.parent.refresh(); }.bind(this), function (e) { this.dialog.remove(); this.glassContext.appController.showToast(StringResource.get('moveError'), { 'type': 'error' }); }.bind(this)); }, makeCopyRequest: function makeCopyRequest(url) { return this.glassContext.services.fetch.post(url, { contentType: 'application/json; charset=utf-8' }); }, makeCopyRenameRequest: function makeCopyRenameRequest(url, count, defaultName) { var newName = defaultName + ' (' + count + ')'; var newUrl = url + '&defaultName=' + newName; return this.glassContext.services.fetch.post(newUrl, { contentType: 'application/json; charset=utf-8' }); }, makeMoveRenameRequest: function makeMoveRenameRequest(url, count, defaultName) { var newName = defaultName + ' (' + count + ')'; var newUrl = url + '&defaultName=' + newName; return this.glassContext.services.fetch.put(newUrl, { contentType: 'application/json; charset=utf-8' }); }, makeMoveRequest: function makeMoveRequest(url) { return this.glassContext.services.fetch.put(url); }, _refreshAccountListPane: function _refreshAccountListPane() { this.parent.listAdaptor.sortChanged = true; this.parent.listView.reload(false); } }); return SecurityObjectExplorerCopyMoveView; });