parent
							
								
									d2204fd5c8
								
							
						
					
					
						commit
						d1807ee5dc
					
				
					 6 changed files with 48 additions and 2 deletions
				
			
		|  | @ -73,8 +73,9 @@ You should also include the user name that made the change. | |||
| - Push notification of Antenna note @tamaina | ||||
| - AVIF support @tamaina | ||||
| - Add Cloudflare Turnstile CAPTCHA support @CyberRex0 | ||||
| - 非モデレーターでも、権限を持つロールをアサインされたユーザーはインスタンスの招待コードを発行できるように | ||||
| - 非モデレーターでも、権限を持つロールをアサインされたユーザーはカスタム絵文字の追加、編集、削除を行えるように | ||||
| - 非モデレーターでも、権限を持つロールをアサインされたユーザーはインスタンスの招待コードを発行できるように @syuilo | ||||
| - 非モデレーターでも、権限を持つロールをアサインされたユーザーはカスタム絵文字の追加、編集、削除を行えるように @syuilo | ||||
| - ハードワードミュートの最大文字数を設定可能に @syuilo | ||||
| - Server: signToActivityPubGet is set to true by default @syuilo | ||||
| - Server: improve syslog performance @syuilo | ||||
| - Server: Use undici instead of node-fetch and got @tamaina | ||||
|  |  | |||
|  | @ -962,6 +962,7 @@ _role: | |||
|     canManageCustomEmojis: "カスタム絵文字の管理" | ||||
|     driveCapacity: "ドライブ容量" | ||||
|     antennaMax: "アンテナの作成可能数" | ||||
|     wordMuteMax: "ワードミュートの最大文字数" | ||||
|   _condition: | ||||
|     isLocal: "ローカルユーザー" | ||||
|     isRemote: "リモートユーザー" | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ export type RoleOptions = { | |||
| 	canManageCustomEmojis: boolean; | ||||
| 	driveCapacityMb: number; | ||||
| 	antennaLimit: number; | ||||
| 	wordMuteLimit: number; | ||||
| }; | ||||
| 
 | ||||
