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;
|
"permissions": string;
|
||||||
/**
|
/**
|
||||||
* Override rank
|
* Limit rank
|
||||||
*/
|
*/
|
||||||
"overrideRank": string;
|
"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;
|
"overrideRankDescription": string;
|
||||||
|
/**
|
||||||
|
* Rank
|
||||||
|
*/
|
||||||
|
"rank": string;
|
||||||
"_ranks": {
|
"_ranks": {
|
||||||
/**
|
/**
|
||||||
* Admin
|
* Admin
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,10 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
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 { DI } from '@/di-symbols.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
@ -46,6 +47,19 @@ export const meta = {
|
||||||
type: 'string',
|
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)
|
@Inject(DI.accessTokensRepository)
|
||||||
private accessTokensRepository: AccessTokensRepository,
|
private accessTokensRepository: AccessTokensRepository,
|
||||||
|
|
||||||
|
@Inject(DI.sharedAccessTokensRepository)
|
||||||
|
private readonly sharedAccessTokenRepository: SharedAccessTokensRepository,
|
||||||
|
|
||||||
|
private readonly userEntityService: UserEntityService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
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();
|
const tokens = await query.getMany();
|
||||||
|
|
||||||
return await Promise.all(tokens.map(token => ({
|
return await Promise.all(tokens.map(async token => {
|
||||||
id: token.id,
|
// TODO inline this table into a column w/ GIN index
|
||||||
name: token.name ?? token.app?.name,
|
const sharedTokens = await this.sharedAccessTokenRepository.find({
|
||||||
createdAt: this.idService.parse(token.id).date.toISOString(),
|
where: { accessTokenId: token.id },
|
||||||
lastUsedAt: token.lastUsedAt?.toISOString(),
|
relations: { grantee: true },
|
||||||
permission: token.app ? token.app.permission : token.permission,
|
});
|
||||||
})));
|
|
||||||
|
// 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 #key>{{ i18n.ts.lastUsedDate }}</template>
|
||||||
<template #value><MkTime :time="token.lastUsedAt" :mode="'detail'"/></template>
|
<template #value><MkTime :time="token.lastUsedAt" :mode="'detail'"/></template>
|
||||||
</MkKeyValue>
|
</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>
|
</div>
|
||||||
<MkFolder>
|
<MkFolder v-if="standardPerms(token.permissions).length > 0">
|
||||||
<template #label>{{ i18n.ts.permission }}</template>
|
<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>
|
<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>
|
</ul>
|
||||||
</MkFolder>
|
</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>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -50,7 +67,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
|
||||||
import FormPagination from '@/components/MkPagination.vue';
|
import FormPagination from '@/components/MkPagination.vue';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
@ -58,6 +74,7 @@ import { definePage } from '@/page.js';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
|
|
||||||
const list = ref<InstanceType<typeof FormPagination>>();
|
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 headerActions = computed(() => []);
|
||||||
|
|
||||||
const headerTabs = computed(() => []);
|
const headerTabs = computed(() => []);
|
||||||
|
|
|
||||||
|
|
@ -22670,7 +22670,7 @@ export type operations = {
|
||||||
/** @description OK (with results) */
|
/** @description OK (with results) */
|
||||||
200: {
|
200: {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': ({
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
id: string;
|
id: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|
@ -22679,7 +22679,10 @@ export type operations = {
|
||||||
/** Format: date-time */
|
/** Format: date-time */
|
||||||
lastUsedAt?: string;
|
lastUsedAt?: string;
|
||||||
permission: string[];
|
permission: string[];
|
||||||
}[];
|
grantees: components['schemas']['UserLite'][];
|
||||||
|
/** @enum {string|null} */
|
||||||
|
rank: 'admin' | 'mod' | 'user';
|
||||||
|
})[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Client error */
|
/** @description Client error */
|
||||||
|
|
|
||||||
|
|
@ -692,8 +692,9 @@ noSharedAccess: "You have not been granted shared access to any accounts"
|
||||||
expand: "Expand"
|
expand: "Expand"
|
||||||
collapse: "Collapse"
|
collapse: "Collapse"
|
||||||
permissions: "Permissions"
|
permissions: "Permissions"
|
||||||
overrideRank: "Override rank"
|
overrideRank: "Limit rank"
|
||||||
overrideRankDescription: "Overrides the user rank (admin, moderator, or user) for apps using this token."
|
overrideRankDescription: "Limits the user rank (admin, moderator, or user) for apps using this token."
|
||||||
|
rank: "Rank"
|
||||||
_ranks:
|
_ranks:
|
||||||
admin: "Admin"
|
admin: "Admin"
|
||||||
mod: "Moderator"
|
mod: "Moderator"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue