Merge "Users may now issue their own access tokens."

This commit is contained in:
Jenkins 2014-12-22 14:13:59 +00:00 committed by Gerrit Code Review
commit c4e7615817
9 changed files with 385 additions and 4 deletions

View 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');
};
});

View 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();
});

View File

@ -23,8 +23,8 @@
* @author Michael Krotscheck
*/
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) {
'use strict';
@ -40,7 +40,7 @@ angular.module('sb.profile',
isLoggedIn: SessionResolver.requireLoggedIn,
currentUser: SessionResolver.requireCurrentUser
},
views : {
views: {
'submenu@': {
templateUrl: 'app/profile/template/profile_submenu.html'
},
@ -53,5 +53,32 @@ angular.module('sb.profile',
url: '/preferences',
templateUrl: 'app/profile/template/preferences.html',
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;
}
}
});
});

View File

@ -17,7 +17,7 @@
<div class="container" ng-hide="isLoading">
<div class="row">
<div class="col-xs-12">
<h1>Preferences</h1>
<h1><i class="fa fa-sb-profile-preferences"></i> Preferences</h1>
</div>
</div>
<div class="row">

View File

@ -20,4 +20,9 @@
<i class="fa fa-sb-profile-preferences fa-lg"></i>
</a>
</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>

View 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()">&times;</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)">
&times;
</button>
</th>
</script>

View 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>&nbsp;</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>
&nbsp;{{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">&times;</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

View 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;
});

View File

@ -29,3 +29,4 @@
.@{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-preferences:before { content: @fa-var-gear; }
.@{fa-css-prefix}-sb-profile-tokens:before { content: @fa-var-key; }