色々fix
This commit is contained in:
parent
805280874b
commit
592c6e60a9
11 changed files with 388 additions and 6 deletions
|
|
@ -330,6 +330,7 @@ import * as ep___users_following from './endpoints/users/following.js';
|
|||
import * as ep___users_gallery_posts from './endpoints/users/gallery/posts.js';
|
||||
import * as ep___users_getFrequentlyRepliedUsers from './endpoints/users/get-frequently-replied-users.js';
|
||||
import * as ep___users_featuredNotes from './endpoints/users/featured-notes.js';
|
||||
import * as ep___users_user_stats from './endpoints/users/stats.js';
|
||||
import * as ep___users_lists_create from './endpoints/users/lists/create.js';
|
||||
import * as ep___users_lists_delete from './endpoints/users/lists/delete.js';
|
||||
import * as ep___users_lists_list from './endpoints/users/lists/list.js';
|
||||
|
|
@ -567,6 +568,7 @@ const $i_importMuting: Provider = { provide: 'ep:i/import-muting', useClass: ep_
|
|||
const $i_importUserLists: Provider = { provide: 'ep:i/import-user-lists', useClass: ep___i_importUserLists.default };
|
||||
const $i_importAntennas: Provider = { provide: 'ep:i/import-antennas', useClass: ep___i_importAntennas.default };
|
||||
const $i_notifications: Provider = { provide: 'ep:i/notifications', useClass: ep___i_notifications.default };
|
||||
const $i_userstats: Provider = { provide: 'ep:i/stats', useClass: ep___users_user_stats.default }
|
||||
const $i_pageLikes: Provider = { provide: 'ep:i/page-likes', useClass: ep___i_pageLikes.default };
|
||||
const $i_pages: Provider = { provide: 'ep:i/pages', useClass: ep___i_pages.default };
|
||||
const $i_pin: Provider = { provide: 'ep:i/pin', useClass: ep___i_pin.default };
|
||||
|
|
@ -816,6 +818,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$channels_timeline,
|
||||
$channels_unfollow,
|
||||
$channels_update,
|
||||
$i_userstats,
|
||||
$channels_favorite,
|
||||
$channels_unfavorite,
|
||||
$channels_myFavorites,
|
||||
|
|
@ -1103,6 +1106,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
|||
$admin_emoji_setisSensitiveBulk,
|
||||
$admin_emoji_update,
|
||||
$admin_federation_deleteAllFiles,
|
||||
$i_userstats,
|
||||
$admin_federation_refreshRemoteInstanceMetadata,
|
||||
$admin_federation_removeAllFollowing,
|
||||
$admin_federation_updateInstance,
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ import * as ep___i_webhooks_show from './endpoints/i/webhooks/show.js';
|
|||
import * as ep___i_webhooks_list from './endpoints/i/webhooks/list.js';
|
||||
import * as ep___i_webhooks_update from './endpoints/i/webhooks/update.js';
|
||||
import * as ep___i_webhooks_delete from './endpoints/i/webhooks/delete.js';
|
||||
import * as ep___i_user_stats from './endpoints/users/stats.js';
|
||||
import * as ep___invite_create from './endpoints/invite/create.js';
|
||||
import * as ep___invite_delete from './endpoints/invite/delete.js';
|
||||
import * as ep___invite_list from './endpoints/invite/list.js';
|
||||
|
|
@ -589,6 +590,7 @@ const eps = [
|
|||
['i/webhooks/show', ep___i_webhooks_show],
|
||||
['i/webhooks/update', ep___i_webhooks_update],
|
||||
['i/webhooks/delete', ep___i_webhooks_delete],
|
||||
['i/stats', ep___i_user_stats],
|
||||
['invite/create', ep___invite_create],
|
||||
['invite/delete', ep___invite_delete],
|
||||
['invite/list', ep___invite_list],
|
||||
|
|
|
|||
228
packages/backend/src/server/api/endpoints/users/stats.ts
Normal file
228
packages/backend/src/server/api/endpoints/users/stats.ts
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
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,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue