1
0
mirror of https://github.com/MisskeyIO/misskey synced 2024-11-23 14:46:40 +09:00

fix(backend): クリップ周りの不具合修正 (MisskeyIO#709)

This commit is contained in:
riku6460 2024-08-18 06:26:21 +09:00 committed by GitHub
parent 8329498d4c
commit b3376501d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 72 additions and 10 deletions

View File

@ -134,6 +134,10 @@ export class ClipService {
throw new ClipService.NoSuchClipError(); throw new ClipService.NoSuchClipError();
} }
if (await this.clipNotesRepository.existsBy({ clipId, noteId })) {
throw new ClipService.AlreadyAddedError();
}
const policies = await this.roleService.getUserPolicies(me.id); const policies = await this.roleService.getUserPolicies(me.id);
const currentClipCount = await this.clipsRepository.countBy({ const currentClipCount = await this.clipsRepository.countBy({
@ -143,6 +147,13 @@ export class ClipService {
throw new ClipService.ClipLimitExceededError(); throw new ClipService.ClipLimitExceededError();
} }
const currentNoteCount = await this.clipNotesRepository.countBy({
clipId: clip.id,
});
if (currentNoteCount >= policies.noteEachClipsLimit) {
throw new ClipService.TooManyClipNotesError();
}
const currentNoteCounts = await this.clipNotesRepository const currentNoteCounts = await this.clipNotesRepository
.createQueryBuilder('cn') .createQueryBuilder('cn')
.select('COUNT(*)') .select('COUNT(*)')
@ -154,13 +165,6 @@ export class ClipService {
throw new ClipService.ClipNotesLimitExceededError(); throw new ClipService.ClipNotesLimitExceededError();
} }
const currentNoteCount = await this.clipNotesRepository.countBy({
clipId: clip.id,
});
if (currentNoteCount >= policies.noteEachClipsLimit) {
throw new ClipService.TooManyClipNotesError();
}
try { try {
await this.clipNotesRepository.insert({ await this.clipNotesRepository.insert({
id: this.idService.gen(), id: this.idService.gen(),

View File

@ -9,7 +9,16 @@ import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.js'; import type Logger from '@/logger.js';
import type { MiUser } from '@/models/User.js'; import type { MiUser } from '@/models/User.js';
import type { FollowingsRepository, FollowRequestsRepository } from '@/models/_.js'; import type {
AntennasRepository,
ClipNotesRepository,
ClipsRepository,
FollowingsRepository,
FollowRequestsRepository,
UserListMembershipsRepository,
UserListsRepository,
WebhooksRepository,
} from '@/models/_.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
@ -30,6 +39,24 @@ export class UserSuspendService {
@Inject(DI.followRequestsRepository) @Inject(DI.followRequestsRepository)
private followRequestsRepository: FollowRequestsRepository, private followRequestsRepository: FollowRequestsRepository,
@Inject(DI.antennasRepository)
private antennasRepository: AntennasRepository,
@Inject(DI.webhooksRepository)
private webhooksRepository: WebhooksRepository,
@Inject(DI.userListsRepository)
private userListsRepository: UserListsRepository,
@Inject(DI.clipsRepository)
private clipsRepository: ClipsRepository,
@Inject(DI.clipNotesRepository)
private clipNotesRepository: ClipNotesRepository,
@Inject(DI.userListMembershipsRepository)
private userListMembershipsRepository: UserListMembershipsRepository,
private queueService: QueueService, private queueService: QueueService,
private globalEventService: GlobalEventService, private globalEventService: GlobalEventService,
private apRendererService: ApRendererService, private apRendererService: ApRendererService,
@ -45,10 +72,41 @@ export class UserSuspendService {
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true }); this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true });
await Promise.all([ const promises: Promise<unknown>[] = [];
let cursor = '';
while (true) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition, no-constant-condition
const clipNotes = await this.clipNotesRepository.createQueryBuilder('c')
.select('c.id')
.innerJoin('c.note', 'n')
.where('n.userId = :userId', { userId: user.id })
.andWhere('c.id > :cursor', { cursor })
.orderBy('c.id', 'ASC')
.limit(500)
.getRawMany<{ id: string }>();
if (clipNotes.length === 0) break;
cursor = clipNotes.at(-1)?.id ?? '';
promises.push(this.clipNotesRepository.createQueryBuilder()
.delete()
.where('id IN (:...ids)', { ids: clipNotes.map((clipNote) => clipNote.id) })
.execute());
}
await Promise.allSettled([
this.followRequestsRepository.delete({ followeeId: user.id }), this.followRequestsRepository.delete({ followeeId: user.id }),
this.followRequestsRepository.delete({ followerId: user.id }), this.followRequestsRepository.delete({ followerId: user.id }),
]).catch(() => null);
this.antennasRepository.delete({ userId: user.id }),
this.webhooksRepository.delete({ userId: user.id }),
this.userListsRepository.delete({ userId: user.id }),
this.clipsRepository.delete({ userId: user.id }),
...promises,
this.userListMembershipsRepository.delete({ userId: user.id }),
]);
if (this.userEntityService.isLocalUser(user)) { if (this.userEntityService.isLocalUser(user)) {
// 知り得る全SharedInboxにDelete配信 // 知り得る全SharedInboxにDelete配信