(add) ロール制御
This commit is contained in:
		
							parent
							
								
									8608df20b2
								
							
						
					
					
						commit
						7694d17b2e
					
				|  | @ -1665,6 +1665,7 @@ export interface Locale { | |||
|             "gtlAvailable": string; | ||||
|             "ltlAvailable": string; | ||||
|             "canPublicNote": string; | ||||
|             "canScheduleNote": string; | ||||
|             "canInvite": string; | ||||
|             "inviteLimit": string; | ||||
|             "inviteLimitCycle": string; | ||||
|  |  | |||
|  | @ -1574,6 +1574,7 @@ _role: | |||
|     gtlAvailable: "グローバルタイムラインの閲覧" | ||||
|     ltlAvailable: "ローカルタイムラインの閲覧" | ||||
|     canPublicNote: "パブリック投稿の許可" | ||||
|     canScheduleNote: "予約投稿の許可" | ||||
|     canInvite: "サーバー招待コードの発行" | ||||
|     inviteLimit: "招待コードの作成可能数" | ||||
|     inviteLimitCycle: "招待コードの発行間隔" | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ export type RolePolicies = { | |||
| 	gtlAvailable: boolean; | ||||
| 	ltlAvailable: boolean; | ||||
| 	canPublicNote: boolean; | ||||
| 	canScheduleNote: boolean; | ||||
| 	canInvite: boolean; | ||||
| 	inviteLimit: number; | ||||
| 	inviteLimitCycle: number; | ||||
|  | @ -53,6 +54,7 @@ export const DEFAULT_POLICIES: RolePolicies = { | |||
| 	gtlAvailable: true, | ||||
| 	ltlAvailable: true, | ||||
| 	canPublicNote: true, | ||||
| 	canScheduleNote: true, | ||||
| 	canInvite: false, | ||||
| 	inviteLimit: 0, | ||||
| 	inviteLimitCycle: 60 * 24 * 7, | ||||
|  | @ -303,6 +305,7 @@ export class RoleService implements OnApplicationShutdown { | |||
| 			gtlAvailable: calc('gtlAvailable', vs => vs.some(v => v === true)), | ||||
| 			ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)), | ||||
| 			canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)), | ||||
| 			canScheduleNote: calc('canScheduleNote', vs => vs.some(v => v === true)), | ||||
| 			canInvite: calc('canInvite', vs => vs.some(v => v === true)), | ||||
| 			inviteLimit: calc('inviteLimit', vs => Math.max(...vs)), | ||||
| 			inviteLimitCycle: calc('inviteLimitCycle', vs => Math.max(...vs)), | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; | |||
| import { NoteCreateService } from '@/core/NoteCreateService.js'; | ||||
| import { QueueService } from '@/core/QueueService.js'; | ||||
| import { IdService } from '@/core/IdService.js'; | ||||
| import { RoleService } from '@/core/RoleService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { isPureRenote } from '@/misc/is-pure-renote.js'; | ||||
| import { ApiError } from '../../error.js'; | ||||
|  | @ -132,6 +133,12 @@ export const meta = { | |||
| 			code: 'NO_SUCH_SCHEDULE', | ||||
| 			id: '44dee229-8da1-4a61-856d-e3a4bbc12032', | ||||
| 		}, | ||||
| 		rolePermissionDenied: { | ||||
| 			message: 'You are not assigned to a required role.', | ||||
| 			code: 'ROLE_PERMISSION_DENIED', | ||||
| 			kind: 'permission', | ||||
| 			id: '7f86f06f-7e15-4057-8561-f4b6d4ac755a', | ||||
| 		}, | ||||
| 	}, | ||||
| } as const; | ||||
| 
 | ||||
|  | @ -234,6 +241,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 		private noteEntityService: NoteEntityService, | ||||
| 		private noteCreateService: NoteCreateService, | ||||
| 
 | ||||
| 		private roleService: RoleService, | ||||
| 		private queueService: QueueService, | ||||
|     private idService: IdService, | ||||
| 	) { | ||||
|  | @ -375,6 +383,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 			}; | ||||
| 
 | ||||
