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 | ||||
| - Webhookの作成可能数を設定可能に @syuilo | ||||
| - Server: signToActivityPubGet is set to true by default @syuilo | ||||
|  |  | |||
|  | @ -966,6 +966,8 @@ _role: | |||
|     webhookMax: "Webhookの作成可能数" | ||||
|     clipMax: "クリップの作成可能数" | ||||
|     noteEachClipsMax: "クリップ内のノートの最大数" | ||||
|     userListMax: "ユーザーリストの作成可能数" | ||||
|     userEachUserListsMax: "ユーザーリスト内のユーザーの最大数" | ||||
|   _condition: | ||||
|     isLocal: "ローカルユーザー" | ||||
|     isRemote: "リモートユーザー" | ||||
|  |  | |||
|  | @ -25,6 +25,8 @@ export type RoleOptions = { | |||
| 	webhookLimit: number; | ||||
| 	clipLimit: number; | ||||
| 	noteEachClipsLimit: number; | ||||
| 	userListLimit: number; | ||||
| 	userEachUserListsLimit: number; | ||||
| }; | ||||
| 
 | ||||
| export const DEFAULT_ROLE: RoleOptions = { | ||||
|  | @ -39,6 +41,8 @@ export const DEFAULT_ROLE: RoleOptions = { | |||
| 	webhookLimit: 3, | ||||
| 	clipLimit: 10, | ||||
| 	noteEachClipsLimit: 200, | ||||
| 	userListLimit: 10, | ||||
| 	userEachUserListsLimit: 50, | ||||
| }; | ||||
| 
 | ||||
| @Injectable() | ||||
|  | @ -212,6 +216,8 @@ export class RoleService implements OnApplicationShutdown { | |||
| 			webhookLimit: Math.max(...getOptionValues('webhookLimit')), | ||||
| 			clipLimit: Math.max(...getOptionValues('clipLimit')), | ||||
| 			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 { ProxyAccountService } from '@/core/ProxyAccountService.js'; | ||||
| import { bindThis } from '@/decorators.js'; | ||||
| import { RoleService } from '@/core/RoleService.js'; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class UserListService { | ||||
|  | @ -23,13 +24,21 @@ export class UserListService { | |||
| 		private userEntityService: UserEntityService, | ||||
| 		private idService: IdService, | ||||
| 		private userFollowingService: UserFollowingService, | ||||
| 		private roleService: RoleService, | ||||
| 		private globalEventServie: GlobalEventService, | ||||
| 		private proxyAccountService: ProxyAccountService, | ||||
| 	) { | ||||
| 	} | ||||
| 
 | ||||
| 	@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({ | ||||
| 			id: this.idService.genId(), | ||||
| 			createdAt: new Date(), | ||||
|  |  | |||
|  | @ -10,10 +10,10 @@ import { DownloadService } from '@/core/DownloadService.js'; | |||
| import { UserListService } from '@/core/UserListService.js'; | ||||
| import { IdService } from '@/core/IdService.js'; | ||||
| import { UtilityService } from '@/core/UtilityService.js'; | ||||
| import { bindThis } from '@/decorators.js'; | ||||
| import { QueueLoggerService } from '../QueueLoggerService.js'; | ||||
| import type Bull from 'bull'; | ||||
| import type { DbUserImportJobData } from '../types.js'; | ||||
| import { bindThis } from '@/decorators.js'; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class ImportUserListsProcessorService { | ||||
|  | @ -102,7 +102,7 @@ export class ImportUserListsProcessorService { | |||
| 
 | ||||
| 				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) { | ||||
| 				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 { UserListEntityService } from '@/core/entities/UserListEntityService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { ApiError } from '@/server/api/error'; | ||||
| import { RoleService } from '@/core/RoleService.js'; | ||||
| 
 | ||||
| export const meta = { | ||||
| 	tags: ['lists'], | ||||
|  | @ -20,6 +22,14 @@ export const meta = { | |||
| 		optional: false, nullable: false, | ||||
| 		ref: 'UserList', | ||||
| 	}, | ||||
| 
 | ||||
| 	errors: { | ||||
| 		tooManyUserLists: { | ||||
| 			message: 'You cannot create user list any more.', | ||||
| 			code: 'TOO_MANY_USERLISTS', | ||||
| 			id: '0cf21a28-7715-4f39-a20d-777bfdb8d138', | ||||
| 		}, | ||||
| 	}, | ||||
| } as const; | ||||
| 
 | ||||
| export const paramDef = { | ||||
|  | @ -39,8 +49,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | |||
| 
 | ||||
| 		private userListEntityService: UserListEntityService, | ||||
| 		private idService: IdService, | ||||
| 		private roleService: RoleService, | ||||
| 	) { | ||||
| 		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({ | ||||
| 				id: this.idService.genId(), | ||||
| 				createdAt: new Date(), | ||||
|  |  | |||
|  | @ -111,7 +111,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | |||
| 			} | ||||
| 
 | ||||
| 			// Push the user
 | ||||
| 			await this.userListService.push(user, userList); | ||||
| 			await this.userListService.push(user, userList, me); | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -176,6 +176,30 @@ | |||
| 					</MkInput> | ||||
| 				</div> | ||||
| 			</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> | ||||
| 	</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_noteEachClipsLimit_useDefault = $ref(role?.options?.noteEachClipsLimit?.useDefault ?? true); | ||||
| 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_) { | ||||
| 	watch($$(condFormula), () => { | ||||
|  | @ -271,6 +299,8 @@ function getOptions() { | |||
| 		webhookLimit: { useDefault: options_webhookLimit_useDefault, value: options_webhookLimit_value }, | ||||
| 		clipLimit: { useDefault: options_clipLimit_useDefault, value: options_clipLimit_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> | ||||
| 						</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> | ||||
| 					</div> | ||||
| 				</MkFolder> | ||||
|  | @ -135,6 +149,8 @@ let options_wordMuteLimit = $ref(instance.baseRole.wordMuteLimit); | |||
| let options_webhookLimit = $ref(instance.baseRole.webhookLimit); | ||||
| let options_clipLimit = $ref(instance.baseRole.clipLimit); | ||||
| let options_noteEachClipsLimit = $ref(instance.baseRole.noteEachClipsLimit); | ||||
| let options_userListLimit = $ref(instance.baseRole.userListLimit); | ||||
| let options_userEachUserListsLimit = $ref(instance.baseRole.userEachUserListsLimit); | ||||
| 
 | ||||
| async function updateBaseRole() { | ||||
| 	await os.apiWithDialog('admin/roles/update-default-role-override', { | ||||
|  | @ -150,6 +166,8 @@ async function updateBaseRole() { | |||
| 			webhookLimit: options_webhookLimit, | ||||
| 			clipLimit: options_clipLimit, | ||||
| 			noteEachClipsLimit: options_noteEachClipsLimit, | ||||
| 			userListLimit: options_userListLimit, | ||||
| 			userEachUserListsLimit: options_userEachUserListsLimit, | ||||
| 		}, | ||||
| 	}); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue