enhance: ユーザーリストおよびユーザーリスト内のユーザーの作成可能数を設定可能に
This commit is contained in:
		
							parent
							
								
									c41879c542
								
							
						
					
					
						commit
						76c049522e
					
				
					 9 changed files with 88 additions and 4 deletions
				
			
		|  | @ -77,6 +77,7 @@ You should also include the user name that made the change. | ||||||
| - 非モデレーターでも、権限を持つロールをアサインされたユーザーはインスタンスの招待コードを発行できるように @syuilo | - 非モデレーターでも、権限を持つロールをアサインされたユーザーはインスタンスの招待コードを発行できるように @syuilo | ||||||
| - 非モデレーターでも、権限を持つロールをアサインされたユーザーはカスタム絵文字の追加、編集、削除を行えるように @syuilo | - 非モデレーターでも、権限を持つロールをアサインされたユーザーはカスタム絵文字の追加、編集、削除を行えるように @syuilo | ||||||
| - クリップおよびクリップ内のノートの作成可能数を設定可能に @syuilo | - クリップおよびクリップ内のノートの作成可能数を設定可能に @syuilo | ||||||
|  | - ユーザーリストおよびユーザーリスト内のユーザーの作成可能数を設定可能に @syuilo | ||||||
| - ハードワードミュートの最大文字数を設定可能に @syuilo | - ハードワードミュートの最大文字数を設定可能に @syuilo | ||||||
| - Webhookの作成可能数を設定可能に @syuilo | - Webhookの作成可能数を設定可能に @syuilo | ||||||
| - Server: signToActivityPubGet is set to true by default @syuilo | - Server: signToActivityPubGet is set to true by default @syuilo | ||||||
|  |  | ||||||
|  | @ -966,6 +966,8 @@ _role: | ||||||
|     webhookMax: "Webhookの作成可能数" |     webhookMax: "Webhookの作成可能数" | ||||||
|     clipMax: "クリップの作成可能数" |     clipMax: "クリップの作成可能数" | ||||||
|     noteEachClipsMax: "クリップ内のノートの最大数" |     noteEachClipsMax: "クリップ内のノートの最大数" | ||||||
|  |     userListMax: "ユーザーリストの作成可能数" | ||||||
|  |     userEachUserListsMax: "ユーザーリスト内のユーザーの最大数" | ||||||
|   _condition: |   _condition: | ||||||
|     isLocal: "ローカルユーザー" |     isLocal: "ローカルユーザー" | ||||||
|     isRemote: "リモートユーザー" |     isRemote: "リモートユーザー" | ||||||
|  |  | ||||||
|  | @ -25,6 +25,8 @@ export type RoleOptions = { | ||||||
| 	webhookLimit: number; | 	webhookLimit: number; | ||||||
| 	clipLimit: number; | 	clipLimit: number; | ||||||
| 	noteEachClipsLimit: number; | 	noteEachClipsLimit: number; | ||||||
|  | 	userListLimit: number; | ||||||
|  | 	userEachUserListsLimit: number; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const DEFAULT_ROLE: RoleOptions = { | export const DEFAULT_ROLE: RoleOptions = { | ||||||
|  | @ -39,6 +41,8 @@ export const DEFAULT_ROLE: RoleOptions = { | ||||||
| 	webhookLimit: 3, | 	webhookLimit: 3, | ||||||
| 	clipLimit: 10, | 	clipLimit: 10, | ||||||
| 	noteEachClipsLimit: 200, | 	noteEachClipsLimit: 200, | ||||||
|  | 	userListLimit: 10, | ||||||
|  | 	userEachUserListsLimit: 50, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @Injectable() | @Injectable() | ||||||
|  | @ -212,6 +216,8 @@ export class RoleService implements OnApplicationShutdown { | ||||||
| 			webhookLimit: Math.max(...getOptionValues('webhookLimit')), | 			webhookLimit: Math.max(...getOptionValues('webhookLimit')), | ||||||
| 			clipLimit: Math.max(...getOptionValues('clipLimit')), | 			clipLimit: Math.max(...getOptionValues('clipLimit')), | ||||||
| 			noteEachClipsLimit: Math.max(...getOptionValues('noteEachClipsLimit')), | 			noteEachClipsLimit: Math.max(...getOptionValues('noteEachClipsLimit')), | ||||||
|  | 			userListLimit: Math.max(...getOptionValues('userListLimit')), | ||||||
|  | 			userEachUserListsLimit: Math.max(...getOptionValues('userEachUserListsLimit')), | ||||||
| 		}; | 		}; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ import { DI } from '@/di-symbols.js'; | ||||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||||
| import { ProxyAccountService } from '@/core/ProxyAccountService.js'; | import { ProxyAccountService } from '@/core/ProxyAccountService.js'; | ||||||
| import { bindThis } from '@/decorators.js'; | import { bindThis } from '@/decorators.js'; | ||||||
|  | import { RoleService } from '@/core/RoleService.js'; | ||||||
| 
 | 
 | ||||||
| @Injectable() | @Injectable() | ||||||
| export class UserListService { | export class UserListService { | ||||||
|  | @ -23,13 +24,21 @@ export class UserListService { | ||||||
| 		private userEntityService: UserEntityService, | 		private userEntityService: UserEntityService, | ||||||
| 		private idService: IdService, | 		private idService: IdService, | ||||||
| 		private userFollowingService: UserFollowingService, | 		private userFollowingService: UserFollowingService, | ||||||
|  | 		private roleService: RoleService, | ||||||
| 		private globalEventServie: GlobalEventService, | 		private globalEventServie: GlobalEventService, | ||||||
| 		private proxyAccountService: ProxyAccountService, | 		private proxyAccountService: ProxyAccountService, | ||||||
| 	) { | 	) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@bindThis | 	@bindThis | ||||||
| 	public async push(target: User, list: UserList) { | 	public async push(target: User, list: UserList, me: User) { | ||||||
|  | 		const currentCount = await this.userListJoiningsRepository.countBy({ | ||||||
|  | 			userListId: list.id, | ||||||
|  | 		}); | ||||||
|  | 		if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).userEachUserListsLimit) { | ||||||
|  | 			throw new Error('Too many users'); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		await this.userListJoiningsRepository.insert({ | 		await this.userListJoiningsRepository.insert({ | ||||||
| 			id: this.idService.genId(), | 			id: this.idService.genId(), | ||||||
| 			createdAt: new Date(), | 			createdAt: new Date(), | ||||||
|  |  | ||||||
|  | @ -10,10 +10,10 @@ import { DownloadService } from '@/core/DownloadService.js'; | ||||||
| import { UserListService } from '@/core/UserListService.js'; | import { UserListService } from '@/core/UserListService.js'; | ||||||
| import { IdService } from '@/core/IdService.js'; | import { IdService } from '@/core/IdService.js'; | ||||||
| import { UtilityService } from '@/core/UtilityService.js'; | import { UtilityService } from '@/core/UtilityService.js'; | ||||||
|  | import { bindThis } from '@/decorators.js'; | ||||||
| import { QueueLoggerService } from '../QueueLoggerService.js'; | import { QueueLoggerService } from '../QueueLoggerService.js'; | ||||||
| import type Bull from 'bull'; | import type Bull from 'bull'; | ||||||
| import type { DbUserImportJobData } from '../types.js'; | import type { DbUserImportJobData } from '../types.js'; | ||||||
| import { bindThis } from '@/decorators.js'; |  | ||||||
| 
 | 
 | ||||||
| @Injectable() | @Injectable() | ||||||
| export class ImportUserListsProcessorService { | export class ImportUserListsProcessorService { | ||||||
|  | @ -102,7 +102,7 @@ export class ImportUserListsProcessorService { | ||||||
| 
 | 
 | ||||||
| 				if (await this.userListJoiningsRepository.findOneBy({ userListId: list!.id, userId: target.id }) != null) continue; | 				if (await this.userListJoiningsRepository.findOneBy({ userListId: list!.id, userId: target.id }) != null) continue; | ||||||
| 
 | 
 | ||||||
| 				this.userListService.push(target, list!); | 				this.userListService.push(target, list!, user); | ||||||
| 			} catch (e) { | 			} catch (e) { | ||||||
| 				this.logger.warn(`Error in line:${linenum} ${e}`); | 				this.logger.warn(`Error in line:${linenum} ${e}`); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ import type { UserList } from '@/models/entities/UserList.js'; | ||||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||||
| import { UserListEntityService } from '@/core/entities/UserListEntityService.js'; | import { UserListEntityService } from '@/core/entities/UserListEntityService.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
|  | import { ApiError } from '@/server/api/error'; | ||||||
|  | import { RoleService } from '@/core/RoleService.js'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['lists'], | 	tags: ['lists'], | ||||||
|  | @ -20,6 +22,14 @@ export const meta = { | ||||||
| 		optional: false, nullable: false, | 		optional: false, nullable: false, | ||||||
| 		ref: 'UserList', | 		ref: 'UserList', | ||||||
| 	}, | 	}, | ||||||
|  | 
 | ||||||
|  | 	errors: { | ||||||
|  | 		tooManyUserLists: { | ||||||
|  | 			message: 'You cannot create user list any more.', | ||||||
|  | 			code: 'TOO_MANY_USERLISTS', | ||||||
|  | 			id: '0cf21a28-7715-4f39-a20d-777bfdb8d138', | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
| } as const; | } as const; | ||||||
| 
 | 
 | ||||||
| export const paramDef = { | export const paramDef = { | ||||||
|  | @ -39,8 +49,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 
 | 
 | ||||||
| 		private userListEntityService: UserListEntityService, | 		private userListEntityService: UserListEntityService, | ||||||
| 		private idService: IdService, | 		private idService: IdService, | ||||||
|  | 		private roleService: RoleService, | ||||||
| 	) { | 	) { | ||||||
| 		super(meta, paramDef, async (ps, me) => { | 		super(meta, paramDef, async (ps, me) => { | ||||||
|  | 			const currentCount = await this.userListsRepository.countBy({ | ||||||
|  | 				userId: me.id, | ||||||
|  | 			}); | ||||||
|  | 			if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).userListLimit) { | ||||||
|  | 				throw new ApiError(meta.errors.tooManyUserLists); | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
| 			const userList = await this.userListsRepository.insert({ | 			const userList = await this.userListsRepository.insert({ | ||||||
| 				id: this.idService.genId(), | 				id: this.idService.genId(), | ||||||
| 				createdAt: new Date(), | 				createdAt: new Date(), | ||||||
|  |  | ||||||
|  | @ -111,7 +111,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			// Push the user
 | 			// Push the user
 | ||||||
| 			await this.userListService.push(user, userList); | 			await this.userListService.push(user, userList, me); | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -176,6 +176,30 @@ | ||||||
| 					</MkInput> | 					</MkInput> | ||||||
| 				</div> | 				</div> | ||||||
| 			</MkFolder> | 			</MkFolder> | ||||||
|  | 
 | ||||||
|  | 			<MkFolder> | ||||||
|  | 				<template #label>{{ i18n.ts._role._options.userListMax }}</template> | ||||||
|  | 				<template #suffix>{{ options_userList_useDefault ? i18n.ts._role.useBaseValue : (options_userList_value) }}</template> | ||||||
|  | 				<div class="_gaps"> | ||||||
|  | 					<MkSwitch v-model="options_userList_useDefault" :readonly="readonly"> | ||||||
|  | 						<template #label>{{ i18n.ts._role.useBaseValue }}</template> | ||||||
|  | 					</MkSwitch> | ||||||
|  | 					<MkInput v-model="options_userList_value" :disabled="options_userList_useDefault" type="number" :readonly="readonly"> | ||||||
|  | 					</MkInput> | ||||||
|  | 				</div> | ||||||
|  | 			</MkFolder> | ||||||
|  | 
 | ||||||
|  | 			<MkFolder> | ||||||
|  | 				<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template> | ||||||
|  | 				<template #suffix>{{ options_userEachUserListsLimit_useDefault ? i18n.ts._role.useBaseValue : (options_userEachUserListsLimit_value) }}</template> | ||||||
|  | 				<div class="_gaps"> | ||||||
|  | 					<MkSwitch v-model="options_userEachUserListsLimit_useDefault" :readonly="readonly"> | ||||||
|  | 						<template #label>{{ i18n.ts._role.useBaseValue }}</template> | ||||||
|  | 					</MkSwitch> | ||||||
|  | 					<MkInput v-model="options_userEachUserListsLimit_value" :disabled="options_userEachUserListsLimit_useDefault" type="number" :readonly="readonly"> | ||||||
|  | 					</MkInput> | ||||||
|  | 				</div> | ||||||
|  | 			</MkFolder> | ||||||
| 		</div> | 		</div> | ||||||
| 	</FormSlot> | 	</FormSlot> | ||||||
| 
 | 
 | ||||||
|  | @ -251,6 +275,10 @@ let options_clipLimit_useDefault = $ref(role?.options?.clipLimit?.useDefault ?? | ||||||
| let options_clipLimit_value = $ref(role?.options?.clipLimit?.value ?? 0); | let options_clipLimit_value = $ref(role?.options?.clipLimit?.value ?? 0); | ||||||
| let options_noteEachClipsLimit_useDefault = $ref(role?.options?.noteEachClipsLimit?.useDefault ?? true); | let options_noteEachClipsLimit_useDefault = $ref(role?.options?.noteEachClipsLimit?.useDefault ?? true); | ||||||
| let options_noteEachClipsLimit_value = $ref(role?.options?.noteEachClipsLimit?.value ?? 0); | let options_noteEachClipsLimit_value = $ref(role?.options?.noteEachClipsLimit?.value ?? 0); | ||||||
|  | let options_userListLimit_useDefault = $ref(role?.options?.userListLimit?.useDefault ?? true); | ||||||
|  | let options_userListLimit_value = $ref(role?.options?.userListLimit?.value ?? 0); | ||||||
|  | let options_userEachUserListsLimit_useDefault = $ref(role?.options?.userEachUserListsLimit?.useDefault ?? true); | ||||||
|  | let options_userEachUserListsLimit_value = $ref(role?.options?.userEachUserListsLimit?.value ?? 0); | ||||||
| 
 | 
 | ||||||
| if (_DEV_) { | if (_DEV_) { | ||||||
| 	watch($$(condFormula), () => { | 	watch($$(condFormula), () => { | ||||||
|  | @ -271,6 +299,8 @@ function getOptions() { | ||||||
| 		webhookLimit: { useDefault: options_webhookLimit_useDefault, value: options_webhookLimit_value }, | 		webhookLimit: { useDefault: options_webhookLimit_useDefault, value: options_webhookLimit_value }, | ||||||
| 		clipLimit: { useDefault: options_clipLimit_useDefault, value: options_clipLimit_value }, | 		clipLimit: { useDefault: options_clipLimit_useDefault, value: options_clipLimit_value }, | ||||||
| 		noteEachClipsLimit: { useDefault: options_noteEachClipsLimit_useDefault, value: options_noteEachClipsLimit_value }, | 		noteEachClipsLimit: { useDefault: options_noteEachClipsLimit_useDefault, value: options_noteEachClipsLimit_value }, | ||||||
|  | 		userListLimit: { useDefault: options_userListLimit_useDefault, value: options_userListLimit_value }, | ||||||
|  | 		userEachUserListsLimit: { useDefault: options_userEachUserListsLimit_useDefault, value: options_userEachUserListsLimit_value }, | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -92,6 +92,20 @@ | ||||||
| 							</MkInput> | 							</MkInput> | ||||||
| 						</MkFolder> | 						</MkFolder> | ||||||
| 
 | 
 | ||||||
|  | 						<MkFolder> | ||||||
|  | 							<template #label>{{ i18n.ts._role._options.userListMax }}</template> | ||||||
|  | 							<template #suffix>{{ options_userListLimit }}</template> | ||||||
|  | 							<MkInput v-model="options_userListLimit" type="number"> | ||||||
|  | 							</MkInput> | ||||||
|  | 						</MkFolder> | ||||||
|  | 
 | ||||||
|  | 						<MkFolder> | ||||||
|  | 							<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template> | ||||||
|  | 							<template #suffix>{{ options_userEachUserListsLimit }}</template> | ||||||
|  | 							<MkInput v-model="options_userEachUserListsLimit" type="number"> | ||||||
|  | 							</MkInput> | ||||||
|  | 						</MkFolder> | ||||||
|  | 
 | ||||||
| 						<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton> | 						<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton> | ||||||
| 					</div> | 					</div> | ||||||
| 				</MkFolder> | 				</MkFolder> | ||||||
|  | @ -135,6 +149,8 @@ let options_wordMuteLimit = $ref(instance.baseRole.wordMuteLimit); | ||||||
| let options_webhookLimit = $ref(instance.baseRole.webhookLimit); | let options_webhookLimit = $ref(instance.baseRole.webhookLimit); | ||||||
| let options_clipLimit = $ref(instance.baseRole.clipLimit); | let options_clipLimit = $ref(instance.baseRole.clipLimit); | ||||||
| let options_noteEachClipsLimit = $ref(instance.baseRole.noteEachClipsLimit); | let options_noteEachClipsLimit = $ref(instance.baseRole.noteEachClipsLimit); | ||||||
|  | let options_userListLimit = $ref(instance.baseRole.userListLimit); | ||||||
|  | let options_userEachUserListsLimit = $ref(instance.baseRole.userEachUserListsLimit); | ||||||
| 
 | 
 | ||||||
| async function updateBaseRole() { | async function updateBaseRole() { | ||||||
| 	await os.apiWithDialog('admin/roles/update-default-role-override', { | 	await os.apiWithDialog('admin/roles/update-default-role-override', { | ||||||
|  | @ -150,6 +166,8 @@ async function updateBaseRole() { | ||||||
| 			webhookLimit: options_webhookLimit, | 			webhookLimit: options_webhookLimit, | ||||||
| 			clipLimit: options_clipLimit, | 			clipLimit: options_clipLimit, | ||||||
| 			noteEachClipsLimit: options_noteEachClipsLimit, | 			noteEachClipsLimit: options_noteEachClipsLimit, | ||||||
|  | 			userListLimit: options_userListLimit, | ||||||
|  | 			userEachUserListsLimit: options_userEachUserListsLimit, | ||||||
| 		}, | 		}, | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue