parent
							
								
									9936088200
								
							
						
					
					
						commit
						7b7faf1e84
					
				
					 9 changed files with 65 additions and 12 deletions
				
			
		|  | @ -957,6 +957,7 @@ _role: | ||||||
|     gtlAvailable: "グローバルタイムラインの閲覧" |     gtlAvailable: "グローバルタイムラインの閲覧" | ||||||
|     ltlAvailable: "ローカルタイムラインの閲覧" |     ltlAvailable: "ローカルタイムラインの閲覧" | ||||||
|     canPublicNote: "パブリック投稿の許可" |     canPublicNote: "パブリック投稿の許可" | ||||||
|  |     canInvite: "インスタンス招待コードの発行" | ||||||
|     driveCapacity: "ドライブ容量" |     driveCapacity: "ドライブ容量" | ||||||
|     antennaMax: "アンテナの作成可能数" |     antennaMax: "アンテナの作成可能数" | ||||||
|   _condition: |   _condition: | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ export type RoleOptions = { | ||||||
| 	gtlAvailable: boolean; | 	gtlAvailable: boolean; | ||||||
| 	ltlAvailable: boolean; | 	ltlAvailable: boolean; | ||||||
| 	canPublicNote: boolean; | 	canPublicNote: boolean; | ||||||
|  | 	canInvite: boolean; | ||||||
| 	driveCapacityMb: number; | 	driveCapacityMb: number; | ||||||
| 	antennaLimit: number; | 	antennaLimit: number; | ||||||
| }; | }; | ||||||
|  | @ -24,6 +25,7 @@ export const DEFAULT_ROLE: RoleOptions = { | ||||||
| 	gtlAvailable: true, | 	gtlAvailable: true, | ||||||
| 	ltlAvailable: true, | 	ltlAvailable: true, | ||||||
| 	canPublicNote: true, | 	canPublicNote: true, | ||||||
|  | 	canInvite: false, | ||||||
| 	driveCapacityMb: 100, | 	driveCapacityMb: 100, | ||||||
| 	antennaLimit: 5, | 	antennaLimit: 5, | ||||||
| }; | }; | ||||||
|  | @ -179,6 +181,7 @@ export class RoleService implements OnApplicationShutdown { | ||||||
| 			gtlAvailable: getOptionValues('gtlAvailable').some(x => x === true), | 			gtlAvailable: getOptionValues('gtlAvailable').some(x => x === true), | ||||||
| 			ltlAvailable: getOptionValues('ltlAvailable').some(x => x === true), | 			ltlAvailable: getOptionValues('ltlAvailable').some(x => x === true), | ||||||
| 			canPublicNote: getOptionValues('canPublicNote').some(x => x === true), | 			canPublicNote: getOptionValues('canPublicNote').some(x => x === true), | ||||||
|  | 			canInvite: getOptionValues('canInvite').some(x => x === true), | ||||||
| 			driveCapacityMb: Math.max(...getOptionValues('driveCapacityMb')), | 			driveCapacityMb: Math.max(...getOptionValues('driveCapacityMb')), | ||||||
| 			antennaLimit: Math.max(...getOptionValues('antennaLimit')), | 			antennaLimit: Math.max(...getOptionValues('antennaLimit')), | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
|  | @ -37,7 +37,7 @@ import * as ep___admin_federation_updateInstance from './endpoints/admin/federat | ||||||
| import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js'; | import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js'; | ||||||
| import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js'; | import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js'; | ||||||
| import * as ep___admin_getUserIps from './endpoints/admin/get-user-ips.js'; | import * as ep___admin_getUserIps from './endpoints/admin/get-user-ips.js'; | ||||||
| import * as ep___admin_invite from './endpoints/admin/invite.js'; | import * as ep___invite from './endpoints/invite.js'; | ||||||
| import * as ep___admin_promo_create from './endpoints/admin/promo/create.js'; | import * as ep___admin_promo_create from './endpoints/admin/promo/create.js'; | ||||||
| import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js'; | import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js'; | ||||||
| import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js'; | import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js'; | ||||||
|  | @ -371,7 +371,7 @@ const $admin_federation_updateInstance: Provider = { provide: 'ep:admin/federati | ||||||
| const $admin_getIndexStats: Provider = { provide: 'ep:admin/get-index-stats', useClass: ep___admin_getIndexStats.default }; | const $admin_getIndexStats: Provider = { provide: 'ep:admin/get-index-stats', useClass: ep___admin_getIndexStats.default }; | ||||||
| const $admin_getTableStats: Provider = { provide: 'ep:admin/get-table-stats', useClass: ep___admin_getTableStats.default }; | const $admin_getTableStats: Provider = { provide: 'ep:admin/get-table-stats', useClass: ep___admin_getTableStats.default }; | ||||||
| const $admin_getUserIps: Provider = { provide: 'ep:admin/get-user-ips', useClass: ep___admin_getUserIps.default }; | const $admin_getUserIps: Provider = { provide: 'ep:admin/get-user-ips', useClass: ep___admin_getUserIps.default }; | ||||||
| const $admin_invite: Provider = { provide: 'ep:admin/invite', useClass: ep___admin_invite.default }; | const $invite: Provider = { provide: 'ep:invite', useClass: ep___invite.default }; | ||||||
| const $admin_promo_create: Provider = { provide: 'ep:admin/promo/create', useClass: ep___admin_promo_create.default }; | const $admin_promo_create: Provider = { provide: 'ep:admin/promo/create', useClass: ep___admin_promo_create.default }; | ||||||
| const $admin_queue_clear: Provider = { provide: 'ep:admin/queue/clear', useClass: ep___admin_queue_clear.default }; | const $admin_queue_clear: Provider = { provide: 'ep:admin/queue/clear', useClass: ep___admin_queue_clear.default }; | ||||||
| const $admin_queue_deliverDelayed: Provider = { provide: 'ep:admin/queue/deliver-delayed', useClass: ep___admin_queue_deliverDelayed.default }; | const $admin_queue_deliverDelayed: Provider = { provide: 'ep:admin/queue/deliver-delayed', useClass: ep___admin_queue_deliverDelayed.default }; | ||||||
|  | @ -709,7 +709,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention | ||||||
| 		$admin_getIndexStats, | 		$admin_getIndexStats, | ||||||
| 		$admin_getTableStats, | 		$admin_getTableStats, | ||||||
| 		$admin_getUserIps, | 		$admin_getUserIps, | ||||||
| 		$admin_invite, | 		$invite, | ||||||
| 		$admin_promo_create, | 		$admin_promo_create, | ||||||
| 		$admin_queue_clear, | 		$admin_queue_clear, | ||||||
| 		$admin_queue_deliverDelayed, | 		$admin_queue_deliverDelayed, | ||||||
|  | @ -1041,7 +1041,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention | ||||||
| 		$admin_getIndexStats, | 		$admin_getIndexStats, | ||||||
| 		$admin_getTableStats, | 		$admin_getTableStats, | ||||||
| 		$admin_getUserIps, | 		$admin_getUserIps, | ||||||
| 		$admin_invite, | 		$invite, | ||||||
| 		$admin_promo_create, | 		$admin_promo_create, | ||||||
| 		$admin_queue_clear, | 		$admin_queue_clear, | ||||||
| 		$admin_queue_deliverDelayed, | 		$admin_queue_deliverDelayed, | ||||||
|  |  | ||||||
|  | @ -36,7 +36,7 @@ import * as ep___admin_federation_updateInstance from './endpoints/admin/federat | ||||||
| import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js'; | import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js'; | ||||||
| import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js'; | import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js'; | ||||||
| import * as ep___admin_getUserIps from './endpoints/admin/get-user-ips.js'; | import * as ep___admin_getUserIps from './endpoints/admin/get-user-ips.js'; | ||||||
| import * as ep___admin_invite from './endpoints/admin/invite.js'; | import * as ep___invite from './endpoints/invite.js'; | ||||||
| import * as ep___admin_promo_create from './endpoints/admin/promo/create.js'; | import * as ep___admin_promo_create from './endpoints/admin/promo/create.js'; | ||||||
| import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js'; | import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js'; | ||||||
| import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js'; | import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js'; | ||||||
|  | @ -368,7 +368,7 @@ const eps = [ | ||||||
| 	['admin/get-index-stats', ep___admin_getIndexStats], | 	['admin/get-index-stats', ep___admin_getIndexStats], | ||||||
| 	['admin/get-table-stats', ep___admin_getTableStats], | 	['admin/get-table-stats', ep___admin_getTableStats], | ||||||
| 	['admin/get-user-ips', ep___admin_getUserIps], | 	['admin/get-user-ips', ep___admin_getUserIps], | ||||||
| 	['admin/invite', ep___admin_invite], | 	['invite', ep___invite], | ||||||
| 	['admin/promo/create', ep___admin_promo_create], | 	['admin/promo/create', ep___admin_promo_create], | ||||||
| 	['admin/queue/clear', ep___admin_queue_clear], | 	['admin/queue/clear', ep___admin_queue_clear], | ||||||
| 	['admin/queue/deliver-delayed', ep___admin_queue_deliverDelayed], | 	['admin/queue/deliver-delayed', ep___admin_queue_deliverDelayed], | ||||||
|  |  | ||||||
|  | @ -4,12 +4,12 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||||
| import type { RegistrationTicketsRepository } from '@/models/index.js'; | import type { RegistrationTicketsRepository } from '@/models/index.js'; | ||||||
| import { IdService } from '@/core/IdService.js'; | import { IdService } from '@/core/IdService.js'; | ||||||
| import { DI } from '@/di-symbols.js'; | import { DI } from '@/di-symbols.js'; | ||||||
|  | import { RoleService } from '@/core/RoleService.js'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['admin'], | 	tags: ['meta'], | ||||||
| 
 | 
 | ||||||
| 	requireCredential: true, | 	requireCredential: true, | ||||||
| 	requireModerator: true, |  | ||||||
| 
 | 
 | ||||||
| 	res: { | 	res: { | ||||||
| 		type: 'object', | 		type: 'object', | ||||||
|  | @ -39,9 +39,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | ||||||
| 		@Inject(DI.registrationTicketsRepository) | 		@Inject(DI.registrationTicketsRepository) | ||||||
| 		private registrationTicketsRepository: RegistrationTicketsRepository, | 		private registrationTicketsRepository: RegistrationTicketsRepository, | ||||||
| 
 | 
 | ||||||
|  | 		private roleService: RoleService, | ||||||
| 		private idService: IdService, | 		private idService: IdService, | ||||||
| 	) { | 	) { | ||||||
| 		super(meta, paramDef, async () => { | 		super(meta, paramDef, async (ps, me) => { | ||||||
|  | 			const role = await this.roleService.getUserRoleOptions(me.id); | ||||||
|  | 			if (!me.isRoot && !role.canInvite) { | ||||||
|  | 				throw new Error('access denied'); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			const code = rndstr({ | 			const code = rndstr({ | ||||||
| 				length: 8, | 				length: 8, | ||||||
| 				chars: '2-9A-HJ-NP-Z', // [0-9A-Z] w/o [01IO] (32 patterns)
 | 				chars: '2-9A-HJ-NP-Z', // [0-9A-Z] w/o [01IO] (32 patterns)
 | ||||||
|  | @ -80,7 +80,7 @@ const menuDef = $computed(() => [{ | ||||||
| 		action: lookup, | 		action: lookup, | ||||||
| 	}, ...(instance.disableRegistration ? [{ | 	}, ...(instance.disableRegistration ? [{ | ||||||
| 		type: 'button', | 		type: 'button', | ||||||
| 		icon: 'ti ti-user', | 		icon: 'ti ti-user-plus', | ||||||
| 		text: i18n.ts.invite, | 		text: i18n.ts.invite, | ||||||
| 		action: invite, | 		action: invite, | ||||||
| 	}] : [])], | 	}] : [])], | ||||||
|  | @ -223,7 +223,7 @@ provideMetadataReceiver((info) => { | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const invite = () => { | const invite = () => { | ||||||
| 	os.api('admin/invite').then(x => { | 	os.api('invite').then(x => { | ||||||
| 		os.alert({ | 		os.alert({ | ||||||
| 			type: 'info', | 			type: 'info', | ||||||
| 			text: x.code, | 			text: x.code, | ||||||
|  |  | ||||||
|  | @ -77,6 +77,19 @@ | ||||||
| 				</div> | 				</div> | ||||||
| 			</MkFolder> | 			</MkFolder> | ||||||
| 
 | 
 | ||||||
|  | 			<MkFolder> | ||||||
|  | 				<template #label>{{ i18n.ts._role._options.canInvite }}</template> | ||||||
|  | 				<template #suffix>{{ options_canInvite_useDefault ? i18n.ts._role.useBaseValue : (options_canInvite_value ? i18n.ts.yes : i18n.ts.no) }}</template> | ||||||
|  | 				<div class="_gaps"> | ||||||
|  | 					<MkSwitch v-model="options_canInvite_useDefault" :readonly="readonly"> | ||||||
|  | 						<template #label>{{ i18n.ts._role.useBaseValue }}</template> | ||||||
|  | 					</MkSwitch> | ||||||
|  | 					<MkSwitch v-model="options_canInvite_value" :disabled="options_canInvite_useDefault" :readonly="readonly"> | ||||||
|  | 						<template #label>{{ i18n.ts.enable }}</template> | ||||||
|  | 					</MkSwitch> | ||||||
|  | 				</div> | ||||||
|  | 			</MkFolder> | ||||||
|  | 
 | ||||||
| 			<MkFolder> | 			<MkFolder> | ||||||
| 				<template #label>{{ i18n.ts._role._options.driveCapacity }}</template> | 				<template #label>{{ i18n.ts._role._options.driveCapacity }}</template> | ||||||
| 				<template #suffix>{{ options_driveCapacityMb_useDefault ? i18n.ts._role.useBaseValue : (options_driveCapacityMb_value + 'MB') }}</template> | 				<template #suffix>{{ options_driveCapacityMb_useDefault ? i18n.ts._role.useBaseValue : (options_driveCapacityMb_value + 'MB') }}</template> | ||||||
|  | @ -160,6 +173,8 @@ let options_ltlAvailable_useDefault = $ref(role?.options?.ltlAvailable?.useDefau | ||||||
| let options_ltlAvailable_value = $ref(role?.options?.ltlAvailable?.value ?? false); | let options_ltlAvailable_value = $ref(role?.options?.ltlAvailable?.value ?? false); | ||||||
| let options_canPublicNote_useDefault = $ref(role?.options?.canPublicNote?.useDefault ?? true); | let options_canPublicNote_useDefault = $ref(role?.options?.canPublicNote?.useDefault ?? true); | ||||||
| let options_canPublicNote_value = $ref(role?.options?.canPublicNote?.value ?? false); | let options_canPublicNote_value = $ref(role?.options?.canPublicNote?.value ?? false); | ||||||
|  | let options_canInvite_useDefault = $ref(role?.options?.canInvite?.useDefault ?? true); | ||||||
|  | let options_canInvite_value = $ref(role?.options?.canInvite?.value ?? false); | ||||||
| let options_driveCapacityMb_useDefault = $ref(role?.options?.driveCapacityMb?.useDefault ?? true); | let options_driveCapacityMb_useDefault = $ref(role?.options?.driveCapacityMb?.useDefault ?? true); | ||||||
| let options_driveCapacityMb_value = $ref(role?.options?.driveCapacityMb?.value ?? 0); | let options_driveCapacityMb_value = $ref(role?.options?.driveCapacityMb?.value ?? 0); | ||||||
| let options_antennaLimit_useDefault = $ref(role?.options?.antennaLimit?.useDefault ?? true); | let options_antennaLimit_useDefault = $ref(role?.options?.antennaLimit?.useDefault ?? true); | ||||||
|  | @ -176,6 +191,7 @@ function getOptions() { | ||||||
| 		gtlAvailable: { useDefault: options_gtlAvailable_useDefault, value: options_gtlAvailable_value }, | 		gtlAvailable: { useDefault: options_gtlAvailable_useDefault, value: options_gtlAvailable_value }, | ||||||
| 		ltlAvailable: { useDefault: options_ltlAvailable_useDefault, value: options_ltlAvailable_value }, | 		ltlAvailable: { useDefault: options_ltlAvailable_useDefault, value: options_ltlAvailable_value }, | ||||||
| 		canPublicNote: { useDefault: options_canPublicNote_useDefault, value: options_canPublicNote_value }, | 		canPublicNote: { useDefault: options_canPublicNote_useDefault, value: options_canPublicNote_value }, | ||||||
|  | 		canInvite: { useDefault: options_canInvite_useDefault, value: options_canInvite_value }, | ||||||
| 		driveCapacityMb: { useDefault: options_driveCapacityMb_useDefault, value: options_driveCapacityMb_value }, | 		driveCapacityMb: { useDefault: options_driveCapacityMb_useDefault, value: options_driveCapacityMb_value }, | ||||||
| 		antennaLimit: { useDefault: options_antennaLimit_useDefault, value: options_antennaLimit_value }, | 		antennaLimit: { useDefault: options_antennaLimit_useDefault, value: options_antennaLimit_value }, | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | @ -32,6 +32,14 @@ | ||||||
| 							</MkSwitch> | 							</MkSwitch> | ||||||
| 						</MkFolder> | 						</MkFolder> | ||||||
| 
 | 
 | ||||||
|  | 						<MkFolder> | ||||||
|  | 							<template #label>{{ i18n.ts._role._options.canInvite }}</template> | ||||||
|  | 							<template #suffix>{{ options_canInvite ? i18n.ts.yes : i18n.ts.no }}</template> | ||||||
|  | 							<MkSwitch v-model="options_canInvite"> | ||||||
|  | 								<template #label>{{ i18n.ts.enable }}</template> | ||||||
|  | 							</MkSwitch> | ||||||
|  | 						</MkFolder> | ||||||
|  | 
 | ||||||
| 						<MkFolder> | 						<MkFolder> | ||||||
| 							<template #label>{{ i18n.ts._role._options.driveCapacity }}</template> | 							<template #label>{{ i18n.ts._role._options.driveCapacity }}</template> | ||||||
| 							<template #suffix>{{ options_driveCapacityMb }}MB</template> | 							<template #suffix>{{ options_driveCapacityMb }}MB</template> | ||||||
|  | @ -81,6 +89,7 @@ const roles = await os.api('admin/roles/list'); | ||||||
| let options_gtlAvailable = $ref(instance.baseRole.gtlAvailable); | let options_gtlAvailable = $ref(instance.baseRole.gtlAvailable); | ||||||
| let options_ltlAvailable = $ref(instance.baseRole.ltlAvailable); | let options_ltlAvailable = $ref(instance.baseRole.ltlAvailable); | ||||||
| let options_canPublicNote = $ref(instance.baseRole.canPublicNote); | let options_canPublicNote = $ref(instance.baseRole.canPublicNote); | ||||||
|  | let options_canInvite = $ref(instance.baseRole.canInvite); | ||||||
| let options_driveCapacityMb = $ref(instance.baseRole.driveCapacityMb); | let options_driveCapacityMb = $ref(instance.baseRole.driveCapacityMb); | ||||||
| let options_antennaLimit = $ref(instance.baseRole.antennaLimit); | let options_antennaLimit = $ref(instance.baseRole.antennaLimit); | ||||||
| 
 | 
 | ||||||
|  | @ -90,6 +99,7 @@ async function updateBaseRole() { | ||||||
| 			gtlAvailable: options_gtlAvailable, | 			gtlAvailable: options_gtlAvailable, | ||||||
| 			ltlAvailable: options_ltlAvailable, | 			ltlAvailable: options_ltlAvailable, | ||||||
| 			canPublicNote: options_canPublicNote, | 			canPublicNote: options_canPublicNote, | ||||||
|  | 			canInvite: options_canInvite, | ||||||
| 			driveCapacityMb: options_driveCapacityMb, | 			driveCapacityMb: options_driveCapacityMb, | ||||||
| 			antennaLimit: options_antennaLimit, | 			antennaLimit: options_antennaLimit, | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ import * as os from '@/os'; | ||||||
| import { instance } from '@/instance'; | import { instance } from '@/instance'; | ||||||
| import { host } from '@/config'; | import { host } from '@/config'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
|  | import { $i } from '@/account'; | ||||||
| 
 | 
 | ||||||
| export function openInstanceMenu(ev: MouseEvent) { | export function openInstanceMenu(ev: MouseEvent) { | ||||||
| 	os.popupMenu([{ | 	os.popupMenu([{ | ||||||
|  | @ -46,7 +47,23 @@ export function openInstanceMenu(ev: MouseEvent) { | ||||||
| 			to: '/clicker', | 			to: '/clicker', | ||||||
| 			text: '🍪👈', | 			text: '🍪👈', | ||||||
| 			icon: 'ti ti-cookie', | 			icon: 'ti ti-cookie', | ||||||
| 		}], | 		}, ($i && ($i.isRoot || $i.role.canInvite) && instance.disableRegistration) ? { | ||||||
|  | 			text: i18n.ts.invite, | ||||||
|  | 			icon: 'ti ti-user-plus', | ||||||
|  | 			action: () => { | ||||||
|  | 				os.api('invite').then(x => { | ||||||
|  | 					os.alert({ | ||||||
|  | 						type: 'info', | ||||||
|  | 						text: x.code, | ||||||
|  | 					}); | ||||||
|  | 				}).catch(err => { | ||||||
|  | 					os.alert({ | ||||||
|  | 						type: 'error', | ||||||
|  | 						text: err, | ||||||
|  | 					}); | ||||||
|  | 				}); | ||||||
|  | 			}, | ||||||
|  | 		} : undefined], | ||||||
| 	}, null, { | 	}, null, { | ||||||
| 		text: i18n.ts.help, | 		text: i18n.ts.help, | ||||||
| 		icon: 'ti ti-question-circle', | 		icon: 'ti ti-question-circle', | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue