mirror of
https://github.com/ansible/awx.git
synced 2026-05-09 10:27:37 -02:30
Merge pull request #2519 from mabashian/2505-application-token
Removes application requirement when creating token, fixes delete personal token
This commit is contained in:
@@ -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 }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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') }}"
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
26
awx/ui/client/lib/models/Token.js
Normal file
26
awx/ui/client/lib/models/Token.js
Normal 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;
|
||||||
40
awx/ui/client/lib/models/User.js
Normal file
40
awx/ui/client/lib/models/User.js
Normal 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;
|
||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user