Added a Manage tokens tab to the user panel
This commit is contained in:
parent
23268ded75
commit
05d2785ec6
11 changed files with 332 additions and 22 deletions
|
@ -1,6 +1,6 @@
|
||||||
#user
|
#user
|
||||||
width: 100%
|
width: 100%
|
||||||
max-width: 35em
|
max-width: 45em
|
||||||
nav.text-nav
|
nav.text-nav
|
||||||
margin-bottom: 1.5em
|
margin-bottom: 1.5em
|
||||||
|
|
||||||
|
@ -37,6 +37,24 @@
|
||||||
height: 1px
|
height: 1px
|
||||||
clear: both
|
clear: both
|
||||||
|
|
||||||
|
#user-tokens
|
||||||
|
.token-flex-container
|
||||||
|
width: 100%
|
||||||
|
display: flex;
|
||||||
|
flex-direction column;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
|
||||||
|
.token-flex-row
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-top: 0.25em;
|
||||||
|
padding-bottom: 0.25em;
|
||||||
|
border-bottom: black solid 1px;
|
||||||
|
|
||||||
|
form
|
||||||
|
width: auto;
|
||||||
|
|
||||||
#user-delete form
|
#user-delete form
|
||||||
width: 100%
|
width: 100%
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
--><% if (ctx.canEditAnything) { %><!--
|
--><% if (ctx.canEditAnything) { %><!--
|
||||||
--><li data-name='edit'><a href='<%- ctx.formatClientLink('user', ctx.user.name, 'edit') %>'>Account settings</a></li><!--
|
--><li data-name='edit'><a href='<%- ctx.formatClientLink('user', ctx.user.name, 'edit') %>'>Account settings</a></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
|
--><% if (ctx.canListTokens) { %><!--
|
||||||
|
--><li data-name='list-tokens'><a href='<%- ctx.formatClientLink('user', ctx.user.name, 'list-tokens') %>'>Manage tokens</a></li><!--
|
||||||
|
--><% } %><!--
|
||||||
--><% if (ctx.canDelete) { %><!--
|
--><% if (ctx.canDelete) { %><!--
|
||||||
--><li data-name='delete'><a href='<%- ctx.formatClientLink('user', ctx.user.name, 'delete') %>'>Account deletion</a></li><!--
|
--><li data-name='delete'><a href='<%- ctx.formatClientLink('user', ctx.user.name, 'delete') %>'>Account deletion</a></li><!--
|
||||||
--><% } %><!--
|
--><% } %><!--
|
||||||
|
|
29
client/html/user_tokens.tpl
Normal file
29
client/html/user_tokens.tpl
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<div id='user-tokens'>
|
||||||
|
<div class='messages'></div>
|
||||||
|
<% if (ctx.tokens.length > 0) { %>
|
||||||
|
<div class="token-flex-container">
|
||||||
|
<div class="token-flex-row">
|
||||||
|
<div>Token</div>
|
||||||
|
<div>Actions</div>
|
||||||
|
</div>
|
||||||
|
<% _.each(ctx.tokens, function(token, index) { %>
|
||||||
|
<div class="token-flex-row">
|
||||||
|
<div><%= token.token %></div>
|
||||||
|
<div>
|
||||||
|
<form id='token<%= index %>'>
|
||||||
|
<input type='hidden' name='token' value='<%= token.token %>'/>
|
||||||
|
<input type='submit' value='Delete token'/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% }); %>
|
||||||
|
</div>
|
||||||
|
<% } else { %>
|
||||||
|
<h2>No Registered Tokens</h2>
|
||||||
|
<% } %>
|
||||||
|
<form id='create-token-form'>
|
||||||
|
<div class='buttons'>
|
||||||
|
<input type='submit' value='Create token'/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -120,7 +120,7 @@ class Api extends events.EventTarget {
|
||||||
|
|
||||||
create_token(userName, options) {
|
create_token(userName, options) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.post('/user-token', {})
|
this.post('/user-token/' + userName, {})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
cookies.set(
|
cookies.set(
|
||||||
'auth',
|
'auth',
|
||||||
|
@ -137,7 +137,7 @@ class Api extends events.EventTarget {
|
||||||
|
|
||||||
delete_token(userName, userToken) {
|
delete_token(userName, userToken) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.delete('/user-token/' + userToken, {})
|
this.delete('/user-token/' + userName + '/' + userToken, {})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const options = {};
|
const options = {};
|
||||||
cookies.set(
|
cookies.set(
|
||||||
|
|
|
@ -7,6 +7,7 @@ const misc = require('../util/misc.js');
|
||||||
const config = require('../config.js');
|
const config = require('../config.js');
|
||||||
const views = require('../util/views.js');
|
const views = require('../util/views.js');
|
||||||
const User = require('../models/user.js');
|
const User = require('../models/user.js');
|
||||||
|
const UserToken = require('../models/user_token.js');
|
||||||
const topNavigation = require('../models/top_navigation.js');
|
const topNavigation = require('../models/top_navigation.js');
|
||||||
const UserView = require('../views/user_view.js');
|
const UserView = require('../views/user_view.js');
|
||||||
const EmptyView = require('../views/empty_view.js');
|
const EmptyView = require('../views/empty_view.js');
|
||||||
|
@ -21,8 +22,11 @@ class UserController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._successMessages = [];
|
||||||
|
this._errorMessages = [];
|
||||||
|
|
||||||
topNavigation.setTitle('User ' + userName);
|
topNavigation.setTitle('User ' + userName);
|
||||||
User.get(userName).then(user => {
|
User.get(userName).then(async user => {
|
||||||
const isLoggedIn = api.isLoggedIn(user);
|
const isLoggedIn = api.isLoggedIn(user);
|
||||||
const infix = isLoggedIn ? 'self' : 'any';
|
const infix = isLoggedIn ? 'self' : 'any';
|
||||||
|
|
||||||
|
@ -48,6 +52,17 @@ class UserController {
|
||||||
} else {
|
} else {
|
||||||
topNavigation.activate('users');
|
topNavigation.activate('users');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let userTokens = [];
|
||||||
|
if (section === 'list-tokens') {
|
||||||
|
userTokens = await UserToken.get(userName)
|
||||||
|
.then(response => {
|
||||||
|
return response;
|
||||||
|
}, error => {
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this._view = new UserView({
|
this._view = new UserView({
|
||||||
user: user,
|
user: user,
|
||||||
section: section,
|
section: section,
|
||||||
|
@ -58,18 +73,50 @@ class UserController {
|
||||||
canEditRank: api.hasPrivilege(`users:edit:${infix}:rank`),
|
canEditRank: api.hasPrivilege(`users:edit:${infix}:rank`),
|
||||||
canEditAvatar: api.hasPrivilege(`users:edit:${infix}:avatar`),
|
canEditAvatar: api.hasPrivilege(`users:edit:${infix}:avatar`),
|
||||||
canEditAnything: api.hasPrivilege(`users:edit:${infix}`),
|
canEditAnything: api.hasPrivilege(`users:edit:${infix}`),
|
||||||
|
canListTokens: api.hasPrivilege(`userToken:list:${infix}`),
|
||||||
|
canCreateToken: api.hasPrivilege(`userToken:create:${infix}`),
|
||||||
|
canEditToken: api.hasPrivilege(`userToken:edit:${infix}`),
|
||||||
|
canDeleteToken: api.hasPrivilege(`userToken:delete:${infix}`),
|
||||||
canDelete: api.hasPrivilege(`users:delete:${infix}`),
|
canDelete: api.hasPrivilege(`users:delete:${infix}`),
|
||||||
ranks: ranks,
|
ranks: ranks,
|
||||||
|
tokens: userTokens,
|
||||||
});
|
});
|
||||||
this._view.addEventListener('change', e => this._evtChange(e));
|
this._view.addEventListener('change', e => this._evtChange(e));
|
||||||
this._view.addEventListener('submit', e => this._evtUpdate(e));
|
this._view.addEventListener('submit', e => this._evtUpdate(e));
|
||||||
this._view.addEventListener('delete', e => this._evtDelete(e));
|
this._view.addEventListener('delete', e => this._evtDelete(e));
|
||||||
|
this._view.addEventListener('create-token', e => this._evtCreateToken(e));
|
||||||
|
this._view.addEventListener('delete-token', e => this._evtDeleteToken(e));
|
||||||
|
|
||||||
|
for (let i = 0; i < this._successMessages.length; i++) {
|
||||||
|
this.showSuccess(this._successMessages[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < this._errorMessages.length; i++) {
|
||||||
|
this.showError(this._errorMessages[i]);
|
||||||
|
}
|
||||||
|
|
||||||
}, error => {
|
}, error => {
|
||||||
this._view = new EmptyView();
|
this._view = new EmptyView();
|
||||||
this._view.showError(error.message);
|
this._view.showError(error.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showSuccess(message) {
|
||||||
|
if (typeof this._view === 'undefined') {
|
||||||
|
this._successMessages.push(message)
|
||||||
|
} else {
|
||||||
|
this._view.showSuccess(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showError(message) {
|
||||||
|
if (typeof this._view === 'undefined') {
|
||||||
|
this._errorMessages.push(message)
|
||||||
|
} else {
|
||||||
|
this._view.showError(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_evtChange(e) {
|
_evtChange(e) {
|
||||||
misc.enableExitConfirmation();
|
misc.enableExitConfirmation();
|
||||||
}
|
}
|
||||||
|
@ -148,6 +195,32 @@ class UserController {
|
||||||
this._view.enableForm();
|
this._view.enableForm();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_evtCreateToken(e) {
|
||||||
|
this._view.clearMessages();
|
||||||
|
this._view.disableForm();
|
||||||
|
UserToken.create(e.detail.user.name)
|
||||||
|
.then(response => {
|
||||||
|
const ctx = router.show(uri.formatClientLink('user', e.detail.user.name, 'list-tokens'));
|
||||||
|
ctx.controller.showSuccess('Token ' + response.token + ' created.');
|
||||||
|
}, error => {
|
||||||
|
this._view.showError(error.message);
|
||||||
|
this._view.enableForm();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_evtDeleteToken(e) {
|
||||||
|
this._view.clearMessages();
|
||||||
|
this._view.disableForm();
|
||||||
|
e.detail.userToken.delete(e.detail.user.name)
|
||||||
|
.then(() => {
|
||||||
|
const ctx = router.show(uri.formatClientLink('user', e.detail.user.name, 'list-tokens'));
|
||||||
|
ctx.controller.showSuccess('Token ' + e.detail.userToken.token + ' deleted.');
|
||||||
|
}, error => {
|
||||||
|
this._view.showError(error.message);
|
||||||
|
this._view.enableForm();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = router => {
|
module.exports = router => {
|
||||||
|
@ -157,6 +230,9 @@ module.exports = router => {
|
||||||
router.enter(['user', ':name', 'edit'], (ctx, next) => {
|
router.enter(['user', ':name', 'edit'], (ctx, next) => {
|
||||||
ctx.controller = new UserController(ctx, 'edit');
|
ctx.controller = new UserController(ctx, 'edit');
|
||||||
});
|
});
|
||||||
|
router.enter(['user', ':name', 'list-tokens'], (ctx, next) => {
|
||||||
|
ctx.controller = new UserController(ctx, 'list-tokens');
|
||||||
|
});
|
||||||
router.enter(['user', ':name', 'delete'], (ctx, next) => {
|
router.enter(['user', ':name', 'delete'], (ctx, next) => {
|
||||||
ctx.controller = new UserController(ctx, 'delete');
|
ctx.controller = new UserController(ctx, 'delete');
|
||||||
});
|
});
|
||||||
|
|
76
client/js/models/user_token.js
Normal file
76
client/js/models/user_token.js
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const api = require('../api.js');
|
||||||
|
const uri = require('../util/uri.js');
|
||||||
|
const events = require('../events.js');
|
||||||
|
|
||||||
|
class UserToken extends events.EventTarget {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this._orig = {};
|
||||||
|
this._updateFromResponse({});
|
||||||
|
}
|
||||||
|
|
||||||
|
get token() { return this._token; }
|
||||||
|
get enabled() { return this._enabled; }
|
||||||
|
get version() { return this._version; }
|
||||||
|
get creation_time() { return this._creation_time; }
|
||||||
|
|
||||||
|
static fromResponse(response) {
|
||||||
|
if (typeof response.results !== 'undefined') {
|
||||||
|
let token_list = [];
|
||||||
|
for (let i = 0; i < response.results.length; i++) {
|
||||||
|
const token = new UserToken();
|
||||||
|
token._updateFromResponse(response.results[i]);
|
||||||
|
token_list.push(token)
|
||||||
|
}
|
||||||
|
return token_list;
|
||||||
|
} else {
|
||||||
|
const ret = new UserToken();
|
||||||
|
ret._updateFromResponse(response);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get(userName) {
|
||||||
|
return api.get(uri.formatApiLink('user-tokens', userName))
|
||||||
|
.then(response => {
|
||||||
|
return Promise.resolve(UserToken.fromResponse(response));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(userName) {
|
||||||
|
return api.post(uri.formatApiLink('user-token', userName))
|
||||||
|
.then(response => {
|
||||||
|
return Promise.resolve(UserToken.fromResponse(response))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(userName) {
|
||||||
|
return api.delete(
|
||||||
|
uri.formatApiLink('user-token', userName, this._orig._token),
|
||||||
|
{version: this._version})
|
||||||
|
.then(response => {
|
||||||
|
this.dispatchEvent(new CustomEvent('delete', {
|
||||||
|
detail: {
|
||||||
|
userToken: this,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateFromResponse(response) {
|
||||||
|
const map = {
|
||||||
|
_token: response.token,
|
||||||
|
_enabled: response.enabled,
|
||||||
|
_version: response.version,
|
||||||
|
_creation_time: response.creationTime,
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(this, map);
|
||||||
|
Object.assign(this._orig, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = UserToken;
|
86
client/js/views/user_tokens_view.js
Normal file
86
client/js/views/user_tokens_view.js
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const events = require('../events.js');
|
||||||
|
const views = require('../util/views.js');
|
||||||
|
|
||||||
|
const template = views.getTemplate('user-tokens');
|
||||||
|
|
||||||
|
class UserTokenView extends events.EventTarget {
|
||||||
|
constructor(ctx) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._user = ctx.user;
|
||||||
|
this._tokens = ctx.tokens;
|
||||||
|
this._hostNode = ctx.hostNode;
|
||||||
|
this._tokenFormNodes = [];
|
||||||
|
views.replaceContent(this._hostNode, template(ctx));
|
||||||
|
views.decorateValidator(this._formNode);
|
||||||
|
|
||||||
|
this._formNode.addEventListener('submit', e => this._evtSubmit(e));
|
||||||
|
|
||||||
|
this._decorateTokenForms()
|
||||||
|
}
|
||||||
|
|
||||||
|
_decorateTokenForms() {
|
||||||
|
for (let i = 0; i < this._tokens.length; i++) {
|
||||||
|
let formNode = this._hostNode.querySelector('#token' + i);
|
||||||
|
views.decorateValidator(formNode);
|
||||||
|
formNode.addEventListener('submit', e => this._evtDelete(e));
|
||||||
|
this._tokenFormNodes.push(formNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMessages() {
|
||||||
|
views.clearMessages(this._hostNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
showSuccess(message) {
|
||||||
|
views.showSuccess(this._hostNode, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
showError(message) {
|
||||||
|
views.showError(this._hostNode, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
enableForm() {
|
||||||
|
views.enableForm(this._formNode);
|
||||||
|
for (let i = 0; i < this._tokenFormNodes.length; i++) {
|
||||||
|
let formNode = this._tokenFormNodes[i];
|
||||||
|
views.enableForm(formNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disableForm() {
|
||||||
|
views.disableForm(this._formNode);
|
||||||
|
for (let i = 0; i < this._tokenFormNodes.length; i++) {
|
||||||
|
let formNode = this._tokenFormNodes[i];
|
||||||
|
views.disableForm(formNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_evtDelete(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const userToken = this._tokens[parseInt(e.target.id.replace('token', ''))];
|
||||||
|
this.dispatchEvent(new CustomEvent('delete', {
|
||||||
|
detail: {
|
||||||
|
user: this._user,
|
||||||
|
userToken: userToken,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
_evtSubmit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.dispatchEvent(new CustomEvent('submit', {
|
||||||
|
detail: {
|
||||||
|
user: this._user
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
get _formNode() {
|
||||||
|
return this._hostNode.querySelector('#create-token-form');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = UserTokenView;
|
|
@ -3,6 +3,7 @@
|
||||||
const events = require('../events.js');
|
const events = require('../events.js');
|
||||||
const views = require('../util/views.js');
|
const views = require('../util/views.js');
|
||||||
const UserDeleteView = require('./user_delete_view.js');
|
const UserDeleteView = require('./user_delete_view.js');
|
||||||
|
const UserTokensView = require('./user_tokens_view.js');
|
||||||
const UserSummaryView = require('./user_summary_view.js');
|
const UserSummaryView = require('./user_summary_view.js');
|
||||||
const UserEditView = require('./user_edit_view.js');
|
const UserEditView = require('./user_edit_view.js');
|
||||||
const EmptyView = require('../views/empty_view.js');
|
const EmptyView = require('../views/empty_view.js');
|
||||||
|
@ -42,7 +43,16 @@ class UserView extends events.EventTarget {
|
||||||
this._view = new UserEditView(ctx);
|
this._view = new UserEditView(ctx);
|
||||||
events.proxyEvent(this._view, this, 'submit');
|
events.proxyEvent(this._view, this, 'submit');
|
||||||
}
|
}
|
||||||
|
} else if (ctx.section == 'list-tokens') {
|
||||||
|
if (!this._ctx.canListTokens) {
|
||||||
|
this._view = new EmptyView();
|
||||||
|
this._view.showError(
|
||||||
|
'You don\'t have privileges to view user tokens.');
|
||||||
|
} else {
|
||||||
|
this._view = new UserTokensView(ctx);
|
||||||
|
events.proxyEvent(this._view, this, 'delete', 'delete-token');
|
||||||
|
events.proxyEvent(this._view, this, 'submit', 'create-token');
|
||||||
|
}
|
||||||
} else if (ctx.section == 'delete') {
|
} else if (ctx.section == 'delete') {
|
||||||
if (!this._ctx.canDelete) {
|
if (!this._ctx.canDelete) {
|
||||||
this._view = new EmptyView();
|
this._view = new EmptyView();
|
||||||
|
|
|
@ -86,10 +86,14 @@ privileges:
|
||||||
'users:delete:any': administrator
|
'users:delete:any': administrator
|
||||||
'users:delete:self': regular
|
'users:delete:self': regular
|
||||||
|
|
||||||
'user_token:list': regular
|
'user_token:list:any': administrator
|
||||||
'user_token:create': regular
|
'user_token:list:self': regular
|
||||||
'user_token:edit': regular
|
'user_token:create:any': administrator
|
||||||
'user_token:delete': regular
|
'user_token:create:self': regular
|
||||||
|
'user_token:edit:any': administrator
|
||||||
|
'user_token:edit:self': regular
|
||||||
|
'user_token:delete:any': administrator
|
||||||
|
'user_token:delete:self': regular
|
||||||
|
|
||||||
'posts:create:anonymous': regular
|
'posts:create:anonymous': regular
|
||||||
'posts:create:identified': regular
|
'posts:create:identified': regular
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from szurubooru import model, rest
|
from szurubooru import model, rest
|
||||||
from szurubooru.func import auth, user_tokens, serialization, versions
|
from szurubooru.func import auth, users, user_tokens, serialization, versions
|
||||||
|
|
||||||
|
|
||||||
def _serialize(
|
def _serialize(
|
||||||
|
@ -12,34 +12,42 @@ def _serialize(
|
||||||
options=serialization.get_serialization_options(ctx))
|
options=serialization.get_serialization_options(ctx))
|
||||||
|
|
||||||
|
|
||||||
@rest.routes.get('/user-tokens/?')
|
@rest.routes.get('/user-tokens/(?P<user_name>[^/]+)/?')
|
||||||
def get_user_tokens(ctx: rest.Context, _params: Dict[str, str] = {}) -> rest.Response:
|
def get_user_tokens(ctx: rest.Context, params: Dict[str, str] = {}) -> rest.Response:
|
||||||
auth.verify_privilege(ctx.user, 'user_token:list')
|
user = users.get_user_by_name(params['user_name'])
|
||||||
|
infix = 'self' if ctx.user.user_id == user.user_id else 'any'
|
||||||
|
auth.verify_privilege(ctx.user, 'user_token:list:%s' % infix)
|
||||||
user_token_list = user_tokens.get_user_tokens(ctx.user)
|
user_token_list = user_tokens.get_user_tokens(ctx.user)
|
||||||
return {
|
return {
|
||||||
"results": [_serialize(ctx, token) for token in user_token_list]
|
"results": [_serialize(ctx, token) for token in user_token_list]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@rest.routes.post('/user-token/?')
|
@rest.routes.post('/user-token/(?P<user_name>[^/]+)/?')
|
||||||
def create_user_token(ctx: rest.Context, _params: Dict[str, str] = {}) -> rest.Response:
|
def create_user_token(ctx: rest.Context, params: Dict[str, str] = {}) -> rest.Response:
|
||||||
auth.verify_privilege(ctx.user, 'user_token:create')
|
user = users.get_user_by_name(params['user_name'])
|
||||||
|
infix = 'self' if ctx.user.user_id == user.user_id else 'any'
|
||||||
|
auth.verify_privilege(ctx.user, 'user_token:create:%s' % infix)
|
||||||
user_token = user_tokens.create_user_token(ctx.user)
|
user_token = user_tokens.create_user_token(ctx.user)
|
||||||
return _serialize(ctx, user_token)
|
return _serialize(ctx, user_token)
|
||||||
|
|
||||||
|
|
||||||
@rest.routes.put('/user-token/(?P<user_token>[^/]+)/?')
|
@rest.routes.put('/user-token/(?P<user_name>[^/]+)/(?P<user_token>[^/]+)/?')
|
||||||
def edit_user_token(ctx: rest.Context, _params: Dict[str, str] = {}) -> rest.Response:
|
def edit_user_token(ctx: rest.Context, params: Dict[str, str] = {}) -> rest.Response:
|
||||||
auth.verify_privilege(ctx.user, 'user_token:edit')
|
user = users.get_user_by_name(params['user_name'])
|
||||||
|
infix = 'self' if ctx.user.user_id == user.user_id else 'any'
|
||||||
|
auth.verify_privilege(ctx.user, 'user_token:edit:%s' % infix)
|
||||||
user_token = user_tokens.get_user_token_by_user_and_token(ctx.user, params['user_token'])
|
user_token = user_tokens.get_user_token_by_user_and_token(ctx.user, params['user_token'])
|
||||||
versions.verify_version(user_token, ctx)
|
versions.verify_version(user_token, ctx)
|
||||||
versions.bump_version(user_token)
|
versions.bump_version(user_token)
|
||||||
return _serialize(ctx, user_token)
|
return _serialize(ctx, user_token)
|
||||||
|
|
||||||
|
|
||||||
@rest.routes.delete('/user-token/(?P<user_token>[^/]+)/?')
|
@rest.routes.delete('/user-token/(?P<user_name>[^/]+)/(?P<user_token>[^/]+)/?')
|
||||||
def delete_user_token(ctx: rest.Context, params: Dict[str, str]) -> rest.Response:
|
def delete_user_token(ctx: rest.Context, params: Dict[str, str]) -> rest.Response:
|
||||||
auth.verify_privilege(ctx.user, 'user_token:delete')
|
user = users.get_user_by_name(params['user_name'])
|
||||||
|
infix = 'self' if ctx.user.user_id == user.user_id else 'any'
|
||||||
|
auth.verify_privilege(ctx.user, 'user_token:delete:%s' % infix)
|
||||||
user_token = user_tokens.get_user_token_by_user_and_token(ctx.user, params['user_token'])
|
user_token = user_tokens.get_user_token_by_user_and_token(ctx.user, params['user_token'])
|
||||||
if user_token is not None:
|
if user_token is not None:
|
||||||
ctx.session.delete(user_token)
|
ctx.session.delete(user_token)
|
||||||
|
|
|
@ -62,7 +62,7 @@ def get_user_token_by_user_and_token(user: model.User, token: str) -> model.User
|
||||||
def get_user_tokens(user: model.User) -> List[model.UserToken]:
|
def get_user_tokens(user: model.User) -> List[model.UserToken]:
|
||||||
assert user
|
assert user
|
||||||
return (db.session.query(model.UserToken)
|
return (db.session.query(model.UserToken)
|
||||||
.filter(sa.func.lower(model.UserToken.user_id) == sa.func.lower(user.user_id))
|
.filter(model.UserToken.user_id == user.user_id)
|
||||||
.all())
|
.all())
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue