From f904558315a2c48f484f81eb8465d98c0982d5b8 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Mon, 17 Apr 2017 23:11:24 -0400 Subject: [PATCH] manage cipher subvaults from org admin --- .../organizationVaultController.js | 46 ++++++---- ...ganizationVaultLoginSubvaultsController.js | 83 +++++++++++++++++++ .../organization/views/organizationVault.html | 67 +++------------ .../organizationVaultLoginSubvaults.html | 52 ++++++++++++ src/app/services/apiService.js | 1 + src/index.html | 1 + 6 files changed, 179 insertions(+), 71 deletions(-) create mode 100644 src/app/organization/organizationVaultLoginSubvaultsController.js create mode 100644 src/app/organization/views/organizationVaultLoginSubvaults.html diff --git a/src/app/organization/organizationVaultController.js b/src/app/organization/organizationVaultController.js index 84ce96a113..982c7f7686 100644 --- a/src/app/organization/organizationVaultController.js +++ b/src/app/organization/organizationVaultController.js @@ -1,21 +1,24 @@ angular - .module('bit.vault') + .module('bit.organization') .controller('organizationVaultController', function ($scope, apiService, cipherService, $analytics, $q, $state, $localStorage, $uibModal, $filter) { $scope.logins = []; $scope.subvaults = []; - $scope.folders = []; $scope.loading = true; $scope.$on('$viewContentLoaded', function () { var subvaultPromise = apiService.subvaults.listOrganization({ orgId: $state.params.orgId }, function (subvaults) { - var decSubvaults = []; + var decSubvaults = [{ + id: null, + name: 'Unassigned', + collapsed: $localStorage.collapsedOrgSubvaults && 'unassigned' in $localStorage.collapsedOrgSubvaults + }]; for (var i = 0; i < subvaults.Data.length; i++) { var decSubvault = cipherService.decryptSubvault(subvaults.Data[i], null, true); - decSubvault.collapsed = $localStorage.collapsedSubvaults && - decSubvault.id in $localStorage.collapsedSubvaults; + decSubvault.collapsed = $localStorage.collapsedOrgSubvaults && + decSubvault.id in $localStorage.collapsedOrgSubvaults; decSubvaults.push(decSubvault); } @@ -43,14 +46,20 @@ $scope.filterBySubvault = function (subvault) { return function (cipher) { + if (!cipher.subvaultIds || !cipher.subvaultIds.length) { + return subvault.id === null; + } + return cipher.subvaultIds.indexOf(subvault.id) > -1; }; }; - $scope.filterByOrphaned = function () { - return function (cipher) { - return !cipher.subvaultIds || !cipher.subvaultIds.length; - }; + $scope.subvaultSort = function (item) { + if (!item.id) { + return ''; + } + + return item.name.toLowerCase(); }; $scope.collapseExpand = function (subvault) { @@ -58,27 +67,30 @@ $localStorage.collapsedOrgSubvaults = {}; } - if (subvault.id in $localStorage.collapsedOrgSubvaults) { - delete $localStorage.collapsedOrgSubvaults[subvault.id]; + var id = subvault.id || 'unassigned'; + + if (id in $localStorage.collapsedOrgSubvaults) { + delete $localStorage.collapsedOrgSubvaults[id]; } else { - $localStorage.collapsedOrgSubvaults[subvault.id] = true; + $localStorage.collapsedOrgSubvaults[id] = true; } }; - $scope.editSubvaults = function (login) { + $scope.editSubvaults = function (cipher) { var modal = $uibModal.open({ animation: true, - templateUrl: 'app/vault/views/vaultLoginSubvaults.html', - controller: 'vaultOrganizationLoginSubvaultsController', + templateUrl: 'app/organization/views/organizationVaultLoginSubvaults.html', + controller: 'organizationVaultLoginSubvaultsController', resolve: { - loginId: function () { return login.id; } + cipher: function () { return cipher; }, + subvaults: function () { return $scope.subvaults; } } }); modal.result.then(function (response) { if (response.subvaultIds) { - login.subvaultIds = response.subvaultIds; + cipher.subvaultIds = response.subvaultIds; } }); }; diff --git a/src/app/organization/organizationVaultLoginSubvaultsController.js b/src/app/organization/organizationVaultLoginSubvaultsController.js new file mode 100644 index 0000000000..5ebf07b547 --- /dev/null +++ b/src/app/organization/organizationVaultLoginSubvaultsController.js @@ -0,0 +1,83 @@ +angular + .module('bit.organization') + + .controller('organizationVaultLoginSubvaultsController', function ($scope, apiService, $uibModalInstance, cipherService, + cipher, $analytics, subvaults) { + $analytics.eventTrack('organizationVaultLoginSubvaultsController', { category: 'Modal' }); + $scope.cipher = {}; + $scope.subvaults = []; + $scope.selectedSubvaults = {}; + + $uibModalInstance.opened.then(function () { + var subvaultUsed = []; + for (var i = 0; i < subvaults.length; i++) { + if (subvaults[i].id) { + subvaultUsed.push(subvaults[i]); + } + } + $scope.subvaults = subvaultUsed; + + $scope.cipher = cipher; + + var selectedSubvaults = {}; + if ($scope.cipher.subvaultIds) { + for (i = 0; i < $scope.cipher.subvaultIds.length; i++) { + selectedSubvaults[$scope.cipher.subvaultIds[i]] = true; + } + } + $scope.selectedSubvaults = selectedSubvaults; + }); + + $scope.toggleSubvaultSelectionAll = function ($event) { + var subvaults = {}; + if ($event.target.checked) { + for (var i = 0; i < $scope.subvaults.length; i++) { + subvaults[$scope.subvaults[i].id] = true; + } + } + + $scope.selectedSubvaults = subvaults; + }; + + $scope.toggleSubvaultSelection = function (id) { + if (id in $scope.selectedSubvaults) { + delete $scope.selectedSubvaults[id]; + } + else { + $scope.selectedSubvaults[id] = true; + } + }; + + $scope.subvaultSelected = function (subvault) { + return subvault.id in $scope.selectedSubvaults; + }; + + $scope.allSelected = function () { + return Object.keys($scope.selectedSubvaults).length === $scope.subvaults.length; + }; + + $scope.submit = function () { + var request = { + subvaultIds: [] + }; + + for (var id in $scope.selectedSubvaults) { + if ($scope.selectedSubvaults.hasOwnProperty(id)) { + request.subvaultIds.push(id); + } + } + + $scope.submitPromise = apiService.ciphers.putSubvaultsAdmin({ id: cipher.id }, request) + .$promise.then(function (response) { + $analytics.eventTrack('Edited Login Subvaults'); + $uibModalInstance.close({ + action: 'subvaultsEdit', + subvaultIds: request.subvaultIds + }); + }); + }; + + $scope.close = function () { + $uibModalInstance.dismiss('cancel'); + }; + }); diff --git a/src/app/organization/views/organizationVault.html b/src/app/organization/views/organizationVault.html index 360aa9e63d..a42479625e 100644 --- a/src/app/organization/views/organizationVault.html +++ b/src/app/organization/views/organizationVault.html @@ -1,19 +1,21 @@ 

Org Vault - {{subvaults.length}} subvaults, {{logins.length}} logins + + , + +

-
-

Loading...

-
-
+

Loading...

+

- - {{subvault.name}} {{subvaultLogins.length}} logins + + {{subvault.name}} +

-
-
-

- - Orphaned {{orphanedLogins.length}} logins -

-
-
-
-

No orphaned logins.

-
-
- - - - - - - -
- - - {{login.name}} -
{{login.username}}
-
-
-
-
diff --git a/src/app/organization/views/organizationVaultLoginSubvaults.html b/src/app/organization/views/organizationVaultLoginSubvaults.html new file mode 100644 index 0000000000..c516b85751 --- /dev/null +++ b/src/app/organization/views/organizationVaultLoginSubvaults.html @@ -0,0 +1,52 @@ + +
+ + +
\ No newline at end of file diff --git a/src/app/services/apiService.js b/src/app/services/apiService.js index 0238ede743..54d1dd8700 100644 --- a/src/app/services/apiService.js +++ b/src/app/services/apiService.js @@ -32,6 +32,7 @@ putPartial: { url: _apiUri + '/ciphers/:id/partial', method: 'POST', params: { id: '@id' } }, putShare: { url: _apiUri + '/ciphers/:id/share', method: 'POST', params: { id: '@id' } }, putSubvaults: { url: _apiUri + '/ciphers/:id/subvaults', method: 'POST', params: { id: '@id' } }, + putSubvaultsAdmin: { url: _apiUri + '/ciphers/:id/subvaults-admin', method: 'POST', params: { id: '@id' } }, del: { url: _apiUri + '/ciphers/:id/delete', method: 'POST', params: { id: '@id' } } }); diff --git a/src/index.html b/src/index.html index 52d9e4910b..474e6a709b 100644 --- a/src/index.html +++ b/src/index.html @@ -145,6 +145,7 @@ +