mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-11-26 20:53:09 +02:00
refactor: rename role.options -> role.policies
This commit is contained in:
parent
518b3e2f73
commit
81f11d8f86
53 changed files with 254 additions and 232 deletions
|
@ -952,6 +952,7 @@ _role:
|
||||||
isPublic: "ロールを公開"
|
isPublic: "ロールを公開"
|
||||||
descriptionOfIsPublic: "ロールにアサインされたユーザーを誰でも見ることができます。また、ユーザーのプロフィールでこのロールが表示されます。"
|
descriptionOfIsPublic: "ロールにアサインされたユーザーを誰でも見ることができます。また、ユーザーのプロフィールでこのロールが表示されます。"
|
||||||
options: "オプション"
|
options: "オプション"
|
||||||
|
policies: "ポリシー"
|
||||||
baseRole: "ベースロール"
|
baseRole: "ベースロール"
|
||||||
useBaseValue: "ベースロールの値を使用"
|
useBaseValue: "ベースロールの値を使用"
|
||||||
chooseRoleToAssign: "アサインするロールを選択"
|
chooseRoleToAssign: "アサインするロールを選択"
|
||||||
|
|
13
packages/backend/migration/1673783015567-Policies.js
Normal file
13
packages/backend/migration/1673783015567-Policies.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
export class Policies1673783015567 {
|
||||||
|
name = 'Policies1673783015567'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "role" RENAME COLUMN "options" TO "policies"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "defaultRoleOverride" TO "policies"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "policies" TO "defaultRoleOverride"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "role" RENAME COLUMN "policies" TO "options"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -479,8 +479,8 @@ export class DriveService {
|
||||||
if (user && !isLink) {
|
if (user && !isLink) {
|
||||||
const usage = await this.driveFileEntityService.calcDriveUsageOf(user);
|
const usage = await this.driveFileEntityService.calcDriveUsageOf(user);
|
||||||
|
|
||||||
const role = await this.roleService.getUserRoleOptions(user.id);
|
const policies = await this.roleService.getUserPolicies(user.id);
|
||||||
const driveCapacity = 1024 * 1024 * role.driveCapacityMb;
|
const driveCapacity = 1024 * 1024 * policies.driveCapacityMb;
|
||||||
this.registerLogger.debug('drive capacity override applied');
|
this.registerLogger.debug('drive capacity override applied');
|
||||||
this.registerLogger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
|
this.registerLogger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ export class NoteCreateService {
|
||||||
if (data.channel != null) data.localOnly = true;
|
if (data.channel != null) data.localOnly = true;
|
||||||
|
|
||||||
if (data.visibility === 'public' && data.channel == null) {
|
if (data.visibility === 'public' && data.channel == null) {
|
||||||
if ((await this.roleService.getUserRoleOptions(user.id)).canPublicNote === false) {
|
if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) {
|
||||||
data.visibility = 'home';
|
data.visibility = 'home';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ export class NotePiningService {
|
||||||
|
|
||||||
const pinings = await this.userNotePiningsRepository.findBy({ userId: user.id });
|
const pinings = await this.userNotePiningsRepository.findBy({ userId: user.id });
|
||||||
|
|
||||||
if (pinings.length >= (await this.roleService.getUserRoleOptions(user.id)).pinLimit) {
|
if (pinings.length >= (await this.roleService.getUserPolicies(user.id)).pinLimit) {
|
||||||
throw new IdentifiableError('15a018eb-58e5-4da1-93be-330fcc5e4e1a', 'You can not pin notes any more.');
|
throw new IdentifiableError('15a018eb-58e5-4da1-93be-330fcc5e4e1a', 'You can not pin notes any more.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { StreamMessages } from '@/server/api/stream/types.js';
|
import { StreamMessages } from '@/server/api/stream/types.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
|
||||||
export type RoleOptions = {
|
export type RolePolicies = {
|
||||||
gtlAvailable: boolean;
|
gtlAvailable: boolean;
|
||||||
ltlAvailable: boolean;
|
ltlAvailable: boolean;
|
||||||
canPublicNote: boolean;
|
canPublicNote: boolean;
|
||||||
|
@ -31,7 +31,7 @@ export type RoleOptions = {
|
||||||
rateLimitFactor: number;
|
rateLimitFactor: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_ROLE: RoleOptions = {
|
export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
gtlAvailable: true,
|
gtlAvailable: true,
|
||||||
ltlAvailable: true,
|
ltlAvailable: true,
|
||||||
canPublicNote: true,
|
canPublicNote: true,
|
||||||
|
@ -195,26 +195,26 @@ export class RoleService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async getUserRoleOptions(userId: User['id'] | null): Promise<RoleOptions> {
|
public async getUserPolicies(userId: User['id'] | null): Promise<RolePolicies> {
|
||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
const baseRoleOptions = { ...DEFAULT_ROLE, ...meta.defaultRoleOverride };
|
const basePolicies = { ...DEFAULT_POLICIES, ...meta.policies };
|
||||||
|
|
||||||
if (userId == null) return baseRoleOptions;
|
if (userId == null) return basePolicies;
|
||||||
|
|
||||||
const roles = await this.getUserRoles(userId);
|
const roles = await this.getUserRoles(userId);
|
||||||
|
|
||||||
function calc<T extends keyof RoleOptions>(name: T, aggregate: (values: RoleOptions[T][]) => RoleOptions[T]) {
|
function calc<T extends keyof RolePolicies>(name: T, aggregate: (values: RolePolicies[T][]) => RolePolicies[T]) {
|
||||||
if (roles.length === 0) return baseRoleOptions[name];
|
if (roles.length === 0) return basePolicies[name];
|
||||||
|
|
||||||
const options = roles.map(role => role.options[name] ?? { priority: 0, useDefault: true });
|
const policies = roles.map(role => role.policies[name] ?? { priority: 0, useDefault: true });
|
||||||
|
|
||||||
const p2 = options.filter(option => option.priority === 2);
|
const p2 = policies.filter(policy => policy.priority === 2);
|
||||||
if (p2.length > 0) return aggregate(p2.map(option => option.useDefault ? baseRoleOptions[name] : option.value));
|
if (p2.length > 0) return aggregate(p2.map(policy => policy.useDefault ? basePolicies[name] : policy.value));
|
||||||
|
|
||||||
const p1 = options.filter(option => option.priority === 1);
|
const p1 = policies.filter(policy => policy.priority === 1);
|
||||||
if (p1.length > 0) return aggregate(p2.map(option => option.useDefault ? baseRoleOptions[name] : option.value));
|
if (p1.length > 0) return aggregate(p2.map(policy => policy.useDefault ? basePolicies[name] : policy.value));
|
||||||
|
|
||||||
return aggregate(options.map(option => option.useDefault ? baseRoleOptions[name] : option.value));
|
return aggregate(policies.map(policy => policy.useDefault ? basePolicies[name] : policy.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -35,7 +35,7 @@ export class UserListService {
|
||||||
const currentCount = await this.userListJoiningsRepository.countBy({
|
const currentCount = await this.userListJoiningsRepository.countBy({
|
||||||
userListId: list.id,
|
userListId: list.id,
|
||||||
});
|
});
|
||||||
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).userEachUserListsLimit) {
|
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
|
||||||
throw new Error('Too many users');
|
throw new Error('Too many users');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import type { Packed } from '@/misc/schema.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { Role } from '@/models/entities/Role.js';
|
import type { Role } from '@/models/entities/Role.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { DEFAULT_ROLE } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -40,9 +40,9 @@ export class RoleEntityService {
|
||||||
roleId: role.id,
|
roleId: role.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const roleOptions = { ...role.options };
|
const policies = { ...role.policies };
|
||||||
for (const [k, v] of Object.entries(DEFAULT_ROLE)) {
|
for (const [k, v] of Object.entries(DEFAULT_POLICIES)) {
|
||||||
if (roleOptions[k] == null) roleOptions[k] = {
|
if (policies[k] == null) policies[k] = {
|
||||||
useDefault: true,
|
useDefault: true,
|
||||||
priority: 0,
|
priority: 0,
|
||||||
value: v,
|
value: v,
|
||||||
|
@ -62,7 +62,7 @@ export class RoleEntityService {
|
||||||
isAdministrator: role.isAdministrator,
|
isAdministrator: role.isAdministrator,
|
||||||
isModerator: role.isModerator,
|
isModerator: role.isModerator,
|
||||||
canEditMembersByModerator: role.canEditMembersByModerator,
|
canEditMembersByModerator: role.canEditMembersByModerator,
|
||||||
options: roleOptions,
|
policies: policies,
|
||||||
usersCount: assigns.length,
|
usersCount: assigns.length,
|
||||||
...(opts.detail ? {
|
...(opts.detail ? {
|
||||||
users: this.userEntityService.packMany(assigns.map(x => x.userId), me),
|
users: this.userEntityService.packMany(assigns.map(x => x.userId), me),
|
||||||
|
|
|
@ -423,7 +423,7 @@ export class UserEntityService implements OnModuleInit {
|
||||||
bannerUrl: user.banner ? this.driveFileEntityService.getPublicUrl(user.banner, false) : null,
|
bannerUrl: user.banner ? this.driveFileEntityService.getPublicUrl(user.banner, false) : null,
|
||||||
bannerBlurhash: user.banner?.blurhash ?? null,
|
bannerBlurhash: user.banner?.blurhash ?? null,
|
||||||
isLocked: user.isLocked,
|
isLocked: user.isLocked,
|
||||||
isSilenced: this.roleService.getUserRoleOptions(user.id).then(r => !r.canPublicNote),
|
isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote),
|
||||||
isSuspended: user.isSuspended ?? falsy,
|
isSuspended: user.isSuspended ?? falsy,
|
||||||
description: profile!.description,
|
description: profile!.description,
|
||||||
location: profile!.location,
|
location: profile!.location,
|
||||||
|
@ -496,7 +496,7 @@ export class UserEntityService implements OnModuleInit {
|
||||||
} : {}),
|
} : {}),
|
||||||
|
|
||||||
...(opts.includeSecrets ? {
|
...(opts.includeSecrets ? {
|
||||||
role: this.roleService.getUserRoleOptions(user.id),
|
policies: this.roleService.getUserPolicies(user.id),
|
||||||
email: profile!.email,
|
email: profile!.email,
|
||||||
emailVerified: profile!.emailVerified,
|
emailVerified: profile!.emailVerified,
|
||||||
securityKeysList: profile!.twoFactorEnabled
|
securityKeysList: profile!.twoFactorEnabled
|
||||||
|
|
|
@ -458,5 +458,5 @@ export class Meta {
|
||||||
@Column('jsonb', {
|
@Column('jsonb', {
|
||||||
default: { },
|
default: { },
|
||||||
})
|
})
|
||||||
public defaultRoleOverride: Record<string, any>;
|
public policies: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ export class Role {
|
||||||
@Column('jsonb', {
|
@Column('jsonb', {
|
||||||
default: { },
|
default: { },
|
||||||
})
|
})
|
||||||
public options: Record<string, {
|
public policies: Record<string, {
|
||||||
useDefault: boolean;
|
useDefault: boolean;
|
||||||
priority: number;
|
priority: number;
|
||||||
value: any;
|
value: any;
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import NotesChart from '@/core/chart/charts/notes.js';
|
import NotesChart from '@/core/chart/charts/notes.js';
|
||||||
import UsersChart from '@/core/chart/charts/users.js';
|
import UsersChart from '@/core/chart/charts/users.js';
|
||||||
import { DEFAULT_ROLE } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
||||||
|
|
||||||
const nodeinfo2_1path = '/nodeinfo/2.1';
|
const nodeinfo2_1path = '/nodeinfo/2.1';
|
||||||
|
@ -74,7 +74,7 @@ export class NodeinfoServerService {
|
||||||
|
|
||||||
const proxyAccount = meta.proxyAccountId ? await this.userEntityService.pack(meta.proxyAccountId).catch(() => null) : null;
|
const proxyAccount = meta.proxyAccountId ? await this.userEntityService.pack(meta.proxyAccountId).catch(() => null) : null;
|
||||||
|
|
||||||
const baseRoleOptions = { ...DEFAULT_ROLE, ...meta.defaultRoleOverride };
|
const basePolicies = { ...DEFAULT_POLICIES, ...meta.policies };
|
||||||
|
|
||||||
return {
|
return {
|
||||||
software: {
|
software: {
|
||||||
|
@ -105,8 +105,8 @@ export class NodeinfoServerService {
|
||||||
repositoryUrl: meta.repositoryUrl,
|
repositoryUrl: meta.repositoryUrl,
|
||||||
feedbackUrl: meta.feedbackUrl,
|
feedbackUrl: meta.feedbackUrl,
|
||||||
disableRegistration: meta.disableRegistration,
|
disableRegistration: meta.disableRegistration,
|
||||||
disableLocalTimeline: !baseRoleOptions.ltlAvailable,
|
disableLocalTimeline: !basePolicies.ltlAvailable,
|
||||||
disableGlobalTimeline: !baseRoleOptions.gtlAvailable,
|
disableGlobalTimeline: !basePolicies.gtlAvailable,
|
||||||
emailRequiredForSignup: meta.emailRequiredForSignup,
|
emailRequiredForSignup: meta.emailRequiredForSignup,
|
||||||
enableHcaptcha: meta.enableHcaptcha,
|
enableHcaptcha: meta.enableHcaptcha,
|
||||||
enableRecaptcha: meta.enableRecaptcha,
|
enableRecaptcha: meta.enableRecaptcha,
|
||||||
|
|
|
@ -225,7 +225,7 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 毎リクエスト計算するのもあれだしキャッシュしたい
|
// TODO: 毎リクエスト計算するのもあれだしキャッシュしたい
|
||||||
const factor = user ? (await this.roleService.getUserRoleOptions(user.id)).rateLimitFactor : 1;
|
const factor = user ? (await this.roleService.getUserPolicies(user.id)).rateLimitFactor : 1;
|
||||||
|
|
||||||
// Rate limit
|
// Rate limit
|
||||||
await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable<string> }, limitActor, factor).catch(err => {
|
await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable<string> }, limitActor, factor).catch(err => {
|
||||||
|
@ -274,9 +274,9 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ep.meta.requireRoleOption != null && !user!.isRoot) {
|
if (ep.meta.requireRolePolicy != null && !user!.isRoot) {
|
||||||
const myRole = await this.roleService.getUserRoleOptions(user!.id);
|
const policies = await this.roleService.getUserPolicies(user!.id);
|
||||||
if (!myRole[ep.meta.requireRoleOption]) {
|
if (!policies[ep.meta.requireRolePolicy]) {
|
||||||
throw new ApiError({
|
throw new ApiError({
|
||||||
message: 'You are not assigned to a required role.',
|
message: 'You are not assigned to a required role.',
|
||||||
code: 'ROLE_PERMISSION_DENIED',
|
code: 'ROLE_PERMISSION_DENIED',
|
||||||
|
|
|
@ -65,7 +65,7 @@ import * as ep___admin_roles_show from './endpoints/admin/roles/show.js';
|
||||||
import * as ep___admin_roles_update from './endpoints/admin/roles/update.js';
|
import * as ep___admin_roles_update from './endpoints/admin/roles/update.js';
|
||||||
import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
|
import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
|
||||||
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
|
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
|
||||||
import * as ep___admin_roles_updateDefaultRoleOverride from './endpoints/admin/roles/update-default-role-override.js';
|
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
|
||||||
import * as ep___announcements from './endpoints/announcements.js';
|
import * as ep___announcements from './endpoints/announcements.js';
|
||||||
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
||||||
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
||||||
|
@ -399,7 +399,7 @@ const $admin_roles_show: Provider = { provide: 'ep:admin/roles/show', useClass:
|
||||||
const $admin_roles_update: Provider = { provide: 'ep:admin/roles/update', useClass: ep___admin_roles_update.default };
|
const $admin_roles_update: Provider = { provide: 'ep:admin/roles/update', useClass: ep___admin_roles_update.default };
|
||||||
const $admin_roles_assign: Provider = { provide: 'ep:admin/roles/assign', useClass: ep___admin_roles_assign.default };
|
const $admin_roles_assign: Provider = { provide: 'ep:admin/roles/assign', useClass: ep___admin_roles_assign.default };
|
||||||
const $admin_roles_unassign: Provider = { provide: 'ep:admin/roles/unassign', useClass: ep___admin_roles_unassign.default };
|
const $admin_roles_unassign: Provider = { provide: 'ep:admin/roles/unassign', useClass: ep___admin_roles_unassign.default };
|
||||||
const $admin_roles_updateDefaultRoleOverride: Provider = { provide: 'ep:admin/roles/update-default-role-override', useClass: ep___admin_roles_updateDefaultRoleOverride.default };
|
const $admin_roles_updateDefaultPolicies: Provider = { provide: 'ep:admin/roles/update-default-policies', useClass: ep___admin_roles_updateDefaultPolicies.default };
|
||||||
const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default };
|
const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default };
|
||||||
const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default };
|
const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default };
|
||||||
const $antennas_delete: Provider = { provide: 'ep:antennas/delete', useClass: ep___antennas_delete.default };
|
const $antennas_delete: Provider = { provide: 'ep:antennas/delete', useClass: ep___antennas_delete.default };
|
||||||
|
@ -737,7 +737,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
||||||
$admin_roles_update,
|
$admin_roles_update,
|
||||||
$admin_roles_assign,
|
$admin_roles_assign,
|
||||||
$admin_roles_unassign,
|
$admin_roles_unassign,
|
||||||
$admin_roles_updateDefaultRoleOverride,
|
$admin_roles_updateDefaultPolicies,
|
||||||
$announcements,
|
$announcements,
|
||||||
$antennas_create,
|
$antennas_create,
|
||||||
$antennas_delete,
|
$antennas_delete,
|
||||||
|
@ -1069,7 +1069,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
|
||||||
$admin_roles_update,
|
$admin_roles_update,
|
||||||
$admin_roles_assign,
|
$admin_roles_assign,
|
||||||
$admin_roles_unassign,
|
$admin_roles_unassign,
|
||||||
$admin_roles_updateDefaultRoleOverride,
|
$admin_roles_updateDefaultPolicies,
|
||||||
$announcements,
|
$announcements,
|
||||||
$antennas_create,
|
$antennas_create,
|
||||||
$antennas_delete,
|
$antennas_delete,
|
||||||
|
|
|
@ -64,7 +64,7 @@ import * as ep___admin_roles_show from './endpoints/admin/roles/show.js';
|
||||||
import * as ep___admin_roles_update from './endpoints/admin/roles/update.js';
|
import * as ep___admin_roles_update from './endpoints/admin/roles/update.js';
|
||||||
import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
|
import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js';
|
||||||
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
|
import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js';
|
||||||
import * as ep___admin_roles_updateDefaultRoleOverride from './endpoints/admin/roles/update-default-role-override.js';
|
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
|
||||||
import * as ep___announcements from './endpoints/announcements.js';
|
import * as ep___announcements from './endpoints/announcements.js';
|
||||||
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
||||||
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
||||||
|
@ -396,7 +396,7 @@ const eps = [
|
||||||
['admin/roles/update', ep___admin_roles_update],
|
['admin/roles/update', ep___admin_roles_update],
|
||||||
['admin/roles/assign', ep___admin_roles_assign],
|
['admin/roles/assign', ep___admin_roles_assign],
|
||||||
['admin/roles/unassign', ep___admin_roles_unassign],
|
['admin/roles/unassign', ep___admin_roles_unassign],
|
||||||
['admin/roles/update-default-role-override', ep___admin_roles_updateDefaultRoleOverride],
|
['admin/roles/update-default-policies', ep___admin_roles_updateDefaultPolicies],
|
||||||
['announcements', ep___announcements],
|
['announcements', ep___announcements],
|
||||||
['antennas/create', ep___antennas_create],
|
['antennas/create', ep___antennas_create],
|
||||||
['antennas/delete', ep___antennas_delete],
|
['antennas/delete', ep___antennas_delete],
|
||||||
|
@ -695,7 +695,7 @@ export interface IEndpointMeta {
|
||||||
*/
|
*/
|
||||||
readonly requireAdmin?: boolean;
|
readonly requireAdmin?: boolean;
|
||||||
|
|
||||||
readonly requireRoleOption?: string;
|
readonly requireRolePolicy?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* エンドポイントのリミテーションに関するやつ
|
* エンドポイントのリミテーションに関するやつ
|
||||||
|
|
|
@ -8,7 +8,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchFile: {
|
noSuchFile: {
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchEmoji: {
|
noSuchEmoji: {
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -10,7 +10,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchEmoji: {
|
noSuchEmoji: {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
export const meta = {
|
export const meta = {
|
||||||
secure: true,
|
secure: true,
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
|
|
@ -8,7 +8,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -8,7 +8,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -8,7 +8,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canManageCustomEmojis',
|
requireRolePolicy: 'canManageCustomEmojis',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
noSuchEmoji: {
|
noSuchEmoji: {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { DEFAULT_ROLE } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
@ -440,7 +440,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
deeplIsPro: instance.deeplIsPro,
|
deeplIsPro: instance.deeplIsPro,
|
||||||
enableIpLogging: instance.enableIpLogging,
|
enableIpLogging: instance.enableIpLogging,
|
||||||
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
||||||
baseRole: { ...DEFAULT_ROLE, ...instance.defaultRoleOverride },
|
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ export const paramDef = {
|
||||||
isModerator: { type: 'boolean' },
|
isModerator: { type: 'boolean' },
|
||||||
isAdministrator: { type: 'boolean' },
|
isAdministrator: { type: 'boolean' },
|
||||||
canEditMembersByModerator: { type: 'boolean' },
|
canEditMembersByModerator: { type: 'boolean' },
|
||||||
options: {
|
policies: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -39,7 +39,7 @@ export const paramDef = {
|
||||||
'isModerator',
|
'isModerator',
|
||||||
'isAdministrator',
|
'isAdministrator',
|
||||||
'canEditMembersByModerator',
|
'canEditMembersByModerator',
|
||||||
'options',
|
'policies',
|
||||||
],
|
],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
isAdministrator: ps.isAdministrator,
|
isAdministrator: ps.isAdministrator,
|
||||||
isModerator: ps.isModerator,
|
isModerator: ps.isModerator,
|
||||||
canEditMembersByModerator: ps.canEditMembersByModerator,
|
canEditMembersByModerator: ps.canEditMembersByModerator,
|
||||||
options: ps.options,
|
policies: ps.policies,
|
||||||
}).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0]));
|
}).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
this.globalEventService.publishInternalEvent('roleCreated', created);
|
this.globalEventService.publishInternalEvent('roleCreated', created);
|
||||||
|
|
|
@ -16,12 +16,12 @@ export const meta = {
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
options: {
|
policies: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
required: [
|
required: [
|
||||||
'options',
|
'policies',
|
||||||
],
|
],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -34,9 +34,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps) => {
|
super(meta, paramDef, async (ps) => {
|
||||||
await this.metaService.update({
|
await this.metaService.update({
|
||||||
defaultRoleOverride: ps.options,
|
policies: ps.policies,
|
||||||
});
|
});
|
||||||
this.globalEventService.publishInternalEvent('defaultRoleOverrideUpdated', ps.options);
|
this.globalEventService.publishInternalEvent('policiesUpdated', ps.policies);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -33,7 +33,7 @@ export const paramDef = {
|
||||||
isModerator: { type: 'boolean' },
|
isModerator: { type: 'boolean' },
|
||||||
isAdministrator: { type: 'boolean' },
|
isAdministrator: { type: 'boolean' },
|
||||||
canEditMembersByModerator: { type: 'boolean' },
|
canEditMembersByModerator: { type: 'boolean' },
|
||||||
options: {
|
policies: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -48,7 +48,7 @@ export const paramDef = {
|
||||||
'isModerator',
|
'isModerator',
|
||||||
'isAdministrator',
|
'isAdministrator',
|
||||||
'canEditMembersByModerator',
|
'canEditMembersByModerator',
|
||||||
'options',
|
'policies',
|
||||||
],
|
],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
isModerator: ps.isModerator,
|
isModerator: ps.isModerator,
|
||||||
isAdministrator: ps.isAdministrator,
|
isAdministrator: ps.isAdministrator,
|
||||||
canEditMembersByModerator: ps.canEditMembersByModerator,
|
canEditMembersByModerator: ps.canEditMembersByModerator,
|
||||||
options: ps.options,
|
policies: ps.policies,
|
||||||
});
|
});
|
||||||
const updated = await this.rolesRepository.findOneByOrFail({ id: ps.roleId });
|
const updated = await this.rolesRepository.findOneByOrFail({ id: ps.roleId });
|
||||||
this.globalEventService.publishInternalEvent('roleUpdated', updated);
|
this.globalEventService.publishInternalEvent('roleUpdated', updated);
|
||||||
|
|
|
@ -52,7 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const isModerator = await this.roleService.isModerator(user);
|
const isModerator = await this.roleService.isModerator(user);
|
||||||
const isSilenced = !(await this.roleService.getUserRoleOptions(user.id)).canPublicNote;
|
const isSilenced = !(await this.roleService.getUserPolicies(user.id)).canPublicNote;
|
||||||
|
|
||||||
const _me = await this.usersRepository.findOneByOrFail({ id: me.id });
|
const _me = await this.usersRepository.findOneByOrFail({ id: me.id });
|
||||||
if (!await this.roleService.isAdministrator(_me) && await this.roleService.isAdministrator(user)) {
|
if (!await this.roleService.isAdministrator(_me) && await this.roleService.isAdministrator(user)) {
|
||||||
|
@ -94,6 +94,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
lastActiveDate: user.lastActiveDate,
|
lastActiveDate: user.lastActiveDate,
|
||||||
moderationNote: profile.moderationNote,
|
moderationNote: profile.moderationNote,
|
||||||
signins,
|
signins,
|
||||||
|
policies: await this.roleService.getUserPolicies(user.id),
|
||||||
roles: await this.roleEntityService.packMany(roles, me, { detail: false }),
|
roles: await this.roleEntityService.packMany(roles, me, { detail: false }),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -92,7 +92,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
const currentAntennasCount = await this.antennasRepository.countBy({
|
const currentAntennasCount = await this.antennasRepository.countBy({
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
if (currentAntennasCount > (await this.roleService.getUserRoleOptions(me.id)).antennaLimit) {
|
if (currentAntennasCount > (await this.roleService.getUserPolicies(me.id)).antennaLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyAntennas);
|
throw new ApiError(meta.errors.tooManyAntennas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
const currentCount = await this.clipNotesRepository.countBy({
|
const currentCount = await this.clipNotesRepository.countBy({
|
||||||
clipId: clip.id,
|
clipId: clip.id,
|
||||||
});
|
});
|
||||||
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).noteEachClipsLimit) {
|
if (currentCount > (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyClipNotes);
|
throw new ApiError(meta.errors.tooManyClipNotes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
const currentCount = await this.clipsRepository.countBy({
|
const currentCount = await this.clipsRepository.countBy({
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).clipLimit) {
|
if (currentCount > (await this.roleService.getUserPolicies(me.id)).clipLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyClips);
|
throw new ApiError(meta.errors.tooManyClips);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
// Calculate drive usage
|
// Calculate drive usage
|
||||||
const usage = await this.driveFileEntityService.calcDriveUsageOf(me.id);
|
const usage = await this.driveFileEntityService.calcDriveUsageOf(me.id);
|
||||||
|
|
||||||
const myRole = await this.roleService.getUserRoleOptions(me.id);
|
const policies = await this.roleService.getUserPolicies(me.id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
capacity: 1024 * 1024 * myRole.driveCapacityMb,
|
capacity: 1024 * 1024 * policies.driveCapacityMb,
|
||||||
usage: usage,
|
usage: usage,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -173,7 +173,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
if (ps.mutedWords !== undefined) {
|
if (ps.mutedWords !== undefined) {
|
||||||
// TODO: ちゃんと数える
|
// TODO: ちゃんと数える
|
||||||
const length = JSON.stringify(ps.mutedWords).length;
|
const length = JSON.stringify(ps.mutedWords).length;
|
||||||
if (length > (await this.roleService.getUserRoleOptions(user.id)).wordMuteLimit) {
|
if (length > (await this.roleService.getUserPolicies(user.id)).wordMuteLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyMutedWords);
|
throw new ApiError(meta.errors.tooManyMutedWords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
const currentWebhooksCount = await this.webhooksRepository.countBy({
|
const currentWebhooksCount = await this.webhooksRepository.countBy({
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
if (currentWebhooksCount > (await this.roleService.getUserRoleOptions(me.id)).webhookLimit) {
|
if (currentWebhooksCount > (await this.roleService.getUserPolicies(me.id)).webhookLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyWebhooks);
|
throw new ApiError(meta.errors.tooManyWebhooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const meta = {
|
||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRoleOption: 'canInvite',
|
requireRolePolicy: 'canInvite',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { DEFAULT_ROLE } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
@ -334,7 +334,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
|
|
||||||
translatorAvailable: instance.deeplAuthKey != null,
|
translatorAvailable: instance.deeplAuthKey != null,
|
||||||
|
|
||||||
baseRole: { ...DEFAULT_ROLE, ...instance.defaultRoleOverride },
|
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||||
|
|
||||||
...(ps.detail ? {
|
...(ps.detail ? {
|
||||||
pinnedPages: instance.pinnedPages,
|
pinnedPages: instance.pinnedPages,
|
||||||
|
|
|
@ -62,8 +62,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
private activeUsersChart: ActiveUsersChart,
|
private activeUsersChart: ActiveUsersChart,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const role = await this.roleService.getUserRoleOptions(me ? me.id : null);
|
const policies = await this.roleService.getUserPolicies(me ? me.id : null);
|
||||||
if (!role.gtlAvailable) {
|
if (!policies.gtlAvailable) {
|
||||||
throw new ApiError(meta.errors.gtlDisabled);
|
throw new ApiError(meta.errors.gtlDisabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
private activeUsersChart: ActiveUsersChart,
|
private activeUsersChart: ActiveUsersChart,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const role = await this.roleService.getUserRoleOptions(me.id);
|
const policies = await this.roleService.getUserPolicies(me.id);
|
||||||
if (!role.ltlAvailable) {
|
if (!policies.ltlAvailable) {
|
||||||
throw new ApiError(meta.errors.stlDisabled);
|
throw new ApiError(meta.errors.stlDisabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,8 +67,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
private activeUsersChart: ActiveUsersChart,
|
private activeUsersChart: ActiveUsersChart,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const role = await this.roleService.getUserRoleOptions(me ? me.id : null);
|
const policies = await this.roleService.getUserPolicies(me ? me.id : null);
|
||||||
if (!role.ltlAvailable) {
|
if (!policies.ltlAvailable) {
|
||||||
throw new ApiError(meta.errors.ltlDisabled);
|
throw new ApiError(meta.errors.ltlDisabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
const currentCount = await this.userListsRepository.countBy({
|
const currentCount = await this.userListsRepository.countBy({
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
if (currentCount > (await this.roleService.getUserRoleOptions(me.id)).userListLimit) {
|
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) {
|
||||||
throw new ApiError(meta.errors.tooManyUserLists);
|
throw new ApiError(meta.errors.tooManyUserLists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@ class GlobalTimelineChannel extends Channel {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async init(params: any) {
|
public async init(params: any) {
|
||||||
const role = await this.roleService.getUserRoleOptions(this.user ? this.user.id : null);
|
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
|
||||||
if (!role.gtlAvailable) return;
|
if (!policies.gtlAvailable) return;
|
||||||
|
|
||||||
// Subscribe events
|
// Subscribe events
|
||||||
this.subscriber.on('notesStream', this.onNote);
|
this.subscriber.on('notesStream', this.onNote);
|
||||||
|
|
|
@ -30,8 +30,8 @@ class HybridTimelineChannel extends Channel {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async init(params: any): Promise<void> {
|
public async init(params: any): Promise<void> {
|
||||||
const role = await this.roleService.getUserRoleOptions(this.user ? this.user.id : null);
|
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
|
||||||
if (!role.ltlAvailable) return;
|
if (!policies.ltlAvailable) return;
|
||||||
|
|
||||||
// Subscribe events
|
// Subscribe events
|
||||||
this.subscriber.on('notesStream', this.onNote);
|
this.subscriber.on('notesStream', this.onNote);
|
||||||
|
|
|
@ -28,8 +28,8 @@ class LocalTimelineChannel extends Channel {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async init(params: any) {
|
public async init(params: any) {
|
||||||
const role = await this.roleService.getUserRoleOptions(this.user ? this.user.id : null);
|
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
|
||||||
if (!role.ltlAvailable) return;
|
if (!policies.ltlAvailable) return;
|
||||||
|
|
||||||
// Subscribe events
|
// Subscribe events
|
||||||
this.subscriber.on('notesStream', this.onNote);
|
this.subscriber.on('notesStream', this.onNote);
|
||||||
|
|
|
@ -30,7 +30,7 @@ export interface InternalStreamTypes {
|
||||||
remoteUserUpdated: Serialized<{ id: User['id']; }>;
|
remoteUserUpdated: Serialized<{ id: User['id']; }>;
|
||||||
follow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
|
follow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
|
||||||
unfollow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
|
unfollow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>;
|
||||||
defaultRoleOverrideUpdated: Serialized<Role['options']>;
|
policiesUpdated: Serialized<Role['options']>;
|
||||||
roleCreated: Serialized<Role>;
|
roleCreated: Serialized<Role>;
|
||||||
roleDeleted: Serialized<Role>;
|
roleDeleted: Serialized<Role>;
|
||||||
roleUpdated: Serialized<Role>;
|
roleUpdated: Serialized<Role>;
|
||||||
|
|
|
@ -36,20 +36,20 @@
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<FormSlot>
|
<FormSlot>
|
||||||
<template #label>{{ i18n.ts._role.options }}</template>
|
<template #label>{{ i18n.ts._role.policies }}</template>
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.rateLimitFactor }}</template>
|
<template #label>{{ i18n.ts._role._options.rateLimitFactor }}</template>
|
||||||
<template #suffix>{{ options.rateLimitFactor.useDefault ? i18n.ts._role.useBaseValue : `${Math.floor(options.rateLimitFactor.value * 100)}%` }} <i :class="getPriorityIcon(options.rateLimitFactor)"></i></template>
|
<template #suffix>{{ policies.rateLimitFactor.useDefault ? i18n.ts._role.useBaseValue : `${Math.floor(policies.rateLimitFactor.value * 100)}%` }} <i :class="getPriorityIcon(policies.rateLimitFactor)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.rateLimitFactor.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.rateLimitFactor.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkRange :model-value="options.rateLimitFactor.value * 100" :min="30" :max="300" :step="10" :text-converter="(v) => `${v}%`" @update:model-value="v => options.rateLimitFactor.value = (v / 100)">
|
<MkRange :model-value="policies.rateLimitFactor.value * 100" :min="30" :max="300" :step="10" :text-converter="(v) => `${v}%`" @update:model-value="v => policies.rateLimitFactor.value = (v / 100)">
|
||||||
<template #label>{{ i18n.ts._role._options.rateLimitFactor }}</template>
|
<template #label>{{ i18n.ts._role._options.rateLimitFactor }}</template>
|
||||||
<template #caption>{{ i18n.ts._role._options.descriptionOfRateLimitFactor }}</template>
|
<template #caption>{{ i18n.ts._role._options.descriptionOfRateLimitFactor }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
<MkRange v-model="options.rateLimitFactor.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.rateLimitFactor.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -57,15 +57,15 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.gtlAvailable }}</template>
|
<template #label>{{ i18n.ts._role._options.gtlAvailable }}</template>
|
||||||
<template #suffix>{{ options.gtlAvailable.useDefault ? i18n.ts._role.useBaseValue : (options.gtlAvailable.value ? i18n.ts.yes : i18n.ts.no) }} <i :class="getPriorityIcon(options.gtlAvailable)"></i></template>
|
<template #suffix>{{ policies.gtlAvailable.useDefault ? i18n.ts._role.useBaseValue : (policies.gtlAvailable.value ? i18n.ts.yes : i18n.ts.no) }} <i :class="getPriorityIcon(policies.gtlAvailable)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.gtlAvailable.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.gtlAvailable.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkSwitch v-model="options.gtlAvailable.value" :disabled="options.gtlAvailable.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.gtlAvailable.value" :disabled="policies.gtlAvailable.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkRange v-model="options.gtlAvailable.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.gtlAvailable.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -73,15 +73,15 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.ltlAvailable }}</template>
|
<template #label>{{ i18n.ts._role._options.ltlAvailable }}</template>
|
||||||
<template #suffix>{{ options.ltlAvailable.useDefault ? i18n.ts._role.useBaseValue : (options.ltlAvailable.value ? i18n.ts.yes : i18n.ts.no) }} <i :class="getPriorityIcon(options.ltlAvailable)"></i></template>
|
<template #suffix>{{ policies.ltlAvailable.useDefault ? i18n.ts._role.useBaseValue : (policies.ltlAvailable.value ? i18n.ts.yes : i18n.ts.no) }} <i :class="getPriorityIcon(policies.ltlAvailable)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.ltlAvailable.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.ltlAvailable.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkSwitch v-model="options.ltlAvailable.value" :disabled="options.ltlAvailable.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.ltlAvailable.value" :disabled="policies.ltlAvailable.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkRange v-model="options.ltlAvailable.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.ltlAvailable.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -89,15 +89,15 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.canPublicNote }}</template>
|
<template #label>{{ i18n.ts._role._options.canPublicNote }}</template>
|
||||||
<template #suffix>{{ options.canPublicNote.useDefault ? i18n.ts._role.useBaseValue : (options.canPublicNote.value ? i18n.ts.yes : i18n.ts.no) }} <i :class="getPriorityIcon(options.canPublicNote)"></i></template>
|
<template #suffix>{{ policies.canPublicNote.useDefault ? i18n.ts._role.useBaseValue : (policies.canPublicNote.value ? i18n.ts.yes : i18n.ts.no) }} <i :class="getPriorityIcon(policies.canPublicNote)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.canPublicNote.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.canPublicNote.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkSwitch v-model="options.canPublicNote.value" :disabled="options.canPublicNote.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.canPublicNote.value" :disabled="policies.canPublicNote.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkRange v-model="options.canPublicNote.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.canPublicNote.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -105,15 +105,15 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.canInvite }}</template>
|
<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) }} <i :class="getPriorityIcon(options.canInvite)"></i></template>
|
<template #suffix>{{ policies.canInvite.useDefault ? i18n.ts._role.useBaseValue : (policies.canInvite.value ? i18n.ts.yes : i18n.ts.no) }} <i :class="getPriorityIcon(policies.canInvite)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.canInvite.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.canInvite.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkSwitch v-model="options.canInvite.value" :disabled="options.canInvite.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.canInvite.value" :disabled="policies.canInvite.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkRange v-model="options.canInvite.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.canInvite.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -121,15 +121,15 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.canManageCustomEmojis }}</template>
|
<template #label>{{ i18n.ts._role._options.canManageCustomEmojis }}</template>
|
||||||
<template #suffix>{{ options.canManageCustomEmojis.useDefault ? i18n.ts._role.useBaseValue : (options.canManageCustomEmojis.value ? i18n.ts.yes : i18n.ts.no) }} <i :class="getPriorityIcon(options.canManageCustomEmojis)"></i></template>
|
<template #suffix>{{ policies.canManageCustomEmojis.useDefault ? i18n.ts._role.useBaseValue : (policies.canManageCustomEmojis.value ? i18n.ts.yes : i18n.ts.no) }} <i :class="getPriorityIcon(policies.canManageCustomEmojis)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.canManageCustomEmojis.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.canManageCustomEmojis.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkSwitch v-model="options.canManageCustomEmojis.value" :disabled="options.canManageCustomEmojis.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.canManageCustomEmojis.value" :disabled="policies.canManageCustomEmojis.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkRange v-model="options.canManageCustomEmojis.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.canManageCustomEmojis.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -137,15 +137,15 @@
|
||||||
|
|
||||||
<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') }} <i :class="getPriorityIcon(options.driveCapacityMb)"></i></template>
|
<template #suffix>{{ policies.driveCapacityMb.useDefault ? i18n.ts._role.useBaseValue : (policies.driveCapacityMb.value + 'MB') }} <i :class="getPriorityIcon(policies.driveCapacityMb)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.driveCapacityMb.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.driveCapacityMb.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkInput v-model="options.driveCapacityMb.value" :disabled="options.driveCapacityMb.useDefault" type="number" :readonly="readonly">
|
<MkInput v-model="policies.driveCapacityMb.value" :disabled="policies.driveCapacityMb.useDefault" type="number" :readonly="readonly">
|
||||||
<template #suffix>MB</template>
|
<template #suffix>MB</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkRange v-model="options.driveCapacityMb.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.driveCapacityMb.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -153,14 +153,14 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.pinMax }}</template>
|
<template #label>{{ i18n.ts._role._options.pinMax }}</template>
|
||||||
<template #suffix>{{ options.pinLimit.useDefault ? i18n.ts._role.useBaseValue : (options.pinLimit.value) }} <i :class="getPriorityIcon(options.pinLimit)"></i></template>
|
<template #suffix>{{ policies.pinLimit.useDefault ? i18n.ts._role.useBaseValue : (policies.pinLimit.value) }} <i :class="getPriorityIcon(policies.pinLimit)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.pinLimit.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.pinLimit.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkInput v-model="options.pinLimit.value" :disabled="options.pinLimit.useDefault" type="number" :readonly="readonly">
|
<MkInput v-model="policies.pinLimit.value" :disabled="policies.pinLimit.useDefault" type="number" :readonly="readonly">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkRange v-model="options.pinLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.pinLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -168,14 +168,14 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.antennaMax }}</template>
|
<template #label>{{ i18n.ts._role._options.antennaMax }}</template>
|
||||||
<template #suffix>{{ options.antennaLimit.useDefault ? i18n.ts._role.useBaseValue : (options.antennaLimit.value) }} <i :class="getPriorityIcon(options.antennaLimit)"></i></template>
|
<template #suffix>{{ policies.antennaLimit.useDefault ? i18n.ts._role.useBaseValue : (policies.antennaLimit.value) }} <i :class="getPriorityIcon(policies.antennaLimit)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.antennaLimit.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.antennaLimit.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkInput v-model="options.antennaLimit.value" :disabled="options.antennaLimit.useDefault" type="number" :readonly="readonly">
|
<MkInput v-model="policies.antennaLimit.value" :disabled="policies.antennaLimit.useDefault" type="number" :readonly="readonly">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkRange v-model="options.antennaLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.antennaLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -183,15 +183,15 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.wordMuteMax }}</template>
|
<template #label>{{ i18n.ts._role._options.wordMuteMax }}</template>
|
||||||
<template #suffix>{{ options.wordMuteLimit.useDefault ? i18n.ts._role.useBaseValue : (options.wordMuteLimit.value) }} <i :class="getPriorityIcon(options.wordMuteLimit)"></i></template>
|
<template #suffix>{{ policies.wordMuteLimit.useDefault ? i18n.ts._role.useBaseValue : (policies.wordMuteLimit.value) }} <i :class="getPriorityIcon(policies.wordMuteLimit)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.wordMuteLimit.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.wordMuteLimit.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkInput v-model="options.wordMuteLimit.value" :disabled="options.wordMuteLimit.useDefault" type="number" :readonly="readonly">
|
<MkInput v-model="policies.wordMuteLimit.value" :disabled="policies.wordMuteLimit.useDefault" type="number" :readonly="readonly">
|
||||||
<template #suffix>chars</template>
|
<template #suffix>chars</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkRange v-model="options.wordMuteLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.wordMuteLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,14 +199,14 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.webhookMax }}</template>
|
<template #label>{{ i18n.ts._role._options.webhookMax }}</template>
|
||||||
<template #suffix>{{ options.webhookLimit.useDefault ? i18n.ts._role.useBaseValue : (options.webhookLimit.value) }} <i :class="getPriorityIcon(options.webhookLimit)"></i></template>
|
<template #suffix>{{ policies.webhookLimit.useDefault ? i18n.ts._role.useBaseValue : (policies.webhookLimit.value) }} <i :class="getPriorityIcon(policies.webhookLimit)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.webhookLimit.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.webhookLimit.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkInput v-model="options.webhookLimit.value" :disabled="options.webhookLimit.useDefault" type="number" :readonly="readonly">
|
<MkInput v-model="policies.webhookLimit.value" :disabled="policies.webhookLimit.useDefault" type="number" :readonly="readonly">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkRange v-model="options.webhookLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.webhookLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -214,14 +214,14 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.clipMax }}</template>
|
<template #label>{{ i18n.ts._role._options.clipMax }}</template>
|
||||||
<template #suffix>{{ options.clipLimit.useDefault ? i18n.ts._role.useBaseValue : (options.clipLimit.value) }} <i :class="getPriorityIcon(options.clipLimit)"></i></template>
|
<template #suffix>{{ policies.clipLimit.useDefault ? i18n.ts._role.useBaseValue : (policies.clipLimit.value) }} <i :class="getPriorityIcon(policies.clipLimit)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.clipLimit.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.clipLimit.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkInput v-model="options.clipLimit.value" :disabled="options.clipLimit.useDefault" type="number" :readonly="readonly">
|
<MkInput v-model="policies.clipLimit.value" :disabled="policies.clipLimit.useDefault" type="number" :readonly="readonly">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkRange v-model="options.clipLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.clipLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -229,14 +229,14 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.noteEachClipsMax }}</template>
|
<template #label>{{ i18n.ts._role._options.noteEachClipsMax }}</template>
|
||||||
<template #suffix>{{ options.noteEachClipsLimit.useDefault ? i18n.ts._role.useBaseValue : (options.noteEachClipsLimit.value) }} <i :class="getPriorityIcon(options.noteEachClipsLimit)"></i></template>
|
<template #suffix>{{ policies.noteEachClipsLimit.useDefault ? i18n.ts._role.useBaseValue : (policies.noteEachClipsLimit.value) }} <i :class="getPriorityIcon(policies.noteEachClipsLimit)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.noteEachClipsLimit.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.noteEachClipsLimit.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkInput v-model="options.noteEachClipsLimit.value" :disabled="options.noteEachClipsLimit.useDefault" type="number" :readonly="readonly">
|
<MkInput v-model="policies.noteEachClipsLimit.value" :disabled="policies.noteEachClipsLimit.useDefault" type="number" :readonly="readonly">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkRange v-model="options.noteEachClipsLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.noteEachClipsLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -244,14 +244,14 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.userListMax }}</template>
|
<template #label>{{ i18n.ts._role._options.userListMax }}</template>
|
||||||
<template #suffix>{{ options.userListLimit.useDefault ? i18n.ts._role.useBaseValue : (options.userListLimit.value) }} <i :class="getPriorityIcon(options.userListLimit)"></i></template>
|
<template #suffix>{{ policies.userListLimit.useDefault ? i18n.ts._role.useBaseValue : (policies.userListLimit.value) }} <i :class="getPriorityIcon(policies.userListLimit)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.userListLimit.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.userListLimit.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkInput v-model="options.userListLimit.value" :disabled="options.userListLimit.useDefault" type="number" :readonly="readonly">
|
<MkInput v-model="policies.userListLimit.value" :disabled="policies.userListLimit.useDefault" type="number" :readonly="readonly">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkRange v-model="options.userListLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.userListLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -259,14 +259,14 @@
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template>
|
<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template>
|
||||||
<template #suffix>{{ options.userEachUserListsLimit.useDefault ? i18n.ts._role.useBaseValue : (options.userEachUserListsLimit.value) }} <i :class="getPriorityIcon(options.userEachUserListsLimit)"></i></template>
|
<template #suffix>{{ policies.userEachUserListsLimit.useDefault ? i18n.ts._role.useBaseValue : (policies.userEachUserListsLimit.value) }} <i :class="getPriorityIcon(policies.userEachUserListsLimit)"></i></template>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkSwitch v-model="options.userEachUserListsLimit.useDefault" :readonly="readonly">
|
<MkSwitch v-model="policies.userEachUserListsLimit.useDefault" :readonly="readonly">
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkInput v-model="options.userEachUserListsLimit.value" :disabled="options.userEachUserListsLimit.useDefault" type="number" :readonly="readonly">
|
<MkInput v-model="policies.userEachUserListsLimit.value" :disabled="policies.userEachUserListsLimit.useDefault" type="number" :readonly="readonly">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkRange v-model="options.userEachUserListsLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
<MkRange v-model="policies.userEachUserListsLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(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>
|
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</div>
|
</div>
|
||||||
|
@ -306,7 +306,7 @@ import * as os from '@/os';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { instance } from '@/instance';
|
import { instance } from '@/instance';
|
||||||
|
|
||||||
const ROLE_OPTIONS = [
|
const ROLE_POLICIES = [
|
||||||
'gtlAvailable',
|
'gtlAvailable',
|
||||||
'ltlAvailable',
|
'ltlAvailable',
|
||||||
'canPublicNote',
|
'canPublicNote',
|
||||||
|
@ -345,13 +345,13 @@ let condFormula = $ref(role?.condFormula ?? { id: uuid(), type: 'isRemote' });
|
||||||
let isPublic = $ref(role?.isPublic ?? false);
|
let isPublic = $ref(role?.isPublic ?? false);
|
||||||
let canEditMembersByModerator = $ref(role?.canEditMembersByModerator ?? false);
|
let canEditMembersByModerator = $ref(role?.canEditMembersByModerator ?? false);
|
||||||
|
|
||||||
const options = reactive<Record<typeof ROLE_OPTIONS[number], { useDefault: boolean; priority: number; value: any; }>>({});
|
const policies = reactive<Record<typeof ROLE_POLICIES[number], { useDefault: boolean; priority: number; value: any; }>>({});
|
||||||
for (const ROLE_OPTION of ROLE_OPTIONS) {
|
for (const ROLE_POLICY of ROLE_POLICIES) {
|
||||||
const _options = role?.options ?? {};
|
const _policies = role?.policies ?? {};
|
||||||
options[ROLE_OPTION] = {
|
policies[ROLE_POLICY] = {
|
||||||
useDefault: _options[ROLE_OPTION]?.useDefault ?? true,
|
useDefault: _policies[ROLE_POLICY]?.useDefault ?? true,
|
||||||
priority: _options[ROLE_OPTION]?.priority ?? 0,
|
priority: _policies[ROLE_POLICY]?.priority ?? 0,
|
||||||
value: _options[ROLE_OPTION]?.value ?? instance.baseRole[ROLE_OPTION],
|
value: _policies[ROLE_POLICY]?.value ?? instance.policies[ROLE_POLICY],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,7 +381,7 @@ async function save() {
|
||||||
isModerator: rolePermission === 'moderator',
|
isModerator: rolePermission === 'moderator',
|
||||||
isPublic,
|
isPublic,
|
||||||
canEditMembersByModerator,
|
canEditMembersByModerator,
|
||||||
options,
|
policies,
|
||||||
});
|
});
|
||||||
emit('updated');
|
emit('updated');
|
||||||
} else {
|
} else {
|
||||||
|
@ -395,7 +395,7 @@ async function save() {
|
||||||
isModerator: rolePermission === 'moderator',
|
isModerator: rolePermission === 'moderator',
|
||||||
isPublic,
|
isPublic,
|
||||||
canEditMembersByModerator,
|
canEditMembersByModerator,
|
||||||
options,
|
policies,
|
||||||
});
|
});
|
||||||
emit('created', created);
|
emit('created', created);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,114 +10,114 @@
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.rateLimitFactor }}</template>
|
<template #label>{{ i18n.ts._role._options.rateLimitFactor }}</template>
|
||||||
<template #suffix>{{ Math.floor(options_rateLimitFactor * 100) }}%</template>
|
<template #suffix>{{ Math.floor(policies.rateLimitFactor * 100) }}%</template>
|
||||||
<MkRange :model-value="options_rateLimitFactor * 100" :min="30" :max="300" :step="10" :text-converter="(v) => `${v}%`" @update:model-value="v => options_rateLimitFactor = (v / 100)">
|
<MkRange :model-value="policies.rateLimitFactor * 100" :min="30" :max="300" :step="10" :text-converter="(v) => `${v}%`" @update:model-value="v => policies.rateLimitFactor = (v / 100)">
|
||||||
<template #caption>{{ i18n.ts._role._options.descriptionOfRateLimitFactor }}</template>
|
<template #caption>{{ i18n.ts._role._options.descriptionOfRateLimitFactor }}</template>
|
||||||
</MkRange>
|
</MkRange>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.gtlAvailable }}</template>
|
<template #label>{{ i18n.ts._role._options.gtlAvailable }}</template>
|
||||||
<template #suffix>{{ options_gtlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.gtlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkSwitch v-model="options_gtlAvailable">
|
<MkSwitch v-model="policies.gtlAvailable">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.ltlAvailable }}</template>
|
<template #label>{{ i18n.ts._role._options.ltlAvailable }}</template>
|
||||||
<template #suffix>{{ options_ltlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.ltlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkSwitch v-model="options_ltlAvailable">
|
<MkSwitch v-model="policies.ltlAvailable">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.canPublicNote }}</template>
|
<template #label>{{ i18n.ts._role._options.canPublicNote }}</template>
|
||||||
<template #suffix>{{ options_canPublicNote ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.canPublicNote ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkSwitch v-model="options_canPublicNote">
|
<MkSwitch v-model="policies.canPublicNote">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.canInvite }}</template>
|
<template #label>{{ i18n.ts._role._options.canInvite }}</template>
|
||||||
<template #suffix>{{ options_canInvite ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.canInvite ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkSwitch v-model="options_canInvite">
|
<MkSwitch v-model="policies.canInvite">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.canManageCustomEmojis }}</template>
|
<template #label>{{ i18n.ts._role._options.canManageCustomEmojis }}</template>
|
||||||
<template #suffix>{{ options_canManageCustomEmojis ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.canManageCustomEmojis ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
<MkSwitch v-model="options_canManageCustomEmojis">
|
<MkSwitch v-model="policies.canManageCustomEmojis">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</MkFolder>
|
</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>{{ policies.driveCapacityMb }}MB</template>
|
||||||
<MkInput v-model="options_driveCapacityMb" type="number">
|
<MkInput v-model="policies.driveCapacityMb" type="number">
|
||||||
<template #suffix>MB</template>
|
<template #suffix>MB</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.pinMax }}</template>
|
<template #label>{{ i18n.ts._role._options.pinMax }}</template>
|
||||||
<template #suffix>{{ options_pinLimit }}</template>
|
<template #suffix>{{ policies.pinLimit }}</template>
|
||||||
<MkInput v-model="options_pinLimit" type="number">
|
<MkInput v-model="policies.pinLimit" type="number">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.antennaMax }}</template>
|
<template #label>{{ i18n.ts._role._options.antennaMax }}</template>
|
||||||
<template #suffix>{{ options_antennaLimit }}</template>
|
<template #suffix>{{ policies.antennaLimit }}</template>
|
||||||
<MkInput v-model="options_antennaLimit" type="number">
|
<MkInput v-model="policies.antennaLimit" type="number">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.wordMuteMax }}</template>
|
<template #label>{{ i18n.ts._role._options.wordMuteMax }}</template>
|
||||||
<template #suffix>{{ options_wordMuteLimit }}</template>
|
<template #suffix>{{ policies.wordMuteLimit }}</template>
|
||||||
<MkInput v-model="options_wordMuteLimit" type="number">
|
<MkInput v-model="policies.wordMuteLimit" type="number">
|
||||||
<template #suffix>chars</template>
|
<template #suffix>chars</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.webhookMax }}</template>
|
<template #label>{{ i18n.ts._role._options.webhookMax }}</template>
|
||||||
<template #suffix>{{ options_webhookLimit }}</template>
|
<template #suffix>{{ policies.webhookLimit }}</template>
|
||||||
<MkInput v-model="options_webhookLimit" type="number">
|
<MkInput v-model="policies.webhookLimit" type="number">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.clipMax }}</template>
|
<template #label>{{ i18n.ts._role._options.clipMax }}</template>
|
||||||
<template #suffix>{{ options_clipLimit }}</template>
|
<template #suffix>{{ policies.clipLimit }}</template>
|
||||||
<MkInput v-model="options_clipLimit" type="number">
|
<MkInput v-model="policies.clipLimit" type="number">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.noteEachClipsMax }}</template>
|
<template #label>{{ i18n.ts._role._options.noteEachClipsMax }}</template>
|
||||||
<template #suffix>{{ options_noteEachClipsLimit }}</template>
|
<template #suffix>{{ policies.noteEachClipsLimit }}</template>
|
||||||
<MkInput v-model="options_noteEachClipsLimit" type="number">
|
<MkInput v-model="policies.noteEachClipsLimit" type="number">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.userListMax }}</template>
|
<template #label>{{ i18n.ts._role._options.userListMax }}</template>
|
||||||
<template #suffix>{{ options_userListLimit }}</template>
|
<template #suffix>{{ policies.userListLimit }}</template>
|
||||||
<MkInput v-model="options_userListLimit" type="number">
|
<MkInput v-model="policies.userListLimit" type="number">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template>
|
<template #label>{{ i18n.ts._role._options.userEachUserListsMax }}</template>
|
||||||
<template #suffix>{{ options_userEachUserListsLimit }}</template>
|
<template #suffix>{{ policies.userEachUserListsLimit }}</template>
|
||||||
<MkInput v-model="options_userEachUserListsLimit" type="number">
|
<MkInput v-model="policies.userEachUserListsLimit" type="number">
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
import { computed, reactive } from 'vue';
|
||||||
import XHeader from './_header_.vue';
|
import XHeader from './_header_.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
|
@ -150,45 +150,36 @@ import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
import { instance } from '@/instance';
|
import { instance } from '@/instance';
|
||||||
import { useRouter } from '@/router';
|
import { useRouter } from '@/router';
|
||||||
|
|
||||||
|
const ROLE_POLICIES = [
|
||||||
|
'gtlAvailable',
|
||||||
|
'ltlAvailable',
|
||||||
|
'canPublicNote',
|
||||||
|
'canInvite',
|
||||||
|
'canManageCustomEmojis',
|
||||||
|
'driveCapacityMb',
|
||||||
|
'pinLimit',
|
||||||
|
'antennaLimit',
|
||||||
|
'wordMuteLimit',
|
||||||
|
'webhookLimit',
|
||||||
|
'clipLimit',
|
||||||
|
'noteEachClipsLimit',
|
||||||
|
'userListLimit',
|
||||||
|
'userEachUserListsLimit',
|
||||||
|
'rateLimitFactor',
|
||||||
|
] as const;
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const roles = await os.api('admin/roles/list');
|
const roles = await os.api('admin/roles/list');
|
||||||
|
|
||||||
let options_gtlAvailable = $ref(instance.baseRole.gtlAvailable);
|
const policies = reactive<Record<typeof ROLE_POLICIES[number], any>>({});
|
||||||
let options_ltlAvailable = $ref(instance.baseRole.ltlAvailable);
|
for (const ROLE_POLICY of ROLE_POLICIES) {
|
||||||
let options_canPublicNote = $ref(instance.baseRole.canPublicNote);
|
policies[ROLE_POLICY] = instance.policies[ROLE_POLICY];
|
||||||
let options_canInvite = $ref(instance.baseRole.canInvite);
|
}
|
||||||
let options_canManageCustomEmojis = $ref(instance.baseRole.canManageCustomEmojis);
|
|
||||||
let options_driveCapacityMb = $ref(instance.baseRole.driveCapacityMb);
|
|
||||||
let options_pinLimit = $ref(instance.baseRole.pinLimit);
|
|
||||||
let options_antennaLimit = $ref(instance.baseRole.antennaLimit);
|
|
||||||
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);
|
|
||||||
let options_rateLimitFactor = $ref(instance.baseRole.rateLimitFactor);
|
|
||||||
|
|
||||||
async function updateBaseRole() {
|
async function updateBaseRole() {
|
||||||
await os.apiWithDialog('admin/roles/update-default-role-override', {
|
await os.apiWithDialog('admin/roles/update-default-policies', {
|
||||||
options: {
|
policies,
|
||||||
gtlAvailable: options_gtlAvailable,
|
|
||||||
ltlAvailable: options_ltlAvailable,
|
|
||||||
canPublicNote: options_canPublicNote,
|
|
||||||
canInvite: options_canInvite,
|
|
||||||
canManageCustomEmojis: options_canManageCustomEmojis,
|
|
||||||
driveCapacityMb: options_driveCapacityMb,
|
|
||||||
pinLimit: options_pinLimit,
|
|
||||||
antennaLimit: options_antennaLimit,
|
|
||||||
wordMuteLimit: options_wordMuteLimit,
|
|
||||||
webhookLimit: options_webhookLimit,
|
|
||||||
clipLimit: options_clipLimit,
|
|
||||||
noteEachClipsLimit: options_noteEachClipsLimit,
|
|
||||||
userListLimit: options_userListLimit,
|
|
||||||
userEachUserListsLimit: options_userEachUserListsLimit,
|
|
||||||
rateLimitFactor: options_rateLimitFactor,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
|
|
||||||
const XTutorial = defineAsyncComponent(() => import('./timeline.tutorial.vue'));
|
const XTutorial = defineAsyncComponent(() => import('./timeline.tutorial.vue'));
|
||||||
|
|
||||||
const isLocalTimelineAvailable = ($i == null && instance.baseRole.ltlAvailable) || ($i != null && $i.role.ltlAvailable);
|
const isLocalTimelineAvailable = ($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable);
|
||||||
const isGlobalTimelineAvailable = ($i == null && instance.baseRole.gtlAvailable) || ($i != null && $i.role.gtlAvailable);
|
const isGlobalTimelineAvailable = ($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable);
|
||||||
const keymap = {
|
const keymap = {
|
||||||
't': focus,
|
't': focus,
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,16 +86,28 @@
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="tab === 'moderation'" class="_gaps_m">
|
<div v-else-if="tab === 'moderation'" class="_gaps_m">
|
||||||
<MkSwitch v-model="suspended" @update:model-value="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch>
|
<MkSwitch v-model="suspended" @update:model-value="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<MkButton v-if="user.host == null && iAmModerator" inline style="margin-right: 8px;" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton>
|
<MkButton v-if="user.host == null && iAmModerator" inline style="margin-right: 8px;" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton>
|
||||||
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
|
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<MkFolder>
|
||||||
|
<template #icon><i class="ti ti-license"></i></template>
|
||||||
|
<template #label>{{ i18n.ts._role.policies }}</template>
|
||||||
|
<div class="_gaps">
|
||||||
|
<div v-for="policy in Object.keys(info.policies)" :key="policy">
|
||||||
|
{{ policy }} ... {{ info.policies[policy] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #icon><i class="ti ti-badges"></i></template>
|
<template #icon><i class="ti ti-badges"></i></template>
|
||||||
<template #label>{{ i18n.ts.roles }}</template>
|
<template #label>{{ i18n.ts.roles }}</template>
|
||||||
|
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkButton v-if="user.host == null && iAmModerator" primary rounded @click="assignRole"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton>
|
<MkButton v-if="user.host == null && iAmModerator" primary rounded @click="assignRole"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton>
|
||||||
|
|
||||||
|
@ -105,6 +117,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #icon><i class="ti ti-password"></i></template>
|
<template #icon><i class="ti ti-password"></i></template>
|
||||||
<template #label>IP</template>
|
<template #label>IP</template>
|
||||||
|
@ -117,16 +130,18 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #icon><i class="ti ti-cloud"></i></template>
|
<template #icon><i class="ti ti-cloud"></i></template>
|
||||||
<template #label>{{ i18n.ts.files }}</template>
|
<template #label>{{ i18n.ts.files }}</template>
|
||||||
|
|
||||||
<MkFileListForAdmin :pagination="filesPagination" view-mode="grid"/>
|
<MkFileListForAdmin :pagination="filesPagination" view-mode="grid"/>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkTextarea v-model="moderationNote" manual-save>
|
<MkTextarea v-model="moderationNote" manual-save>
|
||||||
<template #label>Moderation note</template>
|
<template #label>Moderation note</template>
|
||||||
</MkTextarea>
|
</MkTextarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="tab === 'chart'" class="_gaps_m">
|
<div v-else-if="tab === 'chart'" class="_gaps_m">
|
||||||
<div class="cmhjzshm">
|
<div class="cmhjzshm">
|
||||||
<div class="selects">
|
<div class="selects">
|
||||||
|
@ -142,6 +157,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="tab === 'raw'" class="_gaps_m">
|
<div v-else-if="tab === 'raw'" class="_gaps_m">
|
||||||
<MkObjectView v-if="info && $i.isAdmin" tall :value="info">
|
<MkObjectView v-if="info && $i.isAdmin" tall :value="info">
|
||||||
</MkObjectView>
|
</MkObjectView>
|
||||||
|
|
|
@ -47,7 +47,7 @@ export function openInstanceMenu(ev: MouseEvent) {
|
||||||
to: '/clicker',
|
to: '/clicker',
|
||||||
text: '🍪👈',
|
text: '🍪👈',
|
||||||
icon: 'ti ti-cookie',
|
icon: 'ti ti-cookie',
|
||||||
}, ($i && ($i.isAdmin || $i.role.canInvite) && instance.disableRegistration) ? {
|
}, ($i && ($i.isAdmin || $i.policies.canInvite) && instance.disableRegistration) ? {
|
||||||
text: i18n.ts.invite,
|
text: i18n.ts.invite,
|
||||||
icon: 'ti ti-user-plus',
|
icon: 'ti ti-user-plus',
|
||||||
action: () => {
|
action: () => {
|
||||||
|
@ -63,7 +63,7 @@ export function openInstanceMenu(ev: MouseEvent) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
} : undefined, ($i && ($i.isAdmin || $i.role.canManageCustomEmojis)) ? {
|
} : undefined, ($i && ($i.isAdmin || $i.policies.canManageCustomEmojis)) ? {
|
||||||
type: 'link',
|
type: 'link',
|
||||||
to: '/custom-emojis-manager',
|
to: '/custom-emojis-manager',
|
||||||
text: i18n.ts.manageCustomEmojis,
|
text: i18n.ts.manageCustomEmojis,
|
||||||
|
|
Loading…
Reference in a new issue