| 			if (ps.schedule) { | ||||
| 				const canCreateScheduledNote = (await this.roleService.getUserPolicies(me.id)).canScheduleNote; | ||||
| 				if (!canCreateScheduledNote) { | ||||
| 					throw new ApiError(meta.errors.rolePermissionDenied); | ||||
| 				} | ||||
| 
 | ||||
| 				if (!ps.schedule.expiresAt) { | ||||
| 					throw new ApiError(meta.errors.specifyScheduleDate); | ||||
| 				} | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ export const meta = { | |||
| 	tags: ['notes'], | ||||
| 
 | ||||
| 	requireCredential: true, | ||||
| 	requireRolePolicy: 'canScheduleNote', | ||||
| 	res: { | ||||
| 		type: 'array', | ||||
| 		optional: false, nullable: false, | ||||
|  |  | |||
|  | @ -929,13 +929,13 @@ function openOtherSettingsMenu(ev: MouseEvent) { | |||
| 		text: i18n.ts.reactionAcceptance, | ||||
| 		icon: reactionAcceptanceIcon, | ||||
| 		action: toggleReactionAcceptance, | ||||
| 	}, { | ||||
| 	}, ($i.policies?.canScheduleNote) ? { | ||||
| 		type: 'button', | ||||
| 		text: i18n.ts.schedulePost, | ||||
| 		icon: 'ti ti-calendar-time', | ||||
| 		indicate: (schedule != null), | ||||
| 		action: toggleSchedule, | ||||
| 	}, null, { | ||||
| 	} : undefined, ...(($i.policies?.canScheduleNote) ? [ null, { | ||||
| 		type: 'button', | ||||
| 		text: i18n.ts._schedulePost.list, | ||||
| 		icon: 'ti ti-calendar-event', | ||||
|  | @ -944,7 +944,7 @@ function openOtherSettingsMenu(ev: MouseEvent) { | |||
| 			emit('cancel'); | ||||
| 			listSchedulePost(); | ||||
| 		}, | ||||
| 	}], ev.currentTarget ?? ev.target, { | ||||
| 	}] : [])], ev.currentTarget ?? ev.target, { | ||||
| 		align: 'right', | ||||
| 	}); | ||||
| } | ||||
|  |  | |||
|  | @ -61,6 +61,7 @@ export const ROLE_POLICIES = [ | |||
| 	'gtlAvailable', | ||||
| 	'ltlAvailable', | ||||
| 	'canPublicNote', | ||||
| 	'canScheduleNote', | ||||
| 	'canInvite', | ||||
| 	'inviteLimit', | ||||
| 	'inviteLimitCycle', | ||||
|  |  | |||
|  | @ -174,6 +174,7 @@ export const navbarItemDef = reactive({ | |||
| 	scheduledNotes: { | ||||
| 		title: i18n.ts._schedulePost.list, | ||||
| 		icon: 'ti ti-calendar-event', | ||||
| 		show: computed(() => $i && $i.policies?.canScheduleNote), | ||||
| 		action: (ev) => { | ||||
| 			os.listSchedulePost(); | ||||
| 		}, | ||||
|  |  | |||
|  | @ -160,6 +160,26 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| 				</div> | ||||
| 			</MkFolder> | ||||
| 
 | ||||
| 			<MkFolder v-if="matchQuery([i18n.ts._role._options.canScheduleNote, 'canScheduleNote'])"> | ||||
| 				<template #label>{{ i18n.ts._role._options.canScheduleNote }}</template> | ||||
| 				<template #suffix> | ||||
| 					<span v-if="role.policies.canScheduleNote.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span> | ||||
| 					<span v-else>{{ role.policies.canScheduleNote.value ? i18n.ts.yes : i18n.ts.no }}</span> | ||||
| 					<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.canScheduleNote)"></i></span> | ||||
| 				</template> | ||||
| 				<div class="_gaps"> | ||||
| 					<MkSwitch v-model="role.policies.canScheduleNote.useDefault" :readonly="readonly"> | ||||
| 						<template #label>{{ i18n.ts._role.useBaseValue }}</template> | ||||
| 					</MkSwitch> | ||||
| 					<MkSwitch v-model="role.policies.canScheduleNote.value" :disabled="role.policies.canScheduleNote.useDefault" :readonly="readonly"> | ||||
| 						<template #label>{{ i18n.ts.enable }}</template> | ||||
| 					</MkSwitch> | ||||
| 					<MkRange v-model="role.policies.canScheduleNote.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> | ||||
| 						<template #label>{{ i18n.ts._role.priority }}</template> | ||||
| 					</MkRange> | ||||
| 				</div> | ||||
| 			</MkFolder> | ||||
| 
 | ||||
| 			<MkFolder v-if="matchQuery([i18n.ts._role._options.canInvite, 'canInvite'])"> | ||||
| 				<template #label>{{ i18n.ts._role._options.canInvite }}</template> | ||||
| 				<template #suffix> | ||||
|  | @ -549,7 +569,7 @@ import MkSwitch from '@/components/MkSwitch.vue'; | |||
| import MkRange from '@/components/MkRange.vue'; | ||||
| import FormSlot from '@/components/form/slot.vue'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { ROLE_POLICIES } from '@/const'; | ||||
| import { ROLE_POLICIES } from '@/const.js'; | ||||
| import { instance } from '@/instance.js'; | ||||
| import { deepClone } from '@/scripts/clone.js'; | ||||
| 
 | ||||
|  |  | |||
|  | @ -48,6 +48,14 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| 							</MkSwitch> | ||||
| 						</MkFolder> | ||||
| 
 | ||||
| 						<MkFolder v-if="matchQuery([i18n.ts._role._options.canScheduleNote, 'canScheduleNote'])"> | ||||
| 							<template #label>{{ i18n.ts._role._options.canScheduleNote }}</template> | ||||
| 							<template #suffix>{{ policies.canScheduleNote ? i18n.ts.yes : i18n.ts.no }}</template> | ||||
| 							<MkSwitch v-model="policies.canScheduleNote"> | ||||
| 								<template #label>{{ i18n.ts.enable }}</template> | ||||
| 							</MkSwitch> | ||||
| 						</MkFolder> | ||||
| 
 | ||||
| 						<MkFolder v-if="matchQuery([i18n.ts._role._options.canInvite, 'canInvite'])"> | ||||
| 							<template #label>{{ i18n.ts._role._options.canInvite }}</template> | ||||
| 							<template #suffix>{{ policies.canInvite ? i18n.ts.yes : i18n.ts.no }}</template> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue