Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 7 commits into from
Aug 17, 2024
18 changes: 11 additions & 7 deletions packages/backend/src/core/ClipService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ export class ClipService {
throw new ClipService.NoSuchClipError();
}

if (await this.clipNotesRepository.existsBy({ clipId, noteId })) {
throw new ClipService.AlreadyAddedError();
}

const policies = await this.roleService.getUserPolicies(me.id);

const currentClipCount = await this.clipsRepository.countBy({
Expand All @@ -143,6 +147,13 @@ export class ClipService {
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
.createQueryBuilder('cn')
.select('COUNT(*)')
Expand All @@ -154,13 +165,6 @@ export class ClipService {
throw new ClipService.ClipNotesLimitExceededError();
}

const currentNoteCount = await this.clipNotesRepository.countBy({
clipId: clip.id,
});
if (currentNoteCount >= policies.noteEachClipsLimit) {
throw new ClipService.TooManyClipNotesError();
}

try {
await this.clipNotesRepository.insert({
id: this.idService.gen(),
Expand Down
64 changes: 61 additions & 3 deletions packages/backend/src/core/UserSuspendService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js';
import type Logger from '@/logger.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 { GlobalEventService } from '@/core/GlobalEventService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
Expand All @@ -30,6 +39,24 @@ export class UserSuspendService {
@Inject(DI.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 globalEventService: GlobalEventService,
private apRendererService: ApRendererService,
Expand All @@ -45,10 +72,41 @@ export class UserSuspendService {

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({ 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)) {
// 知り得る全SharedInboxにDelete配信
Expand Down
Loading