mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-05-24 12:44:04 +02:00
enhance: Add canCreateChannel role policy (#17121)
* Initial plan * Add canCreateChannel role policy to control channel creation Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> * Add canCreateChannel to getUserPolicies return value Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> * Add canCreateChannel translations for en-US and ja-JP Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> * Add canCreateChannel to misskey-js rolePolicies array Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> * Add frontend UI for canCreateChannel policy configuration Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> * fix: build autogen files * 🎨 * migrate * fix: unnecessary changes to non-Japanese locales --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
This commit is contained in:
@@ -2122,6 +2122,7 @@ _role:
|
|||||||
canSearchNotes: "ノート検索の利用"
|
canSearchNotes: "ノート検索の利用"
|
||||||
canSearchUsers: "ユーザー検索の利用"
|
canSearchUsers: "ユーザー検索の利用"
|
||||||
canUseTranslator: "翻訳機能の利用"
|
canUseTranslator: "翻訳機能の利用"
|
||||||
|
canCreateChannel: "チャンネルの作成"
|
||||||
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
|
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
|
||||||
canImportAntennas: "アンテナのインポートを許可"
|
canImportAntennas: "アンテナのインポートを許可"
|
||||||
canImportBlocking: "ブロックのインポートを許可"
|
canImportBlocking: "ブロックのインポートを許可"
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export type RolePolicies = {
|
|||||||
canSearchUsers: boolean;
|
canSearchUsers: boolean;
|
||||||
canUseTranslator: boolean;
|
canUseTranslator: boolean;
|
||||||
canHideAds: boolean;
|
canHideAds: boolean;
|
||||||
|
canCreateChannel: boolean;
|
||||||
driveCapacityMb: number;
|
driveCapacityMb: number;
|
||||||
maxFileSizeMb: number;
|
maxFileSizeMb: number;
|
||||||
alwaysMarkNsfw: boolean;
|
alwaysMarkNsfw: boolean;
|
||||||
@@ -88,6 +89,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
|||||||
canSearchUsers: true,
|
canSearchUsers: true,
|
||||||
canUseTranslator: true,
|
canUseTranslator: true,
|
||||||
canHideAds: false,
|
canHideAds: false,
|
||||||
|
canCreateChannel: true,
|
||||||
driveCapacityMb: 100,
|
driveCapacityMb: 100,
|
||||||
maxFileSizeMb: 30,
|
maxFileSizeMb: 30,
|
||||||
alwaysMarkNsfw: false,
|
alwaysMarkNsfw: false,
|
||||||
@@ -410,6 +412,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
|||||||
canSearchUsers: calc('canSearchUsers', vs => vs.some(v => v === true)),
|
canSearchUsers: calc('canSearchUsers', vs => vs.some(v => v === true)),
|
||||||
canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)),
|
canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)),
|
||||||
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
|
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
|
||||||
|
canCreateChannel: calc('canCreateChannel', vs => vs.some(v => v === true)),
|
||||||
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
|
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
|
||||||
maxFileSizeMb: calc('maxFileSizeMb', vs => Math.max(...vs)),
|
maxFileSizeMb: calc('maxFileSizeMb', vs => Math.max(...vs)),
|
||||||
alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)),
|
alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)),
|
||||||
|
|||||||
@@ -224,6 +224,10 @@ export const packedRolePoliciesSchema = {
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
|
canCreateChannel: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
driveCapacityMb: {
|
driveCapacityMb: {
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ export const meta = {
|
|||||||
|
|
||||||
kind: 'write:channels',
|
kind: 'write:channels',
|
||||||
|
|
||||||
|
requiredRolePolicy: 'canCreateChannel',
|
||||||
|
|
||||||
limit: {
|
limit: {
|
||||||
duration: ms('1hour'),
|
duration: ms('1hour'),
|
||||||
max: 10,
|
max: 10,
|
||||||
|
|||||||
@@ -161,6 +161,16 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
</XFolder>
|
</XFolder>
|
||||||
|
|
||||||
|
<XFolder v-if="matchQuery([i18n.ts._role._options.canCreateChannel, 'canCreateChannel'])" v-model:policyMeta="policyMetaModel.canCreateChannel" :isBaseRole="isBaseRole" :readonly="readonly">
|
||||||
|
<template #label>{{ i18n.ts._role._options.canCreateChannel }}</template>
|
||||||
|
<template #suffix>{{ valuesModel.canCreateChannel ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
<template #default="{ disabled }">
|
||||||
|
<MkSwitch v-model="valuesModel.canCreateChannel" :disabled="disabled">
|
||||||
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</template>
|
||||||
|
</XFolder>
|
||||||
|
|
||||||
<XFolder v-if="matchQuery([i18n.ts._role._options.driveCapacity, 'driveCapacityMb'])" v-model:policyMeta="policyMetaModel.driveCapacityMb" :isBaseRole="isBaseRole" :readonly="readonly">
|
<XFolder v-if="matchQuery([i18n.ts._role._options.driveCapacity, 'driveCapacityMb'])" v-model:policyMeta="policyMetaModel.driveCapacityMb" :isBaseRole="isBaseRole" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role._options.driveCapacity }}</template>
|
<template #label>{{ i18n.ts._role._options.driveCapacity }}</template>
|
||||||
<template #valueText>{{ valuesModel.driveCapacityMb }}MB</template>
|
<template #valueText>{{ valuesModel.driveCapacityMb }}MB</template>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="tab === 'owned'" class="_gaps">
|
<div v-else-if="tab === 'owned'" class="_gaps">
|
||||||
<MkButton type="routerLink" primary rounded to="/channels/new"><i class="ti ti-plus"></i> {{ i18n.ts.createNew }}</MkButton>
|
<MkButton v-if="$i?.policies.canCreateChannel" type="routerLink" primary rounded to="/channels/new"><i class="ti ti-plus"></i> {{ i18n.ts.createNew }}</MkButton>
|
||||||
<MkPagination v-slot="{items}" :paginator="ownedPaginator">
|
<MkPagination v-slot="{items}" :paginator="ownedPaginator">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/>
|
<MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/>
|
||||||
@@ -74,6 +74,7 @@ import { definePage } from '@/page.js';
|
|||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { useRouter } from '@/router.js';
|
import { useRouter } from '@/router.js';
|
||||||
import { Paginator } from '@/utility/paginator.js';
|
import { Paginator } from '@/utility/paginator.js';
|
||||||
|
import { $i } from '@/i.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|||||||
@@ -8177,6 +8177,10 @@ export interface Locale extends ILocale {
|
|||||||
* 翻訳機能の利用
|
* 翻訳機能の利用
|
||||||
*/
|
*/
|
||||||
"canUseTranslator": string;
|
"canUseTranslator": string;
|
||||||
|
/**
|
||||||
|
* チャンネルの作成
|
||||||
|
*/
|
||||||
|
"canCreateChannel": string;
|
||||||
/**
|
/**
|
||||||
* アイコンデコレーションの最大取付個数
|
* アイコンデコレーションの最大取付個数
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3466,7 +3466,7 @@ type RoleLite = components['schemas']['RoleLite'];
|
|||||||
type RolePolicies = components['schemas']['RolePolicies'];
|
type RolePolicies = components['schemas']['RolePolicies'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const rolePolicies: readonly ["gtlAvailable", "ltlAvailable", "canPublicNote", "mentionLimit", "canInvite", "inviteLimit", "inviteLimitCycle", "inviteExpirationTime", "canManageCustomEmojis", "canManageAvatarDecorations", "canSearchNotes", "canSearchUsers", "canUseTranslator", "canHideAds", "driveCapacityMb", "maxFileSizeMb", "alwaysMarkNsfw", "canUpdateBioMedia", "pinLimit", "antennaLimit", "wordMuteLimit", "webhookLimit", "clipLimit", "noteEachClipsLimit", "userListLimit", "userEachUserListsLimit", "rateLimitFactor", "avatarDecorationLimit", "canImportAntennas", "canImportBlocking", "canImportFollowing", "canImportMuting", "canImportUserLists", "chatAvailability", "uploadableFileTypes", "noteDraftLimit", "scheduledNoteLimit", "watermarkAvailable"];
|
export const rolePolicies: readonly ["gtlAvailable", "ltlAvailable", "canPublicNote", "mentionLimit", "canInvite", "inviteLimit", "inviteLimitCycle", "inviteExpirationTime", "canManageCustomEmojis", "canManageAvatarDecorations", "canSearchNotes", "canSearchUsers", "canUseTranslator", "canHideAds", "canCreateChannel", "driveCapacityMb", "maxFileSizeMb", "alwaysMarkNsfw", "canUpdateBioMedia", "pinLimit", "antennaLimit", "wordMuteLimit", "webhookLimit", "clipLimit", "noteEachClipsLimit", "userListLimit", "userEachUserListsLimit", "rateLimitFactor", "avatarDecorationLimit", "canImportAntennas", "canImportBlocking", "canImportFollowing", "canImportMuting", "canImportUserLists", "chatAvailability", "uploadableFileTypes", "noteDraftLimit", "scheduledNoteLimit", "watermarkAvailable"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type RolesListResponse = operations['roles___list']['responses']['200']['content']['application/json'];
|
type RolesListResponse = operations['roles___list']['responses']['200']['content']['application/json'];
|
||||||
|
|||||||
@@ -5322,6 +5322,7 @@ export type components = {
|
|||||||
canSearchUsers: boolean;
|
canSearchUsers: boolean;
|
||||||
canUseTranslator: boolean;
|
canUseTranslator: boolean;
|
||||||
canHideAds: boolean;
|
canHideAds: boolean;
|
||||||
|
canCreateChannel: boolean;
|
||||||
driveCapacityMb: number;
|
driveCapacityMb: number;
|
||||||
maxFileSizeMb: number;
|
maxFileSizeMb: number;
|
||||||
uploadableFileTypes: string[];
|
uploadableFileTypes: string[];
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ export const rolePolicies = [
|
|||||||
'canSearchUsers',
|
'canSearchUsers',
|
||||||
'canUseTranslator',
|
'canUseTranslator',
|
||||||
'canHideAds',
|
'canHideAds',
|
||||||
|
'canCreateChannel',
|
||||||
'driveCapacityMb',
|
'driveCapacityMb',
|
||||||
'maxFileSizeMb',
|
'maxFileSizeMb',
|
||||||
'alwaysMarkNsfw',
|
'alwaysMarkNsfw',
|
||||||
|
|||||||
Reference in New Issue
Block a user