fix(backend): アンテナ等がポリシーで定められた上限を超えている場合、変更や追加ができないように (MisskeyIO#646)
This commit is contained in:
parent
5ff34d2f8f
commit
2b2975c0dd
@ -20,6 +20,8 @@ export class ClipService {
|
||||
public static AlreadyAddedError = class extends Error {};
|
||||
public static TooManyClipNotesError = class extends Error {};
|
||||
public static TooManyClipsError = class extends Error {};
|
||||
public static ClipLimitExceededError = class extends Error {};
|
||||
public static ClipNotesLimitExceededError = class extends Error {};
|
||||
|
||||
constructor(
|
||||
@Inject(DI.clipsRepository)
|
||||
@ -38,13 +40,26 @@ export class ClipService {
|
||||
|
||||
@bindThis
|
||||
public async create(me: MiLocalUser, name: string, isPublic: boolean, description: string | null): Promise<MiClip> {
|
||||
const policies = await this.roleService.getUserPolicies(me.id);
|
||||
|
||||
const currentCount = await this.clipsRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentCount > (await this.roleService.getUserPolicies(me.id)).clipLimit) {
|
||||
if (currentCount >= policies.clipLimit) {
|
||||
throw new ClipService.TooManyClipsError();
|
||||
}
|
||||
|
||||
const currentNoteCounts = await this.clipNotesRepository
|
||||
.createQueryBuilder('cn')
|
||||
.select('COUNT(*)')
|
||||
.innerJoin('cn.clip', 'c')
|
||||
.where('c.userId = :userId', { userId: me.id })
|
||||
.groupBy('cn.clipId')
|
||||
.getRawMany<{ count: number }>();
|
||||
if (currentNoteCounts.some((x) => x.count > policies.noteEachClipsLimit)) {
|
||||
throw new ClipService.ClipNotesLimitExceededError();
|
||||
}
|
||||
|
||||
const clip = await this.clipsRepository.insert({
|
||||
id: this.idService.gen(),
|
||||
userId: me.id,
|
||||
@ -67,6 +82,26 @@ export class ClipService {
|
||||
throw new ClipService.NoSuchClipError();
|
||||
}
|
||||
|
||||
const policies = await this.roleService.getUserPolicies(me.id);
|
||||
|
||||
const currentCount = await this.clipsRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentCount > policies.clipLimit) {
|
||||
throw new ClipService.ClipLimitExceededError();
|
||||
}
|
||||
|
||||
const currentNoteCounts = await this.clipNotesRepository
|
||||
.createQueryBuilder('cn')
|
||||
.select('COUNT(*)')
|
||||
.innerJoin('cn.clip', 'c')
|
||||
.where('c.userId = :userId', { userId: me.id })
|
||||
.groupBy('cn.clipId')
|
||||
.getRawMany<{ count: number }>();
|
||||
if (currentNoteCounts.some((x) => x.count > policies.noteEachClipsLimit)) {
|
||||
throw new ClipService.ClipNotesLimitExceededError();
|
||||
}
|
||||
|
||||
await this.clipsRepository.update(clip.id, {
|
||||
name: name,
|
||||
description: description,
|
||||
@ -99,10 +134,30 @@ export class ClipService {
|
||||
throw new ClipService.NoSuchClipError();
|
||||
}
|
||||
|
||||
const currentCount = await this.clipNotesRepository.countBy({
|
||||
const policies = await this.roleService.getUserPolicies(me.id);
|
||||
|
||||
const currentClipCount = await this.clipsRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentClipCount > policies.clipLimit) {
|
||||
throw new ClipService.ClipLimitExceededError();
|
||||
}
|
||||
|
||||
const currentNoteCounts = await this.clipNotesRepository
|
||||
.createQueryBuilder('cn')
|
||||
.select('COUNT(*)')
|
||||
.innerJoin('cn.clip', 'c')
|
||||
.where('c.userId = :userId', { userId: me.id })
|
||||
.groupBy('cn.clipId')
|
||||
.getRawMany<{ count: number }>();
|
||||
if (currentNoteCounts.some((x) => x.count > policies.noteEachClipsLimit)) {
|
||||
throw new ClipService.ClipNotesLimitExceededError();
|
||||
}
|
||||
|
||||
const currentNoteCount = await this.clipNotesRepository.countBy({
|
||||
clipId: clip.id,
|
||||
});
|
||||
if (currentCount > (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) {
|
||||
if (currentNoteCount >= policies.noteEachClipsLimit) {
|
||||
throw new ClipService.TooManyClipNotesError();
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit {
|
||||
const currentCount = await this.userListMembershipsRepository.countBy({
|
||||
userListId: list.id,
|
||||
});
|
||||
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
|
||||
if (currentCount >= (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
|
||||
throw new UserListService.TooManyUsersError();
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
const currentAntennasCount = await this.antennasRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentAntennasCount > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
|
||||
if (currentAntennasCount >= (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
|
||||
throw new ApiError(meta.errors.tooManyAntennas);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import type { AntennasRepository, UserListsRepository } from '@/models/_.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { AntennaEntityService } from '@/core/entities/AntennaEntityService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
@ -33,6 +34,12 @@ export const meta = {
|
||||
code: 'NO_SUCH_USER_LIST',
|
||||
id: '1c6b35c9-943e-48c2-81e4-2844989407f7',
|
||||
},
|
||||
|
||||
antennaLimitExceeded: {
|
||||
message: 'You cannot update the antenna because you have exceeded the limit of antennas.',
|
||||
code: 'ANTENNA_LIMIT_EXCEEDED',
|
||||
id: '3166a92e-09d9-4c09-afa3-1dbe34a3afcf',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
@ -83,6 +90,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
|
||||
private antennaEntityService: AntennaEntityService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private roleService: RoleService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
if (ps.keywords && ps.excludeKeywords) {
|
||||
@ -100,6 +108,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
throw new ApiError(meta.errors.noSuchAntenna);
|
||||
}
|
||||
|
||||
const currentAntennasCount = await this.antennasRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentAntennasCount > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
|
||||
throw new ApiError(meta.errors.antennaLimitExceeded);
|
||||
}
|
||||
|
||||
let userList;
|
||||
|
||||
if ((ps.src === 'list' || antenna.src === 'list') && ps.userListId) {
|
||||
|
@ -48,6 +48,18 @@ export const meta = {
|
||||
code: 'TOO_MANY_CLIP_NOTES',
|
||||
id: 'f0dba960-ff73-4615-8df4-d6ac5d9dc118',
|
||||
},
|
||||
|
||||
clipLimitExceeded: {
|
||||
message: 'You cannot add a note to the clip because you have exceeded the limit of clips.',
|
||||
code: 'CLIP_LIMIT_EXCEEDED',
|
||||
id: '456cd06d-9f5b-4793-8108-dffe6e257d98',
|
||||
},
|
||||
|
||||
clipNotesLimitExceeded: {
|
||||
message: 'You cannot add a note to the clip because you have exceeded the limit of notes in other clips.',
|
||||
code: 'CLIP_NOTES_LIMIT_EXCEEDED',
|
||||
id: 'f3d6de24-ad27-418d-9d13-b50165dbce66',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
@ -77,6 +89,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
throw new ApiError(meta.errors.alreadyClipped);
|
||||
} else if (e instanceof ClipService.TooManyClipNotesError) {
|
||||
throw new ApiError(meta.errors.tooManyClipNotes);
|
||||
} else if (e instanceof ClipService.ClipLimitExceededError) {
|
||||
throw new ApiError(meta.errors.clipLimitExceeded);
|
||||
} else if (e instanceof ClipService.ClipNotesLimitExceededError) {
|
||||
throw new ApiError(meta.errors.clipNotesLimitExceeded);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
@ -32,6 +32,12 @@ export const meta = {
|
||||
code: 'TOO_MANY_CLIPS',
|
||||
id: '920f7c2d-6208-4b76-8082-e632020f5883',
|
||||
},
|
||||
|
||||
clipNotesLimitExceeded: {
|
||||
message: 'You cannot create a clip any more because you have exceeded the limit of notes in a clip.',
|
||||
code: 'CLIP_NOTES_LIMIT_EXCEEDED',
|
||||
id: '1fdd390f-dcd3-4b65-88d9-6476159bc5c8',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
@ -58,6 +64,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
} catch (e) {
|
||||
if (e instanceof ClipService.TooManyClipsError) {
|
||||
throw new ApiError(meta.errors.tooManyClips);
|
||||
} else if (e instanceof ClipService.ClipNotesLimitExceededError) {
|
||||
throw new ApiError(meta.errors.clipNotesLimitExceeded);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
@ -25,6 +25,18 @@ export const meta = {
|
||||
code: 'NO_SUCH_CLIP',
|
||||
id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
|
||||
},
|
||||
|
||||
clipLimitExceeded: {
|
||||
message: 'You cannot update the clip because you have exceeded the limit of clips.',
|
||||
code: 'CLIP_LIMIT_EXCEEDED',
|
||||
id: 'fed46dd9-d99a-4a88-b23f-8d31c80b5b25',
|
||||
},
|
||||
|
||||
clipNotesLimitExceeded: {
|
||||
message: 'You cannot update the clip because you have exceeded the limit of notes in a clip.',
|
||||
code: 'CLIP_NOTES_LIMIT_EXCEEDED',
|
||||
id: '6f02ab37-66a4-4285-afaf-a8b1000e8f3f',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
@ -58,6 +70,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
} catch (e) {
|
||||
if (e instanceof ClipService.NoSuchClipError) {
|
||||
throw new ApiError(meta.errors.noSuchClip);
|
||||
} else if (e instanceof ClipService.ClipLimitExceededError) {
|
||||
throw new ApiError(meta.errors.clipLimitExceeded);
|
||||
} else if (e instanceof ClipService.ClipNotesLimitExceededError) {
|
||||
throw new ApiError(meta.errors.clipNotesLimitExceeded);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
if (file.size === 0) throw new ApiError(meta.errors.emptyFile);
|
||||
const antennas: (_Antenna & { userListAccts: string[] | null })[] = JSON.parse(await this.downloadService.downloadTextFile(file.url));
|
||||
const currentAntennasCount = await this.antennasRepository.countBy({ userId: me.id });
|
||||
if (currentAntennasCount + antennas.length > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
|
||||
if (currentAntennasCount + antennas.length >= (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
|
||||
throw new ApiError(meta.errors.tooManyAntennas);
|
||||
}
|
||||
this.queueService.createImportAntennasJob(me, antennas);
|
||||
|
@ -91,7 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
const currentWebhooksCount = await this.webhooksRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentWebhooksCount > (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
|
||||
if (currentWebhooksCount >= (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
|
||||
throw new ApiError(meta.errors.tooManyWebhooks);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,11 @@ export const meta = {
|
||||
code: 'YOU_ARE_NOT_ADMIN',
|
||||
id: 'a70c7643-1db5-4ebf-becd-ff4b4223cf23',
|
||||
},
|
||||
webhookLimitExceeded: {
|
||||
message: 'You cannot update the webhook because you have exceeded the limit of webhooks.',
|
||||
code: 'WEBHOOK_LIMIT_EXCEEDED',
|
||||
id: 'a261cb2d-867d-47a8-a743-8bbd2c1438b1',
|
||||
},
|
||||
},
|
||||
|
||||
} as const;
|
||||
@ -62,6 +67,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
private roleService: RoleService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const currentWebhooksCount = await this.webhooksRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentWebhooksCount > (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
|
||||
throw new ApiError(meta.errors.webhookLimitExceeded);
|
||||
}
|
||||
|
||||
const webhook = await this.webhooksRepository.findOneBy({
|
||||
id: ps.webhookId,
|
||||
userId: me.id,
|
||||
|
@ -61,6 +61,12 @@ export const meta = {
|
||||
code: 'TOO_MANY_USERS',
|
||||
id: '1845ea77-38d1-426e-8e4e-8b83b24f5bd7',
|
||||
},
|
||||
|
||||
listUsersLimitExceeded: {
|
||||
message: 'You cannot create a list because you have exceeded the limit of users in a list.',
|
||||
code: 'LIST_USERS_LIMIT_EXCEEDED',
|
||||
id: '3e205e58-0798-40f2-a589-a78a619ee3d4',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
@ -99,13 +105,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
},
|
||||
});
|
||||
if (!listExist) throw new ApiError(meta.errors.noSuchList);
|
||||
|
||||
const policies = await this.roleService.getUserPolicies(me.id);
|
||||
const currentCount = await this.userListsRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) {
|
||||
if (currentCount >= policies.userListLimit) {
|
||||
throw new ApiError(meta.errors.tooManyUserLists);
|
||||
}
|
||||
|
||||
const currentUserCounts = await this.userListMembershipsRepository
|
||||
.createQueryBuilder('ulm')
|
||||
.select('COUNT(*)')
|
||||
.where('ulm.userListUserId = :userId', { userId: me.id })
|
||||
.groupBy('ulm.userListId')
|
||||
.getRawMany<{ count: number }>();
|
||||
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
|
||||
throw new ApiError(meta.errors.listUsersLimitExceeded);
|
||||
}
|
||||
|
||||
const userList = await this.userListsRepository.insert({
|
||||
id: this.idService.gen(),
|
||||
userId: me.id,
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { UserListsRepository } from '@/models/_.js';
|
||||
import type { UserListMembershipsRepository, UserListsRepository } from '@/models/_.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import type { MiUserList } from '@/models/UserList.js';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
@ -37,6 +37,12 @@ export const meta = {
|
||||
code: 'TOO_MANY_USERLISTS',
|
||||
id: '0cf21a28-7715-4f39-a20d-777bfdb8d138',
|
||||
},
|
||||
|
||||
listUsersLimitExceeded: {
|
||||
message: 'You cannot create a list because you have exceeded the limit of users in a list.',
|
||||
code: 'LIST_USERS_LIMIT_EXCEEDED',
|
||||
id: 'af66c10d-b0e6-418c-a205-4dd46a482e30',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
@ -54,18 +60,32 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
@Inject(DI.userListsRepository)
|
||||
private userListsRepository: UserListsRepository,
|
||||
|
||||
@Inject(DI.userListMembershipsRepository)
|
||||
private userListMembershipsRepository: UserListMembershipsRepository,
|
||||
|
||||
private userListEntityService: UserListEntityService,
|
||||
private idService: IdService,
|
||||
private roleService: RoleService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const policies = await this.roleService.getUserPolicies(me.id);
|
||||
const currentCount = await this.userListsRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) {
|
||||
if (currentCount >= policies.userListLimit) {
|
||||
throw new ApiError(meta.errors.tooManyUserLists);
|
||||
}
|
||||
|
||||
const currentUserCounts = await this.userListMembershipsRepository
|
||||
.createQueryBuilder('ulm')
|
||||
.select('COUNT(*)')
|
||||
.where('ulm.userListUserId = :userId', { userId: me.id })
|
||||
.groupBy('ulm.userListId')
|
||||
.getRawMany<{ count: number }>();
|
||||
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
|
||||
throw new ApiError(meta.errors.listUsersLimitExceeded);
|
||||
}
|
||||
|
||||
const userList = await this.userListsRepository.insert({
|
||||
id: this.idService.gen(),
|
||||
userId: me.id,
|
||||
|
@ -10,6 +10,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { GetterService } from '@/server/api/GetterService.js';
|
||||
import { UserListService } from '@/core/UserListService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
@ -59,6 +60,18 @@ export const meta = {
|
||||
code: 'TOO_MANY_USERS',
|
||||
id: '2dd9752e-a338-413d-8eec-41814430989b',
|
||||
},
|
||||
|
||||
listLimitExceeded: {
|
||||
message: 'You cannot add a user to the list because you have exceeded the limit of lists.',
|
||||
code: 'LIST_LIMIT_EXCEEDED',
|
||||
id: '5906ab2d-c164-44bc-a60a-464beba52be9',
|
||||
},
|
||||
|
||||
listUsersLimitExceeded: {
|
||||
message: 'You cannot add a user to the list because you have exceeded the limit of users in other list.',
|
||||
code: 'LIST_USERS_LIMIT_EXCEEDED',
|
||||
id: 'd1054b77-908a-4f7d-a9cc-44d665267108',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
@ -85,6 +98,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
|
||||
private getterService: GetterService,
|
||||
private userListService: UserListService,
|
||||
private roleService: RoleService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
// Fetch the list
|
||||
@ -97,6 +111,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
throw new ApiError(meta.errors.noSuchList);
|
||||
}
|
||||
|
||||
// Check the list limit
|
||||
const policies = await this.roleService.getUserPolicies(me.id);
|
||||
const currentCount = await this.userListsRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentCount > policies.userListLimit) {
|
||||
throw new ApiError(meta.errors.listLimitExceeded);
|
||||
}
|
||||
|
||||
const currentUserCounts = await this.userListMembershipsRepository
|
||||
.createQueryBuilder('ulm')
|
||||
.select('COUNT(*)')
|
||||
.where('ulm.userListUserId = :userId', { userId: me.id })
|
||||
.groupBy('ulm.userListId')
|
||||
.getRawMany<{ count: number }>();
|
||||
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
|
||||
throw new ApiError(meta.errors.listUsersLimitExceeded);
|
||||
}
|
||||
|
||||
// Fetch the user
|
||||
const user = await this.getterService.getUser(ps.userId).catch(err => {
|
||||
if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser);
|
||||
|
@ -4,11 +4,12 @@
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { UserListsRepository } from '@/models/_.js';
|
||||
import type { UserListMembershipsRepository, UserListsRepository } from '@/models/_.js';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { GetterService } from '@/server/api/GetterService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { UserListService } from '@/core/UserListService.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
@ -32,6 +33,18 @@ export const meta = {
|
||||
code: 'NO_SUCH_USER',
|
||||
id: '588e7f72-c744-4a61-b180-d354e912bda2',
|
||||
},
|
||||
|
||||
listLimitExceeded: {
|
||||
message: 'You cannot update the user because you have exceeded the limit of lists.',
|
||||
code: 'LIST_LIMIT_EXCEEDED',
|
||||
id: 'd4005118-e773-4132-bafb-10ba22c78da3',
|
||||
},
|
||||
|
||||
listUsersLimitExceeded: {
|
||||
message: 'You cannot update the user because you have exceeded the limit of users in a list.',
|
||||
code: 'LIST_USERS_LIMIT_EXCEEDED',
|
||||
id: 'db7fe164-73d0-4788-8ed1-b6a19e95990d',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
@ -51,8 +64,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
@Inject(DI.userListsRepository)
|
||||
private userListsRepository: UserListsRepository,
|
||||
|
||||
@Inject(DI.userListMembershipsRepository)
|
||||
private userListMembershipsRepository: UserListMembershipsRepository,
|
||||
|
||||
private userListService: UserListService,
|
||||
private getterService: GetterService,
|
||||
private roleService: RoleService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
// Fetch the list
|
||||
@ -65,6 +82,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
throw new ApiError(meta.errors.noSuchList);
|
||||
}
|
||||
|
||||
// Check the list limit
|
||||
const policies = await this.roleService.getUserPolicies(me.id);
|
||||
const currentCount = await this.userListsRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentCount > policies.userListLimit) {
|
||||
throw new ApiError(meta.errors.listLimitExceeded);
|
||||
}
|
||||
|
||||
const currentUserCounts = await this.userListMembershipsRepository
|
||||
.createQueryBuilder('ulm')
|
||||
.select('COUNT(*)')
|
||||
.where('ulm.userListUserId = :userId', { userId: me.id })
|
||||
.groupBy('ulm.userListId')
|
||||
.getRawMany<{ count: number }>();
|
||||
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
|
||||
throw new ApiError(meta.errors.listUsersLimitExceeded);
|
||||
}
|
||||
|
||||
// Fetch the user
|
||||
const user = await this.getterService.getUser(ps.userId).catch(err => {
|
||||
if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser);
|
||||
|
@ -4,10 +4,11 @@
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { UserListsRepository } from '@/models/_.js';
|
||||
import type { UserListMembershipsRepository, UserListsRepository } from '@/models/_.js';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { UserListEntityService } from '@/core/entities/UserListEntityService.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
@ -32,6 +33,18 @@ export const meta = {
|
||||
code: 'NO_SUCH_LIST',
|
||||
id: '796666fe-3dff-4d39-becb-8a5932c1d5b7',
|
||||
},
|
||||
|
||||
listLimitExceeded: {
|
||||
message: 'You cannot update the list because you have exceeded the limit of lists.',
|
||||
code: 'LIST_LIMIT_EXCEEDED',
|
||||
id: '0a1fa63e-3e4c-4bc2-afd1-1ff853b4560e',
|
||||
},
|
||||
|
||||
listUsersLimitExceeded: {
|
||||
message: 'You cannot update the list because you have exceeded the limit of users in a list.',
|
||||
code: 'LIST_USERS_LIMIT_EXCEEDED',
|
||||
id: '831fd3b2-4ac8-421e-89db-bfd98944e529',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
@ -51,7 +64,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
@Inject(DI.userListsRepository)
|
||||
private userListsRepository: UserListsRepository,
|
||||
|
||||
@Inject(DI.userListMembershipsRepository)
|
||||
private userListMembershipsRepository: UserListMembershipsRepository,
|
||||
|
||||
private userListEntityService: UserListEntityService,
|
||||
private roleService: RoleService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const userList = await this.userListsRepository.findOneBy({
|
||||
@ -63,6 +80,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
throw new ApiError(meta.errors.noSuchList);
|
||||
}
|
||||
|
||||
const policies = await this.roleService.getUserPolicies(me.id);
|
||||
const currentCount = await this.userListsRepository.countBy({
|
||||
userId: me.id,
|
||||
});
|
||||
if (currentCount > policies.userListLimit) {
|
||||
throw new ApiError(meta.errors.listLimitExceeded);
|
||||
}
|
||||
|
||||
const currentUserCounts = await this.userListMembershipsRepository
|
||||
.createQueryBuilder('ulm')
|
||||
.select('COUNT(*)')
|
||||
.where('ulm.userListUserId = :userId', { userId: me.id })
|
||||
.groupBy('ulm.userListId')
|
||||
.getRawMany<{ count: number }>();
|
||||
if (currentUserCounts.some((x) => x.count > policies.userEachUserListsLimit)) {
|
||||
throw new ApiError(meta.errors.listUsersLimitExceeded);
|
||||
}
|
||||
|
||||
await this.userListsRepository.update(userList.id, {
|
||||
name: ps.name,
|
||||
isPublic: ps.isPublic,
|
||||
|
@ -167,8 +167,7 @@ describe('アンテナ', () => {
|
||||
});
|
||||
|
||||
test('が上限いっぱいまで作成できること', async () => {
|
||||
// antennaLimit + 1まで作れるのがキモ
|
||||
const response = await Promise.all([...Array(DEFAULT_POLICIES.antennaLimit + 1)].map(() => successfulApiCall({
|
||||
const response = await Promise.all([...Array(DEFAULT_POLICIES.antennaLimit)].map(() => successfulApiCall({
|
||||
endpoint: 'antennas/create',
|
||||
parameters: { ...defaultParam },
|
||||
user: alice,
|
||||
|
@ -153,8 +153,7 @@ describe('クリップ', () => {
|
||||
});
|
||||
|
||||
test('の作成はポリシーで定められた数以上はできない。', async () => {
|
||||
// ポリシー + 1まで作れるという所がミソ
|
||||
const clipLimit = DEFAULT_POLICIES.clipLimit + 1;
|
||||
const clipLimit = DEFAULT_POLICIES.clipLimit;
|
||||
for (let i = 0; i < clipLimit; i++) {
|
||||
await create();
|
||||
}
|
||||
@ -327,10 +326,10 @@ describe('クリップ', () => {
|
||||
});
|
||||
|
||||
test('の一覧(clips/list)が取得できる(上限いっぱい)', async () => {
|
||||
const clipLimit = DEFAULT_POLICIES.clipLimit + 1;
|
||||
const clipLimit = DEFAULT_POLICIES.clipLimit;
|
||||
const clips = await createMany({}, clipLimit);
|
||||
const res = await list({
|
||||
parameters: { limit: 1 }, // FIXME: 無視されて11全部返ってくる
|
||||
parameters: { limit: 1 }, // FIXME: 無視されて10全部返ってくる
|
||||
});
|
||||
|
||||
// 返ってくる配列には順序保障がないのでidでソートして厳密比較
|
||||
@ -705,7 +704,7 @@ describe('クリップ', () => {
|
||||
|
||||
// TODO: 17000msくらいかかる...
|
||||
test('をポリシーで定められた上限いっぱい(200)を超えて追加はできない。', async () => {
|
||||
const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit + 1;
|
||||
const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit;
|
||||
const noteList = await Promise.all([...Array(noteLimit)].map((_, i) => post(alice, {
|
||||
text: `test ${i}`,
|
||||
}) as unknown)) as Misskey.entities.Note[];
|
||||
|
Loading…
Reference in New Issue
Block a user