show grantee and rank info in tokens list
This commit is contained in:
parent
fe53c16b23
commit
23e69eccbb
5 changed files with 86 additions and 18 deletions
8
locales/index.d.ts
vendored
8
locales/index.d.ts
vendored
|
|
@ -13512,13 +13512,17 @@ export interface Locale extends ILocale {
|
|||
*/
|
||||
"permissions": string;
|
||||
/**
|
||||
* Override rank
|
||||
* Limit rank
|
||||
*/
|
||||
"overrideRank": string;
|
||||
/**
|
||||
* Overrides the user rank (admin, moderator, or user) for apps using this token.
|
||||
* Limits the user rank (admin, moderator, or user) for apps using this token.
|
||||
*/
|
||||
"overrideRankDescription": string;
|
||||
/**
|
||||
* Rank
|
||||
*/
|
||||
"rank": string;
|
||||
"_ranks": {
|
||||
/**
|
||||
* Admin
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import type { AccessTokensRepository } from '@/models/_.js';
|
||||
import type { AccessTokensRepository, SharedAccessTokensRepository } from '@/models/_.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
|
@ -46,6 +47,19 @@ export const meta = {
|
|||
type: 'string',
|
||||
},
|
||||
},
|
||||
grantees: {
|
||||
type: 'array',
|
||||
optional: false,
|
||||
items: {
|
||||
ref: 'UserLite',
|
||||
},
|
||||
},
|
||||
rank: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: true,
|
||||
enum: ['admin', 'mod', 'user'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -71,6 +85,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
@Inject(DI.accessTokensRepository)
|
||||
private accessTokensRepository: AccessTokensRepository,
|
||||
|
||||
@Inject(DI.sharedAccessTokensRepository)
|
||||
private readonly sharedAccessTokenRepository: SharedAccessTokensRepository,
|
||||
|
||||
private readonly userEntityService: UserEntityService,
|
||||
private idService: IdService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
|
|
@ -88,13 +106,26 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
const tokens = await query.getMany();
|
||||
|
||||
return await Promise.all(tokens.map(token => ({
|
||||
id: token.id,
|
||||
name: token.name ?? token.app?.name,
|
||||
createdAt: this.idService.parse(token.id).date.toISOString(),
|
||||
lastUsedAt: token.lastUsedAt?.toISOString(),
|
||||
permission: token.app ? token.app.permission : token.permission,
|
||||
})));
|
||||
return await Promise.all(tokens.map(async token => {
|
||||
// TODO inline this table into a column w/ GIN index
|
||||
const sharedTokens = await this.sharedAccessTokenRepository.find({
|
||||
where: { accessTokenId: token.id },
|
||||
relations: { grantee: true },
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const grantees = await this.userEntityService.packMany(sharedTokens.map(t => t.grantee!), me);
|
||||
|
||||
return {
|
||||
id: token.id,
|
||||
name: token.name ?? token.app?.name,
|
||||
createdAt: this.idService.parse(token.id).date.toISOString(),
|
||||
lastUsedAt: token.lastUsedAt?.toISOString(),
|
||||
permission: token.app ? token.app.permission : token.permission,
|
||||
rank: token.rank,
|
||||
grantees,
|
||||
};
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,14 +32,31 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #key>{{ i18n.ts.lastUsedDate }}</template>
|
||||
<template #value><MkTime :time="token.lastUsedAt" :mode="'detail'"/></template>
|
||||
</MkKeyValue>
|
||||
<MkKeyValue v-if="token.rank" oneline>
|
||||
<template #key>{{ i18n.ts.rank }}</template>
|
||||
<template #value>{{ i18n.ts._ranks[token.rank] ?? token.rank }}</template>
|
||||
</MkKeyValue>
|
||||
</div>
|
||||
<MkFolder>
|
||||
<MkFolder v-if="standardPerms(token.permissions).length > 0">
|
||||
<template #label>{{ i18n.ts.permission }}</template>
|
||||
<template #suffix>{{ Object.keys(token.permission).length === 0 ? i18n.ts.none : Object.keys(token.permission).length }}</template>
|
||||
<template #suffix>{{ standardPerms(token.permissions).length }}</template>
|
||||
<ul>
|
||||
<li v-for="p in token.permission" :key="p">{{ i18n.ts._permissions[p] }}</li>
|
||||
<li v-for="p of standardPerms(token.permissions)" :key="p">{{ i18n.ts._permissions[p] }}</li>
|
||||
</ul>
|
||||
</MkFolder>
|
||||
<MkFolder v-if="adminPerms(token.permissions).length > 0">
|
||||
<template #label>{{ i18n.ts.adminPermission }}</template>
|
||||
<template #suffix>{{ adminPerms(token.permissions).length }}</template>
|
||||
<ul>
|
||||
<li v-for="p of adminPerms(token.permissions)" :key="p">{{ i18n.ts._permissions[p] }}</li>
|
||||
</ul>
|
||||
</MkFolder>
|
||||
<MkFolder v-if="token.grantees.length > 0">
|
||||
<template #label>{{ i18n.ts.sharedAccess }}</template>
|
||||
<template #suffix>{{ token.grantees.length }}</template>
|
||||
|
||||
<MkUserCardMini v-for="grantee of token.grantees" :key="grantee.id" :user="grantee" :withChart="false"/>
|
||||
</MkFolder>
|
||||
</div>
|
||||
</MkFolder>
|
||||
</div>
|
||||
|
|
@ -50,7 +67,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import FormPagination from '@/components/MkPagination.vue';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
@ -58,6 +74,7 @@ import { definePage } from '@/page.js';
|
|||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||
|
||||
const list = ref<InstanceType<typeof FormPagination>>();
|
||||
|
||||
|
|
@ -76,6 +93,18 @@ function revoke(token) {
|
|||
});
|
||||
}
|
||||
|
||||
function isAdmin(perm: string): boolean {
|
||||
return perm.startsWith('read:admin') || perm.startsWith('write:admin');
|
||||
}
|
||||
|
||||
function standardPerms(perms: string[]): string[] {
|
||||
return perms.filter(perm => !isAdmin(perm));
|
||||
}
|
||||
|
||||
function adminPerms(perms: string[]): string[] {
|
||||
return perms.filter(perm => isAdmin(perm));
|
||||
}
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = computed(() => []);
|
||||
|
|
|
|||
|
|
@ -22670,7 +22670,7 @@ export type operations = {
|
|||
/** @description OK (with results) */
|
||||
200: {
|
||||
content: {
|
||||
'application/json': {
|
||||
'application/json': ({
|
||||
/** Format: misskey:id */
|
||||
id: string;
|
||||
name?: string;
|
||||
|
|
@ -22679,7 +22679,10 @@ export type operations = {
|
|||
/** Format: date-time */
|
||||
lastUsedAt?: string;
|
||||
permission: string[];
|
||||
}[];
|
||||
grantees: components['schemas']['UserLite'][];
|
||||
/** @enum {string|null} */
|
||||
rank: 'admin' | 'mod' | 'user';
|
||||
})[];
|
||||
};
|
||||
};
|
||||
/** @description Client error */
|
||||
|
|
|
|||
|
|
@ -692,8 +692,9 @@ noSharedAccess: "You have not been granted shared access to any accounts"
|
|||
expand: "Expand"
|
||||
collapse: "Collapse"
|
||||
permissions: "Permissions"
|
||||
overrideRank: "Override rank"
|
||||
overrideRankDescription: "Overrides the user rank (admin, moderator, or user) for apps using this token."
|
||||
overrideRank: "Limit rank"
|
||||
overrideRankDescription: "Limits the user rank (admin, moderator, or user) for apps using this token."
|
||||
rank: "Rank"
|
||||
_ranks:
|
||||
admin: "Admin"
|
||||
mod: "Moderator"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue