feat(api tokens): validate title field when creating a new token
This commit is contained in:
parent
e47ad021a3
commit
021f92303d
|
@ -150,8 +150,10 @@
|
||||||
"60d": "60 Days",
|
"60d": "60 Days",
|
||||||
"90d": "90 Days",
|
"90d": "90 Days",
|
||||||
"permissionExplanation": "Permissions allow you to scope what an api token is allowed to do.",
|
"permissionExplanation": "Permissions allow you to scope what an api token is allowed to do.",
|
||||||
|
"titleRequired": "The title is required",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"title": "Title",
|
"title": "Title",
|
||||||
|
"titlePlaceholder": "Enter a title you will recognize later",
|
||||||
"expiresAt": "Expires at",
|
"expiresAt": "Expires at",
|
||||||
"permissions": "Permissions"
|
"permissions": "Permissions"
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ export interface IApiPermission {
|
||||||
|
|
||||||
export interface IApiToken extends IAbstract {
|
export interface IApiToken extends IAbstract {
|
||||||
id: number
|
id: number
|
||||||
|
title: string
|
||||||
token: string
|
token: string
|
||||||
permissions: IApiPermission
|
permissions: IApiPermission
|
||||||
expiresAt: Date
|
expiresAt: Date
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type {IApiToken} from '@/modelTypes/IApiToken'
|
||||||
|
|
||||||
export default class ApiTokenModel extends AbstractModel<IApiToken> {
|
export default class ApiTokenModel extends AbstractModel<IApiToken> {
|
||||||
id = 0
|
id = 0
|
||||||
|
title = ''
|
||||||
token = ''
|
token = ''
|
||||||
permissions = null
|
permissions = null
|
||||||
expiresAt: Date = null
|
expiresAt: Date = null
|
||||||
|
|
|
@ -16,6 +16,8 @@ const availableRoutes = ref(null)
|
||||||
const newToken = ref(new ApiTokenModel())
|
const newToken = ref(new ApiTokenModel())
|
||||||
const newTokenExpiry = ref<string | number>(30)
|
const newTokenExpiry = ref<string | number>(30)
|
||||||
const newTokenPermissions = ref({})
|
const newTokenPermissions = ref({})
|
||||||
|
const newTokenTitleValid = ref(true)
|
||||||
|
const apiTokenTitle = ref()
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
tokens.value = await service.getAll()
|
tokens.value = await service.getAll()
|
||||||
|
@ -38,12 +40,17 @@ function deleteToken() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createToken() {
|
async function createToken() {
|
||||||
|
if (!newTokenTitleValid.value) {
|
||||||
|
apiTokenTitle.value.focus()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const expiry = Number(newTokenExpiry.value)
|
const expiry = Number(newTokenExpiry.value)
|
||||||
if(!isNaN(expiry)) {
|
if (!isNaN(expiry)) {
|
||||||
// if it's a number, we assume it's the number of days in the future
|
// if it's a number, we assume it's the number of days in the future
|
||||||
newToken.value.expiresAt = new Date((new Date()) + expiry * MILLISECONDS_A_DAY)
|
newToken.value.expiresAt = new Date((new Date()) + expiry * MILLISECONDS_A_DAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
newToken.value.permissions = {}
|
newToken.value.permissions = {}
|
||||||
Object.entries(newTokenPermissions.value).forEach(([key, ps]) => {
|
Object.entries(newTokenPermissions.value).forEach(([key, ps]) => {
|
||||||
const all = Object.entries(ps)
|
const all = Object.entries(ps)
|
||||||
|
@ -54,7 +61,7 @@ async function createToken() {
|
||||||
newToken.value.permissions[key] = all
|
newToken.value.permissions[key] = all
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const token = await service.create(newToken.value)
|
const token = await service.create(newToken.value)
|
||||||
newToken.value = new ApiTokenModel()
|
newToken.value = new ApiTokenModel()
|
||||||
newTokenExpiry.value = 30
|
newTokenExpiry.value = 30
|
||||||
|
@ -113,19 +120,27 @@ async function createToken() {
|
||||||
<input
|
<input
|
||||||
class="input"
|
class="input"
|
||||||
id="apiTokenTitle"
|
id="apiTokenTitle"
|
||||||
|
ref="apiTokenTitle"
|
||||||
type="text"
|
type="text"
|
||||||
v-focus
|
v-focus
|
||||||
v-model="newToken.title"/>
|
:placeholder="$t('user.settings.apiTokens.attributes.titlePlaceholder')"
|
||||||
|
v-model="newToken.title"
|
||||||
|
@keyup="() => newTokenTitleValid = newToken.title !== ''"
|
||||||
|
@focusout="() => newTokenTitleValid = newToken.title !== ''"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="help is-danger" v-if="!newTokenTitleValid">
|
||||||
|
{{ $t('user.settings.apiTokens.titleRequired') }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Expiry -->
|
<!-- Expiry -->
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="apiTokenTitle">{{
|
<label class="label" for="apiTokenExpiry">
|
||||||
$t('user.settings.apiTokens.attributes.expiresAt')
|
{{ $t('user.settings.apiTokens.attributes.expiresAt') }}
|
||||||
}}</label>
|
</label>
|
||||||
<div class="control select">
|
<div class="control select">
|
||||||
<select class="select" v-model="newTokenExpiry">
|
<select class="select" v-model="newTokenExpiry" id="apiTokenExpiry">
|
||||||
<option value="30">{{ $t('user.settings.apiTokens.30d') }}</option>
|
<option value="30">{{ $t('user.settings.apiTokens.30d') }}</option>
|
||||||
<option value="60">{{ $t('user.settings.apiTokens.60d') }}</option>
|
<option value="60">{{ $t('user.settings.apiTokens.60d') }}</option>
|
||||||
<option value="90">{{ $t('user.settings.apiTokens.90d') }}</option>
|
<option value="90">{{ $t('user.settings.apiTokens.90d') }}</option>
|
||||||
|
@ -140,9 +155,9 @@ async function createToken() {
|
||||||
<p>{{ $t('user.settings.apiTokens.permissionExplanation') }}</p>
|
<p>{{ $t('user.settings.apiTokens.permissionExplanation') }}</p>
|
||||||
<div v-for="(routes, group) in availableRoutes" class="mb-2" :key="group">
|
<div v-for="(routes, group) in availableRoutes" class="mb-2" :key="group">
|
||||||
<strong>{{ group }}</strong><br/>
|
<strong>{{ group }}</strong><br/>
|
||||||
<fancycheckbox
|
<fancycheckbox
|
||||||
v-for="(paths, route) in routes"
|
v-for="(paths, route) in routes"
|
||||||
:key="group+'-'+route"
|
:key="group+'-'+route"
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
v-model="newTokenPermissions[group][route]"
|
v-model="newTokenPermissions[group][route]"
|
||||||
>
|
>
|
||||||
|
|
Reference in New Issue