Merge pull request #2519 from mabashian/2505-application-token

Removes application requirement when creating token, fixes delete personal token
This commit is contained in:
Michael Abashian
2018-07-16 10:31:52 -04:00
committed by GitHub
9 changed files with 169 additions and 71 deletions

View File

@@ -28,7 +28,8 @@ function TokensStrings (BaseString) {
DELETE_ACTION_LABEL: t.s('DELETE'), DELETE_ACTION_LABEL: t.s('DELETE'),
SCOPE_PLACEHOLDER: t.s('Select a scope'), SCOPE_PLACEHOLDER: t.s('Select a scope'),
SCOPE_READ_LABEL: t.s('Read'), SCOPE_READ_LABEL: t.s('Read'),
SCOPE_WRITE_LABEL: t.s('Write') SCOPE_WRITE_LABEL: t.s('Write'),
APPLICATION_HELP_TEXT: t.s('Leaving this field blank will result in the creation of a Personal Access Token which is not linked to an Application.')
}; };
ns.list = { ns.list = {
@@ -37,6 +38,7 @@ function TokensStrings (BaseString) {
ROW_ITEM_LABEL_USED: t.s('LAST USED'), ROW_ITEM_LABEL_USED: t.s('LAST USED'),
ROW_ITEM_LABEL_SCOPE: t.s('SCOPE'), ROW_ITEM_LABEL_SCOPE: t.s('SCOPE'),
ROW_ITEM_LABEL_APPLICATION: t.s('APPLICATION'), ROW_ITEM_LABEL_APPLICATION: t.s('APPLICATION'),
PERSONAL_ACCESS_TOKEN: t.s('Personal Access Token'),
HEADER: appName => t.s('{{ appName }} Token', { appName }), HEADER: appName => t.s('{{ appName }} Token', { appName }),
}; };
} }

View File

@@ -1,59 +1,72 @@
function AddTokensController ( function AddTokensController (
models, $state, strings, Rest, Alert, Wait, GetBasePath, models, $state, strings, Alert, Wait,
$filter, ProcessErrors, $scope $filter, ProcessErrors, $scope
) { ) {
const vm = this || {}; const vm = this || {};
const { application } = models; const { application, token, user } = models;
vm.mode = 'add'; vm.mode = 'add';
vm.strings = strings; vm.strings = strings;
vm.panelTitle = strings.get('add.PANEL_TITLE'); vm.panelTitle = strings.get('add.PANEL_TITLE');
vm.form = {}; vm.form = {
application: {
vm.form.application = { type: 'field',
type: 'field', label: 'Application',
label: 'Application', id: 'application',
id: 'application' required: false,
}; help_text: strings.get('add.APPLICATION_HELP_TEXT'),
vm.form.description = { _resource: 'application',
type: 'String', _route: 'users.edit.tokens.add.application',
label: 'Description', _model: application,
id: 'description' _placeholder: strings.get('add.APP_PLACEHOLDER')
}; },
description: {
vm.form.application._resource = 'application'; type: 'String',
vm.form.application._route = 'users.edit.tokens.add.application'; label: 'Description',
vm.form.application._model = application; id: 'description',
vm.form.application._placeholder = strings.get('add.APP_PLACEHOLDER'); required: false
vm.form.application.required = true; },
scope: {
vm.form.description.required = false; choices: [
[null, ''],
vm.form.scope = { ['read', strings.get('add.SCOPE_READ_LABEL')],
choices: [ ['write', strings.get('add.SCOPE_WRITE_LABEL')]
[null, ''], ],
['read', strings.get('add.SCOPE_READ_LABEL')], help_text: strings.get('add.SCOPE_HELP_TEXT'),
['write', strings.get('add.SCOPE_WRITE_LABEL')] id: 'scope',
], label: 'Scope',
help_text: strings.get('add.SCOPE_HELP_TEXT'), required: true,
id: 'scope', _component: 'at-input-select',
label: 'Scope', _data: [
required: true, [null, ''],
_component: 'at-input-select', ['read', strings.get('add.SCOPE_READ_LABEL')],
_data: [ ['write', strings.get('add.SCOPE_WRITE_LABEL')]
[null, ''], ],
['read', strings.get('add.SCOPE_READ_LABEL')], _exp: 'choice[1] for (index, choice) in state._data',
['write', strings.get('add.SCOPE_WRITE_LABEL')] _format: 'selectFromOptions'
], }
_exp: 'choice[1] for (index, choice) in state._data',
_format: 'selectFromOptions'
}; };
vm.form.save = payload => { vm.form.save = payload => {
Rest.setUrl(`${GetBasePath('users')}${$state.params.user_id}/authorized_tokens`); const postToken = _.has(payload, 'application') ?
return Rest.post(payload) user.postAuthorizedTokens({
id: $state.params.user_id,
payload
}) : token.request('post', { data: payload });
return postToken
.then(({ data }) => { .then(({ data }) => {
const refreshHTML = data.refresh_token ?
`<div class="TokenModal">
<div class="TokenModal-label">
${strings.get('add.REFRESH_TOKEN_LABEL')}
</div>
<div class="TokenModal-value">
${data.refresh_token}
</div>
</div>` : '';
Alert(strings.get('add.TOKEN_MODAL_HEADER'), ` Alert(strings.get('add.TOKEN_MODAL_HEADER'), `
<div class="TokenModal"> <div class="TokenModal">
<div class="TokenModal-label"> <div class="TokenModal-label">
@@ -63,14 +76,7 @@ function AddTokensController (
${data.token} ${data.token}
</div> </div>
</div> </div>
<div class="TokenModal"> ${refreshHTML}
<div class="TokenModal-label">
${strings.get('add.REFRESH_TOKEN_LABEL')}
</div>
<div class="TokenModal-value">
${data.refresh_token}
</div>
</div>
<div class="TokenModal"> <div class="TokenModal">
<div class="TokenModal-label"> <div class="TokenModal-label">
${strings.get('add.TOKEN_EXPIRES_LABEL')} ${strings.get('add.TOKEN_EXPIRES_LABEL')}
@@ -106,10 +112,8 @@ AddTokensController.$inject = [
'resolvedModels', 'resolvedModels',
'$state', '$state',
'TokensStrings', 'TokensStrings',
'Rest',
'Alert', 'Alert',
'Wait', 'Wait',
'GetBasePath',
'$filter', '$filter',
'ProcessErrors', 'ProcessErrors',
'$scope' '$scope'

View File

@@ -3,17 +3,21 @@ import AddController from './users-tokens-add.controller';
const addTemplate = require('~features/users/tokens/users-tokens-add.partial.html'); const addTemplate = require('~features/users/tokens/users-tokens-add.partial.html');
function TokensDetailResolve ($q, Application) { function TokensDetailResolve ($q, Application, Token, User) {
const promises = {}; const promises = {};
promises.application = new Application('options'); promises.application = new Application('options');
promises.token = new Token('options');
promises.user = new User('options');
return $q.all(promises); return $q.all(promises);
} }
TokensDetailResolve.$inject = [ TokensDetailResolve.$inject = [
'$q', '$q',
'ApplicationModel' 'ApplicationModel',
'TokenModel',
'UserModel'
]; ];
function isMeResolve ($rootScope, $stateParams, $state) { function isMeResolve ($rootScope, $stateParams, $state) {

View File

@@ -10,13 +10,15 @@ function ListTokensController (
Dataset, Dataset,
strings, strings,
ProcessErrors, ProcessErrors,
Rest,
GetBasePath, GetBasePath,
Prompt, Prompt,
Wait Wait,
models
) { ) {
const vm = this || {}; const vm = this || {};
const { token } = models;
vm.strings = strings; vm.strings = strings;
vm.activeId = $state.params.token_id; vm.activeId = $state.params.token_id;
@@ -48,8 +50,8 @@ function ListTokensController (
return undefined; return undefined;
}; };
vm.getLastUsed = token => { vm.getLastUsed = tokenToCheck => {
const lastUsed = _.get(token, 'last_used'); const lastUsed = _.get(tokenToCheck, 'last_used');
if (!lastUsed) { if (!lastUsed) {
return undefined; return undefined;
@@ -57,7 +59,7 @@ function ListTokensController (
let html = $filter('longDate')(lastUsed); let html = $filter('longDate')(lastUsed);
const { username, id } = _.get(token, 'summary_fields.last_used', {}); const { username, id } = _.get(tokenToCheck, 'summary_fields.last_used', {});
if (username && id) { if (username && id) {
html += ` ${strings.get('add.LAST_USED_LABEL')} <a href="/#/users/${id}">${$filter('sanitize')(username)}</a>`; html += ` ${strings.get('add.LAST_USED_LABEL')} <a href="/#/users/${id}">${$filter('sanitize')(username)}</a>`;
@@ -70,8 +72,7 @@ function ListTokensController (
const action = () => { const action = () => {
$('#prompt-modal').modal('hide'); $('#prompt-modal').modal('hide');
Wait('start'); Wait('start');
Rest.setUrl(`${GetBasePath('tokens')}${tok.id}`); token.request('delete', tok.id)
Rest.destroy()
.then(() => { .then(() => {
let reloadListStateParams = null; let reloadListStateParams = null;
@@ -89,14 +90,12 @@ function ListTokensController (
} else { } else {
$state.go('.', reloadListStateParams, { reload: true }); $state.go('.', reloadListStateParams, { reload: true });
} }
}) }).catch(({ data, status }) => {
.catch(({ data, status }) => {
ProcessErrors($scope, data, status, null, { ProcessErrors($scope, data, status, null, {
hdr: strings.get('error.HEADER'), hdr: strings.get('error.HEADER'),
msg: strings.get('error.CALL', { path: `${GetBasePath('tokens')}${tok.id}`, status }) msg: strings.get('error.CALL', { path: `${GetBasePath('tokens')}${tok.id}`, status })
}); });
}) }).finally(() => {
.finally(() => {
Wait('stop'); Wait('stop');
}); });
}; };
@@ -105,7 +104,9 @@ function ListTokensController (
Prompt({ Prompt({
hdr: strings.get('deleteResource.HEADER'), hdr: strings.get('deleteResource.HEADER'),
resourceName: strings.get('list.HEADER', tok.summary_fields.application.name), resourceName: _.has(tok, 'summary_fields.application.name') ?
strings.get('list.HEADER', tok.summary_fields.application.name) :
strings.get('list.PERSONAL_ACCESS_TOKEN'),
body: deleteModalBody, body: deleteModalBody,
action, action,
actionText: strings.get('add.DELETE_ACTION_LABEL') actionText: strings.get('add.DELETE_ACTION_LABEL')
@@ -120,10 +121,10 @@ ListTokensController.$inject = [
'Dataset', 'Dataset',
'TokensStrings', 'TokensStrings',
'ProcessErrors', 'ProcessErrors',
'Rest',
'GetBasePath', 'GetBasePath',
'Prompt', 'Prompt',
'Wait' 'Wait',
'resolvedModels'
]; ];
export default ListTokensController; export default ListTokensController;

View File

@@ -25,7 +25,10 @@
<at-row ng-repeat="token in tokens"> <at-row ng-repeat="token in tokens">
<div class="at-Row-items"> <div class="at-Row-items">
<at-row-item <at-row-item
header-value="{{ vm.strings.get('list.HEADER', token.summary_fields.application.name) }}"> header-value="{{ token.summary_fields.application.name ?
vm.strings.get('list.HEADER', token.summary_fields.application.name) :
vm.strings.get('list.PERSONAL_ACCESS_TOKEN')
}}">
</at-row-item> </at-row-item>
<at-row-item <at-row-item
label-value="{{:: vm.strings.get('list.ROW_ITEM_LABEL_DESCRIPTION') }}" label-value="{{:: vm.strings.get('list.ROW_ITEM_LABEL_DESCRIPTION') }}"

View File

@@ -4,6 +4,19 @@ import ListController from './users-tokens-list.controller';
const listTemplate = require('~features/users/tokens/users-tokens-list.partial.html'); const listTemplate = require('~features/users/tokens/users-tokens-list.partial.html');
function TokensListResolve ($q, Token) {
const promises = {};
promises.token = new Token('options');
return $q.all(promises);
}
TokensListResolve.$inject = [
'$q',
'TokenModel',
];
export default { export default {
url: '/tokens', url: '/tokens',
name: 'users.edit.tokens', name: 'users.edit.tokens',
@@ -32,6 +45,7 @@ export default {
} }
}, },
resolve: { resolve: {
resolvedModels: TokensListResolve,
Dataset: [ Dataset: [
'$stateParams', '$stateParams',
'Wait', 'Wait',

View File

@@ -0,0 +1,26 @@
let Base;
function setDependentResources () {
this.dependentResources = [];
}
function TokenModel (method, resource, config) {
Base.call(this, 'tokens');
this.Constructor = TokenModel;
this.setDependentResources = setDependentResources.bind(this);
return this.create(method, resource, config);
}
function TokenModelLoader (BaseModel) {
Base = BaseModel;
return TokenModel;
}
TokenModelLoader.$inject = [
'BaseModel',
];
export default TokenModelLoader;

View File

@@ -0,0 +1,40 @@
let Base;
let $http;
function postAuthorizedTokens (params) {
const req = {
method: 'POST',
url: `${this.path}${params.id}/authorized_tokens/`
};
if (params.payload) {
req.data = params.payload;
}
return $http(req);
}
function UserModel (method, resource, config) {
Base.call(this, 'users');
this.Constructor = UserModel;
this.postAuthorizedTokens = postAuthorizedTokens.bind(this);
this.model.launch = {};
return this.create(method, resource, config);
}
function UserModelLoader (BaseModel, _$http_) {
Base = BaseModel;
$http = _$http_;
return UserModel;
}
UserModelLoader.$inject = [
'BaseModel',
'$http'
];
export default UserModelLoader;

View File

@@ -22,11 +22,13 @@ import Project from '~models/Project';
import Schedule from '~models/Schedule'; import Schedule from '~models/Schedule';
import ProjectUpdate from '~models/ProjectUpdate'; import ProjectUpdate from '~models/ProjectUpdate';
import SystemJob from '~models/SystemJob'; import SystemJob from '~models/SystemJob';
import Token from '~models/Token';
import UnifiedJobTemplate from '~models/UnifiedJobTemplate'; import UnifiedJobTemplate from '~models/UnifiedJobTemplate';
import WorkflowJob from '~models/WorkflowJob'; import WorkflowJob from '~models/WorkflowJob';
import WorkflowJobTemplate from '~models/WorkflowJobTemplate'; import WorkflowJobTemplate from '~models/WorkflowJobTemplate';
import WorkflowJobTemplateNode from '~models/WorkflowJobTemplateNode'; import WorkflowJobTemplateNode from '~models/WorkflowJobTemplateNode';
import UnifiedJob from '~models/UnifiedJob'; import UnifiedJob from '~models/UnifiedJob';
import User from '~models/User';
import ModelsStrings from '~models/models.strings'; import ModelsStrings from '~models/models.strings';
@@ -59,10 +61,12 @@ angular
.service('UnifiedJobModel', UnifiedJob) .service('UnifiedJobModel', UnifiedJob)
.service('ProjectUpdateModel', ProjectUpdate) .service('ProjectUpdateModel', ProjectUpdate)
.service('SystemJobModel', SystemJob) .service('SystemJobModel', SystemJob)
.service('TokenModel', Token)
.service('UnifiedJobTemplateModel', UnifiedJobTemplate) .service('UnifiedJobTemplateModel', UnifiedJobTemplate)
.service('WorkflowJobModel', WorkflowJob) .service('WorkflowJobModel', WorkflowJob)
.service('WorkflowJobTemplateModel', WorkflowJobTemplate) .service('WorkflowJobTemplateModel', WorkflowJobTemplate)
.service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode) .service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode)
.service('UserModel', User)
.service('ModelsStrings', ModelsStrings); .service('ModelsStrings', ModelsStrings);
export default MODULE_NAME; export default MODULE_NAME;