mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-23 11:56:00 +01:00
org user invites and confirmation
This commit is contained in:
parent
b36799bf0c
commit
a9e85f8765
@ -22,6 +22,24 @@ angular
|
||||
|
||||
$(document).off('click', '.sidebar li a');
|
||||
}
|
||||
|
||||
$('.table-responsive').on('shown.bs.dropdown', function (e) {
|
||||
var t = $(this),
|
||||
m = $(e.target).find('.dropdown-menu'),
|
||||
tb = t.offset().top + t.height(),
|
||||
mb = m.offset().top + m.outerHeight(true),
|
||||
d = 20; // Space for shadow + scrollbar.
|
||||
if (t[0].scrollWidth > t.innerWidth()) {
|
||||
if (mb + d > tb) {
|
||||
t.css('padding-bottom', ((mb + d) - tb));
|
||||
}
|
||||
}
|
||||
else {
|
||||
t.css('overflow', 'visible');
|
||||
}
|
||||
}).on('hidden.bs.dropdown', function () {
|
||||
$(this).css({ 'padding-bottom': '', 'overflow': '' });
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
|
||||
|
@ -1,6 +1,52 @@
|
||||
angular
|
||||
.module('bit.organization')
|
||||
|
||||
.controller('organizationPeopleController', function ($scope) {
|
||||
.controller('organizationPeopleController', function ($scope, $state, $uibModal, cryptoService, apiService, toastr) {
|
||||
$scope.users = [];
|
||||
loadList();
|
||||
|
||||
$scope.confirm = function (user) {
|
||||
apiService.users.getPublicKey({ id: user.userId }, function (userKey) {
|
||||
var key = cryptoService.rsaEncrypt('org key', userKey.PublicKey);
|
||||
apiService.organizationUsers.confirm({ orgId: $state.params.orgId, id: user.id }, { key: key }, function () {
|
||||
user.status = 2;
|
||||
toastr.success(user.email + ' has been confirmed.', 'User Confirmed');
|
||||
}, function () {
|
||||
toastr.error('Unable to confirm user.', 'Error');
|
||||
});
|
||||
}, function () {
|
||||
toastr.error('Unable to confirm user.', 'Error');
|
||||
});
|
||||
};
|
||||
|
||||
$scope.invite = function () {
|
||||
var modal = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: 'app/organization/views/organizationPeopleInvite.html',
|
||||
controller: 'organizationPeopleInviteController'
|
||||
});
|
||||
|
||||
modal.result.then(function () {
|
||||
loadList();
|
||||
});
|
||||
};
|
||||
|
||||
function loadList() {
|
||||
apiService.organizationUsers.list({ orgId: $state.params.orgId }, function (list) {
|
||||
var users = [];
|
||||
|
||||
for (var i = 0; i < list.Data.length; i++) {
|
||||
users.push({
|
||||
id: list.Data[i].Id,
|
||||
userId: list.Data[i].UserId,
|
||||
name: list.Data[i].Name,
|
||||
email: list.Data[i].Email,
|
||||
status: list.Data[i].Status,
|
||||
type: list.Data[i].Type
|
||||
});
|
||||
}
|
||||
|
||||
$scope.users = users;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
14
src/app/organization/organizationPeopleInviteController.js
Normal file
14
src/app/organization/organizationPeopleInviteController.js
Normal file
@ -0,0 +1,14 @@
|
||||
angular
|
||||
.module('bit.organization')
|
||||
|
||||
.controller('organizationPeopleInviteController', function ($scope, $state, $uibModalInstance, apiService) {
|
||||
$scope.submit = function (model) {
|
||||
apiService.organizationUsers.invite({ orgId: $state.params.orgId }, { email: model.email }, function () {
|
||||
$uibModalInstance.close();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.close = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
};
|
||||
});
|
@ -7,15 +7,53 @@
|
||||
<section class="content">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Users</h3>
|
||||
<h3 class="box-title">Organization Users</h3>
|
||||
<div class="box-tools">
|
||||
<button type="button" class="btn btn-primary btn-sm">
|
||||
<button type="button" class="btn btn-primary btn-sm btn-flat" ng-click="invite()">
|
||||
Invite user
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
Some data
|
||||
<div class="box-body" ng-class="{'no-padding': users.length}">
|
||||
<div ng-show="!users.length">
|
||||
Loading...
|
||||
</div>
|
||||
<div class="table-responsive" ng-show="users.length">
|
||||
<table class="table table-striped table-hover">
|
||||
<tbody>
|
||||
<tr ng-repeat="user in users | orderBy: ['name', 'email']">
|
||||
<td style="width: 70px;" valign="middle">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fa fa-cog"></i> <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="javascript:void(0)" ng-click="confirm(user)">Confirm</a>
|
||||
</li>
|
||||
<li><a href="#">Re-send Invitation</a></li>
|
||||
<li><a href="#" class="text-danger">Remove</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width: 45px;" valign="middle">
|
||||
<img src="//www.gravatar.com/avatar/{{user.email | gravatar}}.jpg?s=45&d=mm"
|
||||
class="img-circle" alt="User Image">
|
||||
</td>
|
||||
<td valign="middle">
|
||||
{{user.email}}
|
||||
<div ng-if="user.name"><small class="text-muted">{{user.name}}</small></div>
|
||||
</td>
|
||||
<td style="width: 80px;" valign="middle">
|
||||
{{user.type}}
|
||||
</td>
|
||||
<td style="width: 80px;" valign="middle">
|
||||
{{user.status}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
29
src/app/organization/views/organizationPeopleInvite.html
Normal file
29
src/app/organization/views/organizationPeopleInvite.html
Normal file
@ -0,0 +1,29 @@
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title"><i class="fa fa-user"></i> Invite User</h4>
|
||||
</div>
|
||||
<form name="inviteForm" ng-submit="inviteForm.$valid && submit(model)" api-form="submitPromise">
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
Invite a new user to your organization by entering their bitwarden account email address below. Users must already
|
||||
be registered with bitwarden before you can invite them to your organization.
|
||||
</p>
|
||||
<div class="callout callout-danger validation-errors" ng-show="inviteForm.$errors">
|
||||
<h4>Errors have occured</h4>
|
||||
<ul>
|
||||
<li ng-repeat="e in inviteForm.$errors">{{e}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="Email" ng-model="model.email" class="form-control" required api-field />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="inviteForm.$loading">
|
||||
<i class="fa fa-refresh fa-spin loading-icon" ng-show="inviteForm.$loading"></i>Send Invite
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Subvaults</h3>
|
||||
<div class="box-tools">
|
||||
<button type="button" class="btn btn-primary btn-sm">
|
||||
<button type="button" class="btn btn-primary btn-sm btn-flat">
|
||||
New subvault
|
||||
</button>
|
||||
</div>
|
||||
|
@ -38,6 +38,15 @@
|
||||
del: { url: _apiUri + '/organizations/:id/delete', method: 'POST', params: { id: '@id' } }
|
||||
});
|
||||
|
||||
_service.organizationUsers = $resource(_apiUri + '/organizations/:orgId/users/:id', {}, {
|
||||
get: { method: 'GET', params: { id: '@id', orgId: '@orgId' } },
|
||||
list: { method: 'GET', params: { orgId: '@orgId' } },
|
||||
invite: { url: _apiUri + '/organizations/:orgId/users/invite', method: 'POST', params: { orgId: '@orgId' } },
|
||||
accept: { url: _apiUri + '/organizations/:orgId/users/:id/accept', method: 'POST', params: { id: '@id', orgId: '@orgId' } },
|
||||
confirm: { url: _apiUri + '/organizations/:orgId/users/:id/confirm', method: 'POST', params: { id: '@id', orgId: '@orgId' } },
|
||||
del: { url: _apiUri + '/organizations/:orgId/users/:id/delete', method: 'POST', params: { id: '@id', orgId: '@orgId' } }
|
||||
});
|
||||
|
||||
_service.accounts = $resource(_apiUri + '/accounts', {}, {
|
||||
register: { url: _apiUri + '/accounts/register', method: 'POST', params: {} },
|
||||
emailToken: { url: _apiUri + '/accounts/email-token', method: 'POST', params: {} },
|
||||
@ -61,6 +70,10 @@
|
||||
putDomains: { url: _apiUri + '/settings/domains', method: 'POST', params: {} },
|
||||
});
|
||||
|
||||
_service.users = $resource(_apiUri + '/users/:id', {}, {
|
||||
getPublicKey: { url: _apiUri + '/users/:id/public-key', method: 'GET', params: { id: '@id' } }
|
||||
});
|
||||
|
||||
_service.identity = $resource(_apiUri + '/connect', {}, {
|
||||
token: {
|
||||
url: _apiUri + '/connect/token',
|
||||
|
@ -190,6 +190,11 @@ angular
|
||||
throw 'Public key unavailable.';
|
||||
}
|
||||
|
||||
if (typeof publicKey === 'string') {
|
||||
var publicKeyBytes = forge.util.decode64(publicKey);
|
||||
publicKey = forge.pki.publicKeyFromAsn1(forge.asn1.fromDer(publicKeyBytes));
|
||||
}
|
||||
|
||||
var encryptedBytes = publicKey.encrypt(plainValue, 'RSA-OAEP', {
|
||||
md: forge.md.sha256.create()
|
||||
});
|
||||
|
@ -123,6 +123,7 @@
|
||||
<script src="app/organization/organizationModule.js"></script>
|
||||
<script src="app/organization/organizationDashboardController.js"></script>
|
||||
<script src="app/organization/organizationPeopleController.js"></script>
|
||||
<script src="app/organization/organizationPeopleInviteController.js"></script>
|
||||
<script src="app/organization/organizationSubvaultsController.js"></script>
|
||||
|
||||
<script src="app/settings/settingsModule.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user