| export const DEFAULT_ROLE: RoleOptions = { | ||||
|  | @ -30,6 +31,7 @@ export const DEFAULT_ROLE: RoleOptions = { | |||
| 	canManageCustomEmojis: false, | ||||
| 	driveCapacityMb: 100, | ||||
| 	antennaLimit: 5, | ||||
| 	wordMuteLimit: 200, | ||||
| }; | ||||
| 
 | ||||
| @Injectable() | ||||
|  | @ -187,6 +189,7 @@ export class RoleService implements OnApplicationShutdown { | |||
| 			canManageCustomEmojis: getOptionValues('canManageCustomEmojis').some(x => x === true), | ||||
| 			driveCapacityMb: Math.max(...getOptionValues('driveCapacityMb')), | ||||
| 			antennaLimit: Math.max(...getOptionValues('antennaLimit')), | ||||
| 			wordMuteLimit: Math.max(...getOptionValues('wordMuteLimit')), | ||||
| 		}; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ import { UserFollowingService } from '@/core/UserFollowingService.js'; | |||
| import { AccountUpdateService } from '@/core/AccountUpdateService.js'; | ||||
| import { HashtagService } from '@/core/HashtagService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { RoleService } from '@/core/RoleService.js'; | ||||
| import { ApiError } from '../../error.js'; | ||||
| 
 | ||||
| export const meta = { | ||||
|  | @ -62,6 +63,12 @@ export const meta = { | |||
| 			code: 'INVALID_REGEXP', | ||||
| 			id: '0d786918-10df-41cd-8f33-8dec7d9a89a5', | ||||
| 		}, | ||||
| 
 | ||||
| 		tooManyMutedWords: { | ||||
| 			message: 'Too many muted words.', | ||||
| 			code: 'TOO_MANY_MUTED_WORDS', | ||||
| 			id: '010665b1-a211-42d2-bc64-8f6609d79785', | ||||
| 		}, | ||||
| 	}, | ||||
| 
 | ||||
| 	res: { | ||||
|  | @ -144,6 +151,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | |||
| 		private userFollowingService: UserFollowingService, | ||||
| 		private accountUpdateService: AccountUpdateService, | ||||
| 		private hashtagService: HashtagService, | ||||
| 		private roleService: RoleService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, _user, token) => { | ||||
| 			const user = await this.usersRepository.findOneByOrFail({ id: _user.id }); | ||||
|  | @ -163,6 +171,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | |||
| 			if (ps.avatarId !== undefined) updates.avatarId = ps.avatarId; | ||||
| 			if (ps.bannerId !== undefined) updates.bannerId = ps.bannerId; | ||||
| 			if (ps.mutedWords !== undefined) { | ||||
| 				// TODO: ちゃんと数える
 | ||||
| 				const length = JSON.stringify(ps.mutedWords).length; | ||||
| 				if (length > (await this.roleService.getUserRoleOptions(user.id)).antennaLimit) { | ||||
| 					throw new ApiError(meta.errors.tooManyMutedWords); | ||||
| 				} | ||||
| 
 | ||||
| 				// validate regular expression syntax
 | ||||
| 				ps.mutedWords.filter(x => !Array.isArray(x)).forEach(x => { | ||||
| 					const regexp = x.match(/^\/(.+)\/(.*)$/); | ||||
|  |  | |||
|  | @ -127,6 +127,19 @@ | |||
| 					</MkInput> | ||||
| 				</div> | ||||
| 			</MkFolder> | ||||
| 
 | ||||
| 			<MkFolder> | ||||
| 				<template #label>{{ i18n.ts._role._options.wordMuteMax }}</template> | ||||
| 				<template #suffix>{{ options_wordMuteLimit_useDefault ? i18n.ts._role.useBaseValue : (options_wordMuteLimit_value) }}</template> | ||||
| 				<div class="_gaps"> | ||||
| 					<MkSwitch v-model="options_wordMuteLimit_useDefault" :readonly="readonly"> | ||||
| 						<template #label>{{ i18n.ts._role.useBaseValue }}</template> | ||||
| 					</MkSwitch> | ||||
| 					<MkInput v-model="options_wordMuteLimit_value" :disabled="options_wordMuteLimit_useDefault" type="number" :readonly="readonly"> | ||||
| 						<template #suffix>chars</template> | ||||
| 					</MkInput> | ||||
| 				</div> | ||||
| 			</MkFolder> | ||||
| 		</div> | ||||
| 	</FormSlot> | ||||
| 
 | ||||
|  | @ -194,6 +207,8 @@ let options_driveCapacityMb_useDefault = $ref(role?.options?.driveCapacityMb?.us | |||
| let options_driveCapacityMb_value = $ref(role?.options?.driveCapacityMb?.value ?? 0); | ||||
| let options_antennaLimit_useDefault = $ref(role?.options?.antennaLimit?.useDefault ?? true); | ||||
| let options_antennaLimit_value = $ref(role?.options?.antennaLimit?.value ?? 0); | ||||
| let options_wordMuteLimit_useDefault = $ref(role?.options?.wordMuteLimit?.useDefault ?? true); | ||||
| let options_wordMuteLimit_value = $ref(role?.options?.wordMuteLimit?.value ?? 0); | ||||
| 
 | ||||
| if (_DEV_) { | ||||
| 	watch($$(condFormula), () => { | ||||
|  | @ -210,6 +225,7 @@ function getOptions() { | |||
| 		canManageCustomEmojis: { useDefault: options_canManageCustomEmojis_useDefault, value: options_canManageCustomEmojis_value }, | ||||
| 		driveCapacityMb: { useDefault: options_driveCapacityMb_useDefault, value: options_driveCapacityMb_value }, | ||||
| 		antennaLimit: { useDefault: options_antennaLimit_useDefault, value: options_antennaLimit_value }, | ||||
| 		wordMuteLimit: { useDefault: options_wordMuteLimit_useDefault, value: options_wordMuteLimit_value }, | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -62,6 +62,15 @@ | |||
| 							<MkInput v-model="options_antennaLimit" type="number"> | ||||
| 							</MkInput> | ||||
| 						</MkFolder> | ||||
| 
 | ||||
| 						<MkFolder> | ||||
| 							<template #label>{{ i18n.ts._role._options.wordMuteMax }}</template> | ||||
| 							<template #suffix>{{ options_wordMuteLimit }}</template> | ||||
| 							<MkInput v-model="options_wordMuteLimit" type="number"> | ||||
| 								<template #suffix>chars</template> | ||||
| 							</MkInput> | ||||
| 						</MkFolder> | ||||
| 
 | ||||
| 						<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton> | ||||
| 					</div> | ||||
| 				</MkFolder> | ||||
|  | @ -101,6 +110,7 @@ let options_canInvite = $ref(instance.baseRole.canInvite); | |||
| let options_canManageCustomEmojis = $ref(instance.baseRole.canManageCustomEmojis); | ||||
| let options_driveCapacityMb = $ref(instance.baseRole.driveCapacityMb); | ||||
| let options_antennaLimit = $ref(instance.baseRole.antennaLimit); | ||||
| let options_wordMuteLimit = $ref(instance.baseRole.wordMuteLimit); | ||||
| 
 | ||||
| async function updateBaseRole() { | ||||
| 	await os.apiWithDialog('admin/roles/update-default-role-override', { | ||||
|  | @ -112,6 +122,7 @@ async function updateBaseRole() { | |||
| 			canManageCustomEmojis: options_canManageCustomEmojis, | ||||
| 			driveCapacityMb: options_driveCapacityMb, | ||||
| 			antennaLimit: options_antennaLimit, | ||||
| 			wordMuteLimit: options_wordMuteLimit, | ||||
| 		}, | ||||
| 	}); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue