mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
billing license management when self hosted
This commit is contained in:
@@ -137,6 +137,11 @@
|
|||||||
url: _apiUri + '/accounts/premium',
|
url: _apiUri + '/accounts/premium',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': undefined }
|
headers: { 'Content-Type': undefined }
|
||||||
|
},
|
||||||
|
putLicense: {
|
||||||
|
url: _apiUri + '/accounts/license',
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': undefined }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
angular
|
angular
|
||||||
.module('bit.settings')
|
.module('bit.settings')
|
||||||
|
|
||||||
.controller('settingsBillingController', function ($scope, apiService, authService, $state, $uibModal, toastr, $analytics) {
|
.controller('settingsBillingController', function ($scope, apiService, authService, $state, $uibModal, toastr, $analytics,
|
||||||
|
appSettings) {
|
||||||
|
$scope.selfHosted = appSettings.selfHosted;
|
||||||
$scope.charges = [];
|
$scope.charges = [];
|
||||||
$scope.paymentSource = null;
|
$scope.paymentSource = null;
|
||||||
$scope.subscription = null;
|
$scope.subscription = null;
|
||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
var license = null;
|
var license = null;
|
||||||
|
$scope.expiration = null;
|
||||||
|
|
||||||
$scope.$on('$viewContentLoaded', function () {
|
$scope.$on('$viewContentLoaded', function () {
|
||||||
load();
|
load();
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.changePayment = function () {
|
$scope.changePayment = function () {
|
||||||
|
if ($scope.selfHosted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var modal = $uibModal.open({
|
var modal = $uibModal.open({
|
||||||
animation: true,
|
animation: true,
|
||||||
templateUrl: 'app/settings/views/settingsBillingChangePayment.html',
|
templateUrl: 'app/settings/views/settingsBillingChangePayment.html',
|
||||||
@@ -30,6 +37,10 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.adjustStorage = function (add) {
|
$scope.adjustStorage = function (add) {
|
||||||
|
if ($scope.selfHosted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var modal = $uibModal.open({
|
var modal = $uibModal.open({
|
||||||
animation: true,
|
animation: true,
|
||||||
templateUrl: 'app/settings/views/settingsBillingAdjustStorage.html',
|
templateUrl: 'app/settings/views/settingsBillingAdjustStorage.html',
|
||||||
@@ -47,6 +58,10 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.cancel = function () {
|
$scope.cancel = function () {
|
||||||
|
if ($scope.selfHosted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to cancel? You will lose access to all premium features at the end ' +
|
if (!confirm('Are you sure you want to cancel? You will lose access to all premium features at the end ' +
|
||||||
'of this billing cycle.')) {
|
'of this billing cycle.')) {
|
||||||
return;
|
return;
|
||||||
@@ -61,6 +76,10 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.reinstate = function () {
|
$scope.reinstate = function () {
|
||||||
|
if ($scope.selfHosted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to remove the cancellation request and reinstate your premium membership?')) {
|
if (!confirm('Are you sure you want to remove the cancellation request and reinstate your premium membership?')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,7 +92,27 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.updateLicense = function () {
|
||||||
|
if (!$scope.selfHosted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var modal = $uibModal.open({
|
||||||
|
animation: true,
|
||||||
|
templateUrl: 'app/settings/views/settingsBillingUpdateLicense.html',
|
||||||
|
controller: 'settingsBillingUpdateLicenseController'
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.result.then(function () {
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$scope.license = function () {
|
$scope.license = function () {
|
||||||
|
if ($scope.selfHosted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var licenseString = JSON.stringify(license, null, 2);
|
var licenseString = JSON.stringify(license, null, 2);
|
||||||
var licenseBlob = new Blob([licenseString]);
|
var licenseBlob = new Blob([licenseString]);
|
||||||
|
|
||||||
@@ -107,7 +146,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
$scope.expiration = billing.Expiration;
|
||||||
license = billing.License;
|
license = billing.License;
|
||||||
|
|
||||||
$scope.storage = null;
|
$scope.storage = null;
|
||||||
|
|||||||
30
src/app/settings/settingsBillingUpdateLicenseController.js
Normal file
30
src/app/settings/settingsBillingUpdateLicenseController.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
angular
|
||||||
|
.module('bit.settings')
|
||||||
|
|
||||||
|
.controller('settingsBillingUpdateLicenseController', function ($scope, $state, $uibModalInstance, apiService,
|
||||||
|
$analytics, toastr, validationService) {
|
||||||
|
$analytics.eventTrack('settingsBillingUpdateLicenseController', { category: 'Modal' });
|
||||||
|
|
||||||
|
$scope.submit = function (form) {
|
||||||
|
var fileEl = document.getElementById('file');
|
||||||
|
var files = fileEl.files;
|
||||||
|
if (!files || !files.length) {
|
||||||
|
validationService.addError(form, 'file', 'Select a license file.', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fd = new FormData();
|
||||||
|
fd.append('license', files[0]);
|
||||||
|
|
||||||
|
$scope.submitPromise = apiService.accounts.putLicense(fd)
|
||||||
|
.$promise.then(function (response) {
|
||||||
|
$analytics.eventTrack('Updated License');
|
||||||
|
toastr.success('You have updated your license.');
|
||||||
|
$uibModalInstance.close();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.close = function () {
|
||||||
|
$uibModalInstance.dismiss('cancel');
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -21,7 +21,19 @@
|
|||||||
<h3 class="box-title">Premium Membership</h3>
|
<h3 class="box-title">Premium Membership</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
<div class="row">
|
<dl ng-if="selfHosted">
|
||||||
|
<dt>Expiration</dt>
|
||||||
|
<dd ng-if="loading">
|
||||||
|
Loading...
|
||||||
|
</dd>
|
||||||
|
<dd ng-if="!loading && expiration">
|
||||||
|
{{expiration | date: 'medium'}}
|
||||||
|
</dd>
|
||||||
|
<dd ng-if="!loading && !expiration">
|
||||||
|
Never expires
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<div class="row" ng-if="!selfHosted">
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Status</dt>
|
<dt>Status</dt>
|
||||||
@@ -30,7 +42,7 @@
|
|||||||
<span ng-if="subscription.markedForCancel">- marked for cancellation</span>
|
<span ng-if="subscription.markedForCancel">- marked for cancellation</span>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Next Charge</dt>
|
<dt>Next Charge</dt>
|
||||||
<dd>{{nextInvoice ? ((nextInvoice.date | date: format: mediumDate) + ', ' + (nextInvoice.amount | currency:'$')) : '-'}}</dd>
|
<dd>{{nextInvoice ? ((nextInvoice.date | date: 'mediumDate') + ', ' + (nextInvoice.amount | currency:'$')) : '-'}}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
@@ -54,7 +66,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-footer" ng-if="!loading && subscription && (!subscription.cancelled || subscription.markedForCancel)">
|
<div class="box-footer" ng-if="!selfHosted && !loading && subscription &&
|
||||||
|
(!subscription.cancelled || subscription.markedForCancel)">
|
||||||
<button type="button" class="btn btn-default btn-flat" ng-click="cancel()"
|
<button type="button" class="btn btn-default btn-flat" ng-click="cancel()"
|
||||||
ng-if="!subscription.cancelled && !subscription.markedForCancel">
|
ng-if="!subscription.cancelled && !subscription.markedForCancel">
|
||||||
Cancel
|
Cancel
|
||||||
@@ -68,8 +81,16 @@
|
|||||||
Download License
|
Download License
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="box-footer" ng-if="selfHosted">
|
||||||
|
<button type="button" class="btn btn-default btn-flat" ng-click="updateLicense()">
|
||||||
|
Update License
|
||||||
|
</button>
|
||||||
|
<a href="https://vault.bitwarden.com" class="btn btn-default btn-flat" target="_blank">
|
||||||
|
Manage Membership
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box box-default" ng-if="storage">
|
<div class="box box-default" ng-if="storage && !selfHosted">
|
||||||
<div class="box-header with-border">
|
<div class="box-header with-border">
|
||||||
<h3 class="box-title">Storage</h3>
|
<h3 class="box-title">Storage</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -95,7 +116,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box box-default">
|
<div class="box box-default" ng-if="!selfHosted">
|
||||||
<div class="box-header with-border">
|
<div class="box-header with-border">
|
||||||
<h3 class="box-title">Payment Method</h3>
|
<h3 class="box-title">Payment Method</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,7 +139,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box box-default">
|
<div class="box box-default" ng-if="!selfHosted">
|
||||||
<div class="box-header with-border">
|
<div class="box-header with-border">
|
||||||
<h3 class="box-title">Charges</h3>
|
<h3 class="box-title">Charges</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,7 +155,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="charge in charges">
|
<tr ng-repeat="charge in charges">
|
||||||
<td style="width: 200px">
|
<td style="width: 200px">
|
||||||
{{charge.date | date: format: mediumDate}}
|
{{charge.date | date: 'mediumDate'}}
|
||||||
</td>
|
</td>
|
||||||
<td style="min-width: 150px">
|
<td style="min-width: 150px">
|
||||||
{{charge.paymentSource}}
|
{{charge.paymentSource}}
|
||||||
|
|||||||
30
src/app/settings/views/settingsBillingUpdateLicense.html
Normal file
30
src/app/settings/views/settingsBillingUpdateLicense.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<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-drivers-license"></i>
|
||||||
|
Update License
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<form name="form" ng-submit="form.$valid && submit(form)" api-form="submitPromise">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="callout callout-danger validation-errors" ng-show="form.$errors">
|
||||||
|
<h4>Errors have occurred</h4>
|
||||||
|
<ul>
|
||||||
|
<li ng-repeat="e in form.$errors">{{e}}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" show-error>
|
||||||
|
<label for="file" class="sr-only">License</label>
|
||||||
|
<input type="file" id="file" name="file" accept=".json" />
|
||||||
|
<p class="help-block">
|
||||||
|
Your license file will be named something like <code>bitwarden_premium_license.json</code>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="form.$loading">
|
||||||
|
<i class="fa fa-refresh fa-spin loading-icon" ng-show="form.$loading"></i>Submit
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
@@ -236,6 +236,7 @@
|
|||||||
<script src="app/settings/settingsBillingChangePaymentController.js"></script>
|
<script src="app/settings/settingsBillingChangePaymentController.js"></script>
|
||||||
<script src="app/settings/settingsUpdateKeyController.js"></script>
|
<script src="app/settings/settingsUpdateKeyController.js"></script>
|
||||||
<script src="app/settings/settingsPremiumController.js"></script>
|
<script src="app/settings/settingsPremiumController.js"></script>
|
||||||
|
<script src="app/settings/settingsBillingUpdateLicenseController.js"></script>
|
||||||
|
|
||||||
<script src="app/tools/toolsModule.js"></script>
|
<script src="app/tools/toolsModule.js"></script>
|
||||||
<script src="app/tools/toolsController.js"></script>
|
<script src="app/tools/toolsController.js"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user