mirror of
https://github.com/MisskeyIO/misskey
synced 2024-11-27 14:28:49 +09:00
parent
fa7fd9ce25
commit
f5dfb64a52
@ -17,6 +17,7 @@
|
|||||||
### General
|
### General
|
||||||
- エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるように
|
- エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるように
|
||||||
- ロールが付与されているユーザーリストを非公開にできるように
|
- ロールが付与されているユーザーリストを非公開にできるように
|
||||||
|
- サーバーの負荷が非常に高いため、ユーザー統計表示機能を削除しました
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Fix: タブがバックグラウンドでもstreamが切断されないように
|
- Fix: タブがバックグラウンドでもstreamが切断されないように
|
||||||
|
@ -333,7 +333,6 @@ import * as ep___users_reportAbuse from './endpoints/users/report-abuse.js';
|
|||||||
import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by-username-and-host.js';
|
import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by-username-and-host.js';
|
||||||
import * as ep___users_search from './endpoints/users/search.js';
|
import * as ep___users_search from './endpoints/users/search.js';
|
||||||
import * as ep___users_show from './endpoints/users/show.js';
|
import * as ep___users_show from './endpoints/users/show.js';
|
||||||
import * as ep___users_stats from './endpoints/users/stats.js';
|
|
||||||
import * as ep___users_achievements from './endpoints/users/achievements.js';
|
import * as ep___users_achievements from './endpoints/users/achievements.js';
|
||||||
import * as ep___users_updateMemo from './endpoints/users/update-memo.js';
|
import * as ep___users_updateMemo from './endpoints/users/update-memo.js';
|
||||||
import * as ep___fetchRss from './endpoints/fetch-rss.js';
|
import * as ep___fetchRss from './endpoints/fetch-rss.js';
|
||||||
@ -674,7 +673,6 @@ const $users_reportAbuse: Provider = { provide: 'ep:users/report-abuse', useClas
|
|||||||
const $users_searchByUsernameAndHost: Provider = { provide: 'ep:users/search-by-username-and-host', useClass: ep___users_searchByUsernameAndHost.default };
|
const $users_searchByUsernameAndHost: Provider = { provide: 'ep:users/search-by-username-and-host', useClass: ep___users_searchByUsernameAndHost.default };
|
||||||
const $users_search: Provider = { provide: 'ep:users/search', useClass: ep___users_search.default };
|
const $users_search: Provider = { provide: 'ep:users/search', useClass: ep___users_search.default };
|
||||||
const $users_show: Provider = { provide: 'ep:users/show', useClass: ep___users_show.default };
|
const $users_show: Provider = { provide: 'ep:users/show', useClass: ep___users_show.default };
|
||||||
const $users_stats: Provider = { provide: 'ep:users/stats', useClass: ep___users_stats.default };
|
|
||||||
const $users_achievements: Provider = { provide: 'ep:users/achievements', useClass: ep___users_achievements.default };
|
const $users_achievements: Provider = { provide: 'ep:users/achievements', useClass: ep___users_achievements.default };
|
||||||
const $users_updateMemo: Provider = { provide: 'ep:users/update-memo', useClass: ep___users_updateMemo.default };
|
const $users_updateMemo: Provider = { provide: 'ep:users/update-memo', useClass: ep___users_updateMemo.default };
|
||||||
const $fetchRss: Provider = { provide: 'ep:fetch-rss', useClass: ep___fetchRss.default };
|
const $fetchRss: Provider = { provide: 'ep:fetch-rss', useClass: ep___fetchRss.default };
|
||||||
@ -1019,7 +1017,6 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||||||
$users_searchByUsernameAndHost,
|
$users_searchByUsernameAndHost,
|
||||||
$users_search,
|
$users_search,
|
||||||
$users_show,
|
$users_show,
|
||||||
$users_stats,
|
|
||||||
$users_achievements,
|
$users_achievements,
|
||||||
$users_updateMemo,
|
$users_updateMemo,
|
||||||
$fetchRss,
|
$fetchRss,
|
||||||
@ -1356,7 +1353,6 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||||||
$users_searchByUsernameAndHost,
|
$users_searchByUsernameAndHost,
|
||||||
$users_search,
|
$users_search,
|
||||||
$users_show,
|
$users_show,
|
||||||
$users_stats,
|
|
||||||
$users_achievements,
|
$users_achievements,
|
||||||
$users_updateMemo,
|
$users_updateMemo,
|
||||||
$fetchRss,
|
$fetchRss,
|
||||||
|
@ -333,7 +333,6 @@ import * as ep___users_reportAbuse from './endpoints/users/report-abuse.js';
|
|||||||
import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by-username-and-host.js';
|
import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by-username-and-host.js';
|
||||||
import * as ep___users_search from './endpoints/users/search.js';
|
import * as ep___users_search from './endpoints/users/search.js';
|
||||||
import * as ep___users_show from './endpoints/users/show.js';
|
import * as ep___users_show from './endpoints/users/show.js';
|
||||||
import * as ep___users_stats from './endpoints/users/stats.js';
|
|
||||||
import * as ep___users_achievements from './endpoints/users/achievements.js';
|
import * as ep___users_achievements from './endpoints/users/achievements.js';
|
||||||
import * as ep___users_updateMemo from './endpoints/users/update-memo.js';
|
import * as ep___users_updateMemo from './endpoints/users/update-memo.js';
|
||||||
import * as ep___fetchRss from './endpoints/fetch-rss.js';
|
import * as ep___fetchRss from './endpoints/fetch-rss.js';
|
||||||
@ -672,7 +671,6 @@ const eps = [
|
|||||||
['users/search-by-username-and-host', ep___users_searchByUsernameAndHost],
|
['users/search-by-username-and-host', ep___users_searchByUsernameAndHost],
|
||||||
['users/search', ep___users_search],
|
['users/search', ep___users_search],
|
||||||
['users/show', ep___users_show],
|
['users/show', ep___users_show],
|
||||||
['users/stats', ep___users_stats],
|
|
||||||
['users/achievements', ep___users_achievements],
|
['users/achievements', ep___users_achievements],
|
||||||
['users/update-memo', ep___users_updateMemo],
|
['users/update-memo', ep___users_updateMemo],
|
||||||
['fetch-rss', ep___fetchRss],
|
['fetch-rss', ep___fetchRss],
|
||||||
|
@ -1,228 +0,0 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
|
||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import type { UsersRepository, NotesRepository, FollowingsRepository, DriveFilesRepository, NoteReactionsRepository, PageLikesRepository, NoteFavoritesRepository, PollVotesRepository } from '@/models/index.js';
|
|
||||||
import { ApiError } from '../../error.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ['users'],
|
|
||||||
|
|
||||||
requireCredential: false,
|
|
||||||
|
|
||||||
description: 'Show statistics about a user.',
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
noSuchUser: {
|
|
||||||
message: 'No such user.',
|
|
||||||
code: 'NO_SUCH_USER',
|
|
||||||
id: '9e638e45-3b25-4ef7-8f95-07e8498f1819',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
res: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
properties: {
|
|
||||||
notesCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
repliesCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
renotesCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
repliedCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
renotedCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
pollVotesCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
pollVotedCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
localFollowingCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
remoteFollowingCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
localFollowersCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
remoteFollowersCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
followingCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
followersCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
sentReactionsCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
receivedReactionsCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
noteFavoritesCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
pageLikesCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
pageLikedCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
driveFilesCount: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
driveUsage: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
description: 'Drive usage in bytes',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
userId: { type: 'string', format: 'misskey:id' },
|
|
||||||
},
|
|
||||||
required: ['userId'],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
|
||||||
@Injectable()
|
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.usersRepository)
|
|
||||||
private usersRepository: UsersRepository,
|
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
|
||||||
private notesRepository: NotesRepository,
|
|
||||||
|
|
||||||
@Inject(DI.followingsRepository)
|
|
||||||
private followingsRepository: FollowingsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.driveFilesRepository)
|
|
||||||
private driveFilesRepository: DriveFilesRepository,
|
|
||||||
|
|
||||||
@Inject(DI.noteReactionsRepository)
|
|
||||||
private noteReactionsRepository: NoteReactionsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.pageLikesRepository)
|
|
||||||
private pageLikesRepository: PageLikesRepository,
|
|
||||||
|
|
||||||
@Inject(DI.noteFavoritesRepository)
|
|
||||||
private noteFavoritesRepository: NoteFavoritesRepository,
|
|
||||||
|
|
||||||
@Inject(DI.pollVotesRepository)
|
|
||||||
private pollVotesRepository: PollVotesRepository,
|
|
||||||
|
|
||||||
private driveFileEntityService: DriveFileEntityService,
|
|
||||||
) {
|
|
||||||
super(meta, paramDef, async (ps, me) => {
|
|
||||||
const user = await this.usersRepository.findOneBy({ id: ps.userId });
|
|
||||||
if (user == null) {
|
|
||||||
throw new ApiError(meta.errors.noSuchUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await awaitAll({
|
|
||||||
notesCount: this.notesRepository.createQueryBuilder('note')
|
|
||||||
.where('note.userId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
repliesCount: this.notesRepository.createQueryBuilder('note')
|
|
||||||
.where('note.userId = :userId', { userId: user.id })
|
|
||||||
.andWhere('note.replyId IS NOT NULL')
|
|
||||||
.getCount(),
|
|
||||||
renotesCount: this.notesRepository.createQueryBuilder('note')
|
|
||||||
.where('note.userId = :userId', { userId: user.id })
|
|
||||||
.andWhere('note.renoteId IS NOT NULL')
|
|
||||||
.getCount(),
|
|
||||||
repliedCount: this.notesRepository.createQueryBuilder('note')
|
|
||||||
.where('note.replyUserId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
renotedCount: this.notesRepository.createQueryBuilder('note')
|
|
||||||
.where('note.renoteUserId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
pollVotesCount: this.pollVotesRepository.createQueryBuilder('vote')
|
|
||||||
.where('vote.userId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
pollVotedCount: this.pollVotesRepository.createQueryBuilder('vote')
|
|
||||||
.innerJoin('vote.note', 'note')
|
|
||||||
.where('note.userId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
localFollowingCount: this.followingsRepository.createQueryBuilder('following')
|
|
||||||
.where('following.followerId = :userId', { userId: user.id })
|
|
||||||
.andWhere('following.followeeHost IS NULL')
|
|
||||||
.getCount(),
|
|
||||||
remoteFollowingCount: this.followingsRepository.createQueryBuilder('following')
|
|
||||||
.where('following.followerId = :userId', { userId: user.id })
|
|
||||||
.andWhere('following.followeeHost IS NOT NULL')
|
|
||||||
.getCount(),
|
|
||||||
localFollowersCount: this.followingsRepository.createQueryBuilder('following')
|
|
||||||
.where('following.followeeId = :userId', { userId: user.id })
|
|
||||||
.andWhere('following.followerHost IS NULL')
|
|
||||||
.getCount(),
|
|
||||||
remoteFollowersCount: this.followingsRepository.createQueryBuilder('following')
|
|
||||||
.where('following.followeeId = :userId', { userId: user.id })
|
|
||||||
.andWhere('following.followerHost IS NOT NULL')
|
|
||||||
.getCount(),
|
|
||||||
sentReactionsCount: this.noteReactionsRepository.createQueryBuilder('reaction')
|
|
||||||
.where('reaction.userId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
receivedReactionsCount: this.noteReactionsRepository.createQueryBuilder('reaction')
|
|
||||||
.innerJoin('reaction.note', 'note')
|
|
||||||
.where('note.userId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
noteFavoritesCount: this.noteFavoritesRepository.createQueryBuilder('favorite')
|
|
||||||
.where('favorite.userId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
pageLikesCount: this.pageLikesRepository.createQueryBuilder('like')
|
|
||||||
.where('like.userId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
pageLikedCount: this.pageLikesRepository.createQueryBuilder('like')
|
|
||||||
.innerJoin('like.page', 'page')
|
|
||||||
.where('page.userId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
driveFilesCount: this.driveFilesRepository.createQueryBuilder('file')
|
|
||||||
.where('file.userId = :userId', { userId: user.id })
|
|
||||||
.getCount(),
|
|
||||||
driveUsage: this.driveFileEntityService.calcDriveUsageOf(user),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
...result,
|
|
||||||
followingCount: result.localFollowingCount + result.remoteFollowingCount,
|
|
||||||
followersCount: result.localFollowersCount + result.remoteFollowersCount,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="_gaps_m">
|
|
||||||
<FormSection v-if="stats" first>
|
|
||||||
<template #label>{{ i18n.ts.statistics }}</template>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.notesCount }}</template>
|
|
||||||
<template #value>{{ number(stats.notesCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.repliesCount }}</template>
|
|
||||||
<template #value>{{ number(stats.repliesCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.renotesCount }}</template>
|
|
||||||
<template #value>{{ number(stats.renotesCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.repliedCount }}</template>
|
|
||||||
<template #value>{{ number(stats.repliedCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.renotedCount }}</template>
|
|
||||||
<template #value>{{ number(stats.renotedCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.pollVotesCount }}</template>
|
|
||||||
<template #value>{{ number(stats.pollVotesCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.pollVotedCount }}</template>
|
|
||||||
<template #value>{{ number(stats.pollVotedCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.sentReactionsCount }}</template>
|
|
||||||
<template #value>{{ number(stats.sentReactionsCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.receivedReactionsCount }}</template>
|
|
||||||
<template #value>{{ number(stats.receivedReactionsCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.noteFavoritesCount }}</template>
|
|
||||||
<template #value>{{ number(stats.noteFavoritesCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.followingCount }}</template>
|
|
||||||
<template #value>{{ number(stats.followingCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.followingCount }} ({{ i18n.ts.local }})</template>
|
|
||||||
<template #value>{{ number(stats.localFollowingCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.followingCount }} ({{ i18n.ts.remote }})</template>
|
|
||||||
<template #value>{{ number(stats.remoteFollowingCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.followersCount }}</template>
|
|
||||||
<template #value>{{ number(stats.followersCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.followersCount }} ({{ i18n.ts.local }})</template>
|
|
||||||
<template #value>{{ number(stats.localFollowersCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.followersCount }} ({{ i18n.ts.remote }})</template>
|
|
||||||
<template #value>{{ number(stats.remoteFollowersCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.pageLikesCount }}</template>
|
|
||||||
<template #value>{{ number(stats.pageLikesCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.pageLikedCount }}</template>
|
|
||||||
<template #value>{{ number(stats.pageLikedCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.driveFilesCount }}</template>
|
|
||||||
<template #value>{{ number(stats.driveFilesCount) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>{{ i18n.ts.driveUsage }}</template>
|
|
||||||
<template #value>{{ bytes(stats.driveUsage) }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
</FormSection>
|
|
||||||
|
|
||||||
<FormSection>
|
|
||||||
<template #label>{{ i18n.ts.other }}</template>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>emailVerified</template>
|
|
||||||
<template #value>{{ $i.emailVerified ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>twoFactorEnabled</template>
|
|
||||||
<template #value>{{ $i.twoFactorEnabled ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>securityKeys</template>
|
|
||||||
<template #value>{{ $i.securityKeys ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>usePasswordLessLogin</template>
|
|
||||||
<template #value>{{ $i.usePasswordLessLogin ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>isModerator</template>
|
|
||||||
<template #value>{{ $i.isModerator ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
<MkKeyValue oneline style="margin: 1em 0;">
|
|
||||||
<template #key>isAdmin</template>
|
|
||||||
<template #value>{{ $i.isAdmin ? i18n.ts.yes : i18n.ts.no }}</template>
|
|
||||||
</MkKeyValue>
|
|
||||||
</FormSection>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
import FormSection from '@/components/form/section.vue';
|
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
|
||||||
import * as os from '@/os';
|
|
||||||
import number from '@/filters/number';
|
|
||||||
import bytes from '@/filters/bytes';
|
|
||||||
import { $i } from '@/account';
|
|
||||||
import { i18n } from '@/i18n';
|
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
|
||||||
|
|
||||||
const stats = ref<any>({});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
os.api('users/stats', {
|
|
||||||
userId: $i!.id,
|
|
||||||
}).then(response => {
|
|
||||||
stats.value = response;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const headerActions = $computed(() => []);
|
|
||||||
|
|
||||||
const headerTabs = $computed(() => []);
|
|
||||||
|
|
||||||
definePageMetadata({
|
|
||||||
title: i18n.ts.accountInfo,
|
|
||||||
icon: 'ti ti-info-circle',
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -26,8 +26,6 @@
|
|||||||
<template #key>{{ i18n.ts.registeredDate }}</template>
|
<template #key>{{ i18n.ts.registeredDate }}</template>
|
||||||
<template #value><MkTime :time="$i.createdAt" mode="detail"/></template>
|
<template #value><MkTime :time="$i.createdAt" mode="detail"/></template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
|
|
||||||
<FormLink to="/settings/account-stats"><template #icon><i class="ti ti-info-circle"></i></template>{{ i18n.ts.statistics }}</FormLink>
|
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
@ -177,10 +177,6 @@ export const routes = [{
|
|||||||
path: '/accounts',
|
path: '/accounts',
|
||||||
name: 'profile',
|
name: 'profile',
|
||||||
component: page(() => import('./pages/settings/accounts.vue')),
|
component: page(() => import('./pages/settings/accounts.vue')),
|
||||||
}, {
|
|
||||||
path: '/account-stats',
|
|
||||||
name: 'other',
|
|
||||||
component: page(() => import('./pages/settings/account-stats.vue')),
|
|
||||||
}, {
|
}, {
|
||||||
path: '/other',
|
path: '/other',
|
||||||
name: 'other',
|
name: 'other',
|
||||||
|
@ -2147,10 +2147,6 @@ export type Endpoints = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
'users/stats': {
|
|
||||||
req: TODO;
|
|
||||||
res: TODO;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
declare namespace entities {
|
declare namespace entities {
|
||||||
|
@ -602,5 +602,4 @@ export type Endpoints = {
|
|||||||
$default: UserDetailed;
|
$default: UserDetailed;
|
||||||
};
|
};
|
||||||
}; };
|
}; };
|
||||||
'users/stats': { req: TODO; res: TODO; };
|
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user