Merge "Users may now issue their own access tokens."
This commit is contained in:
commit
c4e7615817
63
src/app/profile/controller/profile_token_new_controller.js
Normal file
63
src/app/profile/controller/profile_token_new_controller.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License. You may obtain
|
||||||
|
* a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issue token controller.
|
||||||
|
*/
|
||||||
|
angular.module('sb.profile').controller('ProfileTokenNewController',
|
||||||
|
function ($q, $log, $scope, $modalInstance, UserToken, user) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag for the UI to indicate that we're saving.
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
$scope.isSaving = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The new token.
|
||||||
|
*
|
||||||
|
* @type {UserToken}
|
||||||
|
*/
|
||||||
|
$scope.token = new UserToken({
|
||||||
|
user_id: user.id,
|
||||||
|
expires_in: 3600
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the project group
|
||||||
|
*/
|
||||||
|
$scope.save = function () {
|
||||||
|
$scope.isSaving = true;
|
||||||
|
$scope.token.$create(
|
||||||
|
function (token) {
|
||||||
|
$modalInstance.close(token);
|
||||||
|
$scope.isSaving = false;
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
$scope.isSaving = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close this modal without saving.
|
||||||
|
*/
|
||||||
|
$scope.close = function () {
|
||||||
|
$modalInstance.dismiss('cancel');
|
||||||
|
};
|
||||||
|
});
|
70
src/app/profile/controller/profile_tokens_controller.js
Normal file
70
src/app/profile/controller/profile_tokens_controller.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License. You may obtain
|
||||||
|
* a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User profile controller for all of a user's auth tokens.
|
||||||
|
*/
|
||||||
|
angular.module('sb.profile').controller('ProfileTokensController',
|
||||||
|
function ($scope, UserToken, tokens, $modal) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
$scope.tokens = tokens;
|
||||||
|
|
||||||
|
$scope.deleteToken = function (token) {
|
||||||
|
token.$delete(function () {
|
||||||
|
var idx = $scope.tokens.indexOf(token);
|
||||||
|
if (idx > -1) {
|
||||||
|
$scope.tokens.splice(idx, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.issueToken = function () {
|
||||||
|
$modal.open({
|
||||||
|
templateUrl: 'app/profile/template/token_new.html',
|
||||||
|
controller: 'ProfileTokenNewController',
|
||||||
|
resolve: {
|
||||||
|
user: function (CurrentUser) {
|
||||||
|
return CurrentUser.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).result.then(function (token) {
|
||||||
|
// On success, append the token.
|
||||||
|
$scope.tokens.push(token);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for a single token row within the profile token view.
|
||||||
|
*/
|
||||||
|
angular.module('sb.profile').controller('ProfileTokenItemController',
|
||||||
|
function ($scope, AccessToken) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var now = new Date();
|
||||||
|
|
||||||
|
// Render the expiration date.
|
||||||
|
$scope.created = new Date($scope.token.created_at);
|
||||||
|
$scope.expires = new Date($scope.token.created_at);
|
||||||
|
$scope.expires.setSeconds($scope.expires.getSeconds() +
|
||||||
|
$scope.token.expires_in);
|
||||||
|
|
||||||
|
$scope.expired = $scope.expires.getTime() < now.getTime();
|
||||||
|
$scope.current =
|
||||||
|
$scope.token.access_token === AccessToken.getAccessToken();
|
||||||
|
});
|
@ -23,8 +23,8 @@
|
|||||||
* @author Michael Krotscheck
|
* @author Michael Krotscheck
|
||||||
*/
|
*/
|
||||||
angular.module('sb.profile',
|
angular.module('sb.profile',
|
||||||
['sb.services', 'sb.templates', 'sb.auth', 'ui.router', 'ui.bootstrap']
|
['sb.services', 'sb.templates', 'sb.auth', 'ui.router', 'ui.bootstrap']
|
||||||
)
|
)
|
||||||
.config(function ($stateProvider, SessionResolver, $urlRouterProvider) {
|
.config(function ($stateProvider, SessionResolver, $urlRouterProvider) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ angular.module('sb.profile',
|
|||||||
isLoggedIn: SessionResolver.requireLoggedIn,
|
isLoggedIn: SessionResolver.requireLoggedIn,
|
||||||
currentUser: SessionResolver.requireCurrentUser
|
currentUser: SessionResolver.requireCurrentUser
|
||||||
},
|
},
|
||||||
views : {
|
views: {
|
||||||
'submenu@': {
|
'submenu@': {
|
||||||
templateUrl: 'app/profile/template/profile_submenu.html'
|
templateUrl: 'app/profile/template/profile_submenu.html'
|
||||||
},
|
},
|
||||||
@ -53,5 +53,32 @@ angular.module('sb.profile',
|
|||||||
url: '/preferences',
|
url: '/preferences',
|
||||||
templateUrl: 'app/profile/template/preferences.html',
|
templateUrl: 'app/profile/template/preferences.html',
|
||||||
controller: 'ProfilePreferencesController'
|
controller: 'ProfilePreferencesController'
|
||||||
|
})
|
||||||
|
.state('profile.tokens', {
|
||||||
|
url: '/tokens',
|
||||||
|
templateUrl: 'app/profile/template/tokens.html',
|
||||||
|
controller: 'ProfileTokensController',
|
||||||
|
resolve: {
|
||||||
|
tokens: function (CurrentUser, UserToken, $q) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
|
||||||
|
CurrentUser.resolve().then(
|
||||||
|
function (currentUser) {
|
||||||
|
UserToken.query({
|
||||||
|
user_id: currentUser.id
|
||||||
|
}, function (results) {
|
||||||
|
deferred.resolve(results);
|
||||||
|
}, function (error) {
|
||||||
|
deferred.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
deferred.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -17,7 +17,7 @@
|
|||||||
<div class="container" ng-hide="isLoading">
|
<div class="container" ng-hide="isLoading">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<h1>Preferences</h1>
|
<h1><i class="fa fa-sb-profile-preferences"></i> Preferences</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -20,4 +20,9 @@
|
|||||||
<i class="fa fa-sb-profile-preferences fa-lg"></i>
|
<i class="fa fa-sb-profile-preferences fa-lg"></i>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li active-path="^\/profile/tokens.*">
|
||||||
|
<a href="#!/profile/tokens" title="Authentication Tokens">
|
||||||
|
<i class="fa fa-sb-profile-tokens fa-lg"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
102
src/app/profile/template/token_new.html
Normal file
102
src/app/profile/template/token_new.html
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
~ not use this file except in compliance with the License. You may obtain
|
||||||
|
~ a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
~ License for the specific language governing permissions and limitations
|
||||||
|
~ under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<button type="button" class="close"
|
||||||
|
ng-click="close()">×</button>
|
||||||
|
<h3 class="panel-title">Issue Access Token</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<form class="form-horizontal" role="form" name="tokenForm">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="expires_in" class="col-sm-3 control-label">
|
||||||
|
Expires in:
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="expires_in" class="form-control"
|
||||||
|
ng-model="token.expires_in"
|
||||||
|
required
|
||||||
|
ng-disabled="isSaving">
|
||||||
|
<option value="3600">1 hour</option>
|
||||||
|
<option value="86400">1 day</option>
|
||||||
|
<option value="604800">1 week</option>
|
||||||
|
<option value="31536000">1 year</option>
|
||||||
|
<option value="315360000">1 decade</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6 text-right">
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
ng-click="save()"
|
||||||
|
ng-disabled="!tokenForm.$valid || isSaving">
|
||||||
|
Issue Token
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
ng-click="close()"
|
||||||
|
ng-disabled="isSaving"
|
||||||
|
class="btn btn-default">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Template for story metadata -->
|
||||||
|
<script type="text/ng-template" id="/inline/project_row.html">
|
||||||
|
<td class="col-xs-11">
|
||||||
|
<div class="has-feedback has-feedback-no-label">
|
||||||
|
<input id="project"
|
||||||
|
type="text"
|
||||||
|
placeholder="Select a Project"
|
||||||
|
required
|
||||||
|
ng-model="project"
|
||||||
|
typeahead-editable="false"
|
||||||
|
typeahead-wait-ms="200"
|
||||||
|
typeahead="project as project.name for project
|
||||||
|
in searchProjects($viewValue)"
|
||||||
|
typeahead-loading="loadingProjects"
|
||||||
|
typeahead-on-select="selectNewProject(index, $model)"
|
||||||
|
typeahead-input-formatter="formatProjectName($model)"
|
||||||
|
ng-disabled="isSaving"
|
||||||
|
class="form-control input-sm"
|
||||||
|
/>
|
||||||
|
<span class="form-control-feedback text-muted
|
||||||
|
form-control-feedback-sm">
|
||||||
|
<i class="fa fa-refresh fa-spin" ng-show="loadingProjects"></i>
|
||||||
|
<i class="fa fa-search" ng-hide="loadingProjects"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<th class="col-xs-1"
|
||||||
|
ng-show="projects.length > 1">
|
||||||
|
<button type="button" class="close"
|
||||||
|
ng-click="removeProject(index)">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</th>
|
||||||
|
</script>
|
78
src/app/profile/template/tokens.html
Normal file
78
src/app/profile/template/tokens.html
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
~ not use this file except in compliance with the License. You may obtain
|
||||||
|
~ a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
~ License for the specific language governing permissions and limitations
|
||||||
|
~ under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="container" ng-hide="isLoading">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<h1><i class="fa fa-sb-profile-tokens"></i> Authentication
|
||||||
|
Tokens</h1>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-9 col-sm-10">
|
||||||
|
<p class="lead">Authorize and deauthorize authentication tokens
|
||||||
|
for StoryBoard.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-3 col-sm-2">
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-primary btn-sm pull-right"
|
||||||
|
ng-click="issueToken()">
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
|
<span class="hidden-sm hidden-xs">Issue Token</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<table class="table table-condensed">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Token</th>
|
||||||
|
<th>Issued</th>
|
||||||
|
<th>Expires</th>
|
||||||
|
<th> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="token in tokens"
|
||||||
|
ng-controller="ProfileTokenItemController">
|
||||||
|
<td>
|
||||||
|
<span class="label label-success"
|
||||||
|
ng-if="current">
|
||||||
|
Current
|
||||||
|
</span>
|
||||||
|
<span class="label label-danger"
|
||||||
|
ng-if="expired && !current">
|
||||||
|
Expired
|
||||||
|
</span>
|
||||||
|
<span class="label label-info"
|
||||||
|
ng-if="!expired && !current">
|
||||||
|
Active
|
||||||
|
</span>
|
||||||
|
{{token.access_token}}
|
||||||
|
</td>
|
||||||
|
<td><span time-moment eventdate="created"></span></td>
|
||||||
|
<td><span time-moment eventdate="expires"></span></td>
|
||||||
|
<td>
|
||||||
|
<button type="button"
|
||||||
|
class="close"
|
||||||
|
ng-click="deleteToken(token)"
|
||||||
|
ng-if="!current">×</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
35
src/app/services/resource/user_token.js
Normal file
35
src/app/services/resource/user_token.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License. You may obtain
|
||||||
|
* a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The angular resource abstraction that allows us to search, access, and
|
||||||
|
* modify individual user's authentication tokens.
|
||||||
|
*
|
||||||
|
* @see ResourceFactory
|
||||||
|
* @author Michael Krotscheck
|
||||||
|
*/
|
||||||
|
angular.module('sb.services').factory('UserToken',
|
||||||
|
function (ResourceFactory) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var resource = ResourceFactory.build(
|
||||||
|
'/users/:user_id/tokens/:id',
|
||||||
|
null,
|
||||||
|
{user_id: '@user_id', id: '@id'}
|
||||||
|
);
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
});
|
@ -29,3 +29,4 @@
|
|||||||
.@{fa-css-prefix}-sb-admin:before { content: @fa-var-gears; }
|
.@{fa-css-prefix}-sb-admin:before { content: @fa-var-gears; }
|
||||||
.@{fa-css-prefix}-sb-profile:before { content: @fa-var-user; }
|
.@{fa-css-prefix}-sb-profile:before { content: @fa-var-user; }
|
||||||
.@{fa-css-prefix}-sb-profile-preferences:before { content: @fa-var-gear; }
|
.@{fa-css-prefix}-sb-profile-preferences:before { content: @fa-var-gear; }
|
||||||
|
.@{fa-css-prefix}-sb-profile-tokens:before { content: @fa-var-key; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user