feat: ロールによるコンテンツの操作の制限 (#120)
This commit is contained in:
parent
0bed053b7d
commit
46f8a0435c
@ -1404,6 +1404,9 @@ _role:
|
||||
gtlAvailable: "Can view the global timeline"
|
||||
ltlAvailable: "Can view the local timeline"
|
||||
canPublicNote: "Can send public notes"
|
||||
canCreateContent: "Can create contents"
|
||||
canUpdateContent: "Can edit contents"
|
||||
canDeleteContent: "Can delete contents"
|
||||
canInvite: "Can create instance invite codes"
|
||||
inviteLimit: "Invite limit"
|
||||
inviteLimitCycle: "Invite limit cooldown"
|
||||
|
3
locales/index.d.ts
vendored
3
locales/index.d.ts
vendored
@ -1490,6 +1490,9 @@ export interface Locale {
|
||||
"gtlAvailable": string;
|
||||
"ltlAvailable": string;
|
||||
"canPublicNote": string;
|
||||
"canCreateContent": string;
|
||||
"canUpdateContent": string;
|
||||
"canDeleteContent": string;
|
||||
"canInvite": string;
|
||||
"inviteLimit": string;
|
||||
"inviteLimitCycle": string;
|
||||
|
@ -1412,6 +1412,9 @@ _role:
|
||||
gtlAvailable: "グローバルタイムラインの閲覧"
|
||||
ltlAvailable: "ローカルタイムラインの閲覧"
|
||||
canPublicNote: "パブリック投稿の許可"
|
||||
canCreateContent: "コンテンツの作成"
|
||||
canUpdateContent: "コンテンツの編集"
|
||||
canDeleteContent: "コンテンツの削除"
|
||||
canInvite: "サーバー招待コードの発行"
|
||||
inviteLimit: "招待コードの作成可能数"
|
||||
inviteLimitCycle: "招待コードの発行間隔"
|
||||
|
@ -20,6 +20,9 @@ export type RolePolicies = {
|
||||
gtlAvailable: boolean;
|
||||
ltlAvailable: boolean;
|
||||
canPublicNote: boolean;
|
||||
canCreateContent: boolean;
|
||||
canUpdateContent: boolean;
|
||||
canDeleteContent: boolean;
|
||||
canInvite: boolean;
|
||||
inviteLimit: number;
|
||||
inviteLimitCycle: number;
|
||||
@ -44,6 +47,9 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
||||
gtlAvailable: true,
|
||||
ltlAvailable: true,
|
||||
canPublicNote: true,
|
||||
canCreateContent: true,
|
||||
canUpdateContent: true,
|
||||
canDeleteContent: true,
|
||||
canInvite: false,
|
||||
inviteLimit: 0,
|
||||
inviteLimitCycle: 60 * 24 * 7,
|
||||
@ -287,6 +293,9 @@ export class RoleService implements OnApplicationShutdown {
|
||||
gtlAvailable: calc('gtlAvailable', vs => vs.some(v => v === true)),
|
||||
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
|
||||
canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)),
|
||||
canCreateContent: calc('canCreateContent', vs => vs.some(v => v === true)),
|
||||
canUpdateContent: calc('canUpdateContent', vs => vs.some(v => v === true)),
|
||||
canDeleteContent: calc('canDeleteContent', vs => vs.some(v => v === true)),
|
||||
canInvite: calc('canInvite', vs => vs.some(v => v === true)),
|
||||
inviteLimit: calc('inviteLimit', vs => Math.max(...vs)),
|
||||
inviteLimitCycle: calc('inviteLimitCycle', vs => Math.max(...vs)),
|
||||
|
@ -351,8 +351,9 @@ export class UserEntityService implements OnModuleInit {
|
||||
(profile.ffVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount :
|
||||
null;
|
||||
|
||||
const isModerator = isMe && opts.detail ? this.roleService.isModerator(user) : null;
|
||||
const isAdmin = isMe && opts.detail ? this.roleService.isAdministrator(user) : null;
|
||||
const isModerator = isMe && opts.detail ? await this.roleService.isModerator(user) : null;
|
||||
const isAdmin = isMe && opts.detail ? await this.roleService.isAdministrator(user) : null;
|
||||
const policies = opts.detail ? await this.roleService.getUserPolicies(user.id) : null;
|
||||
|
||||
const falsy = opts.detail ? false : undefined;
|
||||
|
||||
@ -396,7 +397,8 @@ export class UserEntityService implements OnModuleInit {
|
||||
bannerUrl: user.bannerUrl,
|
||||
bannerBlurhash: user.bannerBlurhash,
|
||||
isLocked: user.isLocked,
|
||||
isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote),
|
||||
isSilenced: !policies?.canPublicNote,
|
||||
isLimited: !(policies?.canCreateContent && policies.canUpdateContent && policies.canDeleteContent),
|
||||
isSuspended: user.isSuspended ?? falsy,
|
||||
description: profile!.description,
|
||||
location: profile!.location,
|
||||
@ -473,7 +475,7 @@ export class UserEntityService implements OnModuleInit {
|
||||
emailNotificationTypes: profile!.emailNotificationTypes,
|
||||
achievements: profile!.achievements,
|
||||
loggedInDays: profile!.loggedInDates.length,
|
||||
policies: this.roleService.getUserPolicies(user.id),
|
||||
policies: policies,
|
||||
} : {}),
|
||||
|
||||
...(opts.includeSecrets ? {
|
||||
|
@ -121,6 +121,10 @@ export const packedUserDetailedNotMeOnlySchema = {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
isLimited: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
},
|
||||
isSuspended: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: false,
|
||||
|
@ -51,8 +51,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
throw new Error('user not found');
|
||||
}
|
||||
|
||||
const policies = await this.roleService.getUserPolicies(user.id);
|
||||
const isModerator = await this.roleService.isModerator(user);
|
||||
const isSilenced = !(await this.roleService.getUserPolicies(user.id)).canPublicNote;
|
||||
const isLimited = !(policies.canCreateContent && policies.canUpdateContent && policies.canDeleteContent);
|
||||
const isSilenced = !policies.canPublicNote;
|
||||
|
||||
const _me = await this.usersRepository.findOneByOrFail({ id: me.id });
|
||||
if (!await this.roleService.isAdministrator(_me) && await this.roleService.isAdministrator(user)) {
|
||||
@ -80,6 +82,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
mutingNotificationTypes: profile.mutingNotificationTypes,
|
||||
isModerator: isModerator,
|
||||
isSilenced: isSilenced,
|
||||
isLimited: isLimited,
|
||||
isSuspended: user.isSuspended,
|
||||
lastActiveDate: user.lastActiveDate,
|
||||
moderationNote: profile.moderationNote ?? '',
|
||||
|
@ -12,6 +12,7 @@ export const meta = {
|
||||
tags: ['antennas'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['antennas'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['antennas'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -17,6 +17,7 @@ export const meta = {
|
||||
},
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:blocks',
|
||||
|
||||
|
@ -17,6 +17,7 @@ export const meta = {
|
||||
},
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:blocks',
|
||||
|
||||
|
@ -12,6 +12,7 @@ export const meta = {
|
||||
tags: ['channels'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['channels'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['channels'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['channels'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['channels'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['channels'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:channels',
|
||||
|
||||
|
@ -14,6 +14,7 @@ export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
prohibitMoved: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -11,6 +11,7 @@ export const meta = {
|
||||
tags: ['clips'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['clips'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['account', 'notes', 'clips'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['clip'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['clips'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -14,6 +14,7 @@ export const meta = {
|
||||
tags: ['drive'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -11,6 +11,7 @@ export const meta = {
|
||||
tags: ['drive'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:drive',
|
||||
|
||||
|
@ -11,6 +11,7 @@ export const meta = {
|
||||
tags: ['drive'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:drive',
|
||||
|
||||
|
@ -18,6 +18,7 @@ export const meta = {
|
||||
description: 'Request the server to download a new drive file from the specified URL.',
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -12,6 +12,7 @@ export const meta = {
|
||||
tags: ['drive'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
kind: 'write:drive',
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['drive'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:drive',
|
||||
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['drive'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:drive',
|
||||
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['flash'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['flashs'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:flash',
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['flash'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['flash'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['flash'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -12,6 +12,7 @@ export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:gallery',
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -7,6 +7,7 @@ import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
secure: true,
|
||||
} as const;
|
||||
|
@ -11,6 +11,8 @@ import { ApiError } from '../../error.js';
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
limit: {
|
||||
|
@ -10,6 +10,8 @@ import { ApiError } from '../../error.js';
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
limit: {
|
||||
|
@ -10,6 +10,8 @@ import { ApiError } from '../../error.js';
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
limit: {
|
||||
|
@ -10,7 +10,10 @@ import { ApiError } from '../../error.js';
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
max: 1,
|
||||
|
@ -23,7 +23,10 @@ export const meta = {
|
||||
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1day'),
|
||||
max: 5,
|
||||
|
@ -8,6 +8,8 @@ export const meta = {
|
||||
tags: ['account', 'notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
kind: 'write:account',
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['account', 'notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -12,10 +12,11 @@ import { L_CHARS, secureRndstr } from '@/misc/secure-rndstr.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
secure: true,
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
max: 3,
|
||||
|
@ -30,6 +30,7 @@ export const meta = {
|
||||
tags: ['account'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -12,6 +12,7 @@ export const meta = {
|
||||
tags: ['webhooks'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['webhooks'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['webhooks'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -11,6 +11,8 @@ export const meta = {
|
||||
tags: ['account'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
kind: 'write:mutes',
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['account'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:mutes',
|
||||
|
||||
|
@ -17,6 +17,7 @@ export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -12,6 +12,7 @@ export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:notes',
|
||||
|
||||
|
@ -12,6 +12,8 @@ export const meta = {
|
||||
tags: ['notes', 'favorites'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
kind: 'write:favorites',
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['notes', 'favorites'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:favorites',
|
||||
|
||||
|
@ -16,6 +16,7 @@ export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['reactions', 'notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['reactions', 'notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:reactions',
|
||||
|
||||
|
@ -12,6 +12,7 @@ export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -11,6 +11,7 @@ export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:notes',
|
||||
|
||||
|
@ -12,6 +12,7 @@ export const meta = {
|
||||
tags: ['pages'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['pages'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:pages',
|
||||
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['pages'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['pages'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['pages'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -13,6 +13,8 @@ export const meta = {
|
||||
tags: ['account'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
kind: 'write:mutes',
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['account'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:mutes',
|
||||
|
||||
|
@ -12,7 +12,10 @@ import { UserListService } from '@/core/UserListService.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
|
@ -12,6 +12,7 @@ export const meta = {
|
||||
tags: ['lists'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canCreateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -8,6 +8,7 @@ export const meta = {
|
||||
tags: ['lists'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canDeleteContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -7,6 +7,8 @@ import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
errors: {
|
||||
noSuchList: {
|
||||
message: 'No such user list.',
|
||||
|
@ -11,6 +11,7 @@ export const meta = {
|
||||
tags: ['lists', 'users'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -11,6 +11,7 @@ export const meta = {
|
||||
tags: ['lists', 'users'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
prohibitMoved: true,
|
||||
|
||||
|
@ -6,6 +6,8 @@ import { DI } from '@/di-symbols.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
errors: {
|
||||
noSuchList: {
|
||||
message: 'No such user list.',
|
||||
|
@ -9,6 +9,7 @@ export const meta = {
|
||||
tags: ['lists'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -10,6 +10,7 @@ export const meta = {
|
||||
tags: ['account'],
|
||||
|
||||
requireCredential: true,
|
||||
requireRolePolicy: 'canUpdateContent',
|
||||
|
||||
kind: 'write:account',
|
||||
|
||||
|
@ -91,6 +91,7 @@ describe('ユーザー', () => {
|
||||
bannerBlurhash: user.bannerBlurhash,
|
||||
isLocked: user.isLocked,
|
||||
isSilenced: user.isSilenced,
|
||||
isLimited: user.isLimited,
|
||||
isSuspended: user.isSuspended,
|
||||
description: user.description,
|
||||
location: user.location,
|
||||
@ -356,6 +357,7 @@ describe('ユーザー', () => {
|
||||
assert.strictEqual(response.bannerBlurhash, null);
|
||||
assert.strictEqual(response.isLocked, false);
|
||||
assert.strictEqual(response.isSilenced, false);
|
||||
assert.strictEqual(response.isLimited, false);
|
||||
assert.strictEqual(response.isSuspended, false);
|
||||
assert.strictEqual(response.description, null);
|
||||
assert.strictEqual(response.location, null);
|
||||
|
@ -99,6 +99,7 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi
|
||||
isModerator: false,
|
||||
isMuted: false,
|
||||
isSilenced: false,
|
||||
isLimited: false,
|
||||
isSuspended: false,
|
||||
lang: 'en',
|
||||
location: 'Fediverse',
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-adaptive-bg :class="[$style.root, { yellow: user.isSilenced, red: user.isSuspended, gray: false }]">
|
||||
<div v-adaptive-bg :class="[$style.root, { yellow: user.isSilenced, gray: user.isLimited, red: user.isSuspended }]">
|
||||
<MkAvatar class="avatar" :user="user" indicator/>
|
||||
<div class="body">
|
||||
<span class="name"><MkUserName class="name" :user="user"/></span>
|
||||
|
@ -56,6 +56,9 @@ export const ROLE_POLICIES = [
|
||||
'gtlAvailable',
|
||||
'ltlAvailable',
|
||||
'canPublicNote',
|
||||
'canCreateContent',
|
||||
'canUpdateContent',
|
||||
'canDeleteContent',
|
||||
'canInvite',
|
||||
'inviteLimit',
|
||||
'inviteLimitCycle',
|
||||
|
@ -155,6 +155,66 @@
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canCreateContent, 'canCreateContent'])">
|
||||
<template #label>{{ i18n.ts._role._options.canCreateContent }}</template>
|
||||
<template #suffix>
|
||||
<span v-if="role.policies.canCreateContent.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
|
||||
<span v-else>{{ role.policies.canCreateContent.value ? i18n.ts.yes : i18n.ts.no }}</span>
|
||||
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.canCreateContent)"></i></span>
|
||||
</template>
|
||||
<div class="_gaps">
|
||||
<MkSwitch v-model="role.policies.canCreateContent.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="role.policies.canCreateContent.value" :disabled="role.policies.canCreateContent.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
<MkRange v-model="role.policies.canCreateContent.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
||||
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||
</MkRange>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUpdateContent, 'canUpdateContent'])">
|
||||
<template #label>{{ i18n.ts._role._options.canUpdateContent }}</template>
|
||||
<template #suffix>
|
||||
<span v-if="role.policies.canUpdateContent.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
|
||||
<span v-else>{{ role.policies.canUpdateContent.value ? i18n.ts.yes : i18n.ts.no }}</span>
|
||||
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.canUpdateContent)"></i></span>
|
||||
</template>
|
||||
<div class="_gaps">
|
||||
<MkSwitch v-model="role.policies.canUpdateContent.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="role.policies.canUpdateContent.value" :disabled="role.policies.canUpdateContent.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
<MkRange v-model="role.policies.canUpdateContent.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
||||
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||
</MkRange>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canDeleteContent, 'canDeleteContent'])">
|
||||
<template #label>{{ i18n.ts._role._options.canDeleteContent }}</template>
|
||||
<template #suffix>
|
||||
<span v-if="role.policies.canDeleteContent.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
|
||||
<span v-else>{{ role.policies.canDeleteContent.value ? i18n.ts.yes : i18n.ts.no }}</span>
|
||||
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.canDeleteContent)"></i></span>
|
||||
</template>
|
||||
<div class="_gaps">
|
||||
<MkSwitch v-model="role.policies.canDeleteContent.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="role.policies.canDeleteContent.value" :disabled="role.policies.canDeleteContent.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
<MkRange v-model="role.policies.canDeleteContent.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
||||
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||
</MkRange>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canInvite, 'canInvite'])">
|
||||
<template #label>{{ i18n.ts._role._options.canInvite }}</template>
|
||||
<template #suffix>
|
||||
|
@ -43,6 +43,30 @@
|
||||
</MkSwitch>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canCreateContent, 'canCreateContent'])">
|
||||
<template #label>{{ i18n.ts._role._options.canCreateContent }}</template>
|
||||
<template #suffix>{{ policies.canCreateContent ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||
<MkSwitch v-model="policies.canCreateContent">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUpdateContent, 'canUpdateContent'])">
|
||||
<template #label>{{ i18n.ts._role._options.canUpdateContent }}</template>
|
||||
<template #suffix>{{ policies.canUpdateContent ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||
<MkSwitch v-model="policies.canUpdateContent">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canDeleteContent, 'canDeleteContent'])">
|
||||
<template #label>{{ i18n.ts._role._options.canDeleteContent }}</template>
|
||||
<template #suffix>{{ policies.canDeleteContent ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||
<MkSwitch v-model="policies.canDeleteContent">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canInvite, 'canInvite'])">
|
||||
<template #label>{{ i18n.ts._role._options.canInvite }}</template>
|
||||
<template #suffix>{{ policies.canInvite ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||
@ -57,7 +81,7 @@
|
||||
<MkInput v-model="policies.inviteLimit" type="number">
|
||||
</MkInput>
|
||||
</MkFolder>
|
||||
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.inviteLimitCycle, 'inviteLimitCycle'])">
|
||||
<template #label>{{ i18n.ts._role._options.inviteLimitCycle }}</template>
|
||||
<template #suffix>{{ policies.inviteLimitCycle + i18n.ts._time.minute }}</template>
|
||||
|
@ -11,6 +11,7 @@
|
||||
<span class="sub"><span class="acct _monospace">@{{ acct(user) }}</span></span>
|
||||
<span class="state">
|
||||
<span v-if="suspended" class="suspended">Suspended</span>
|
||||
<span v-if="limited" class="limited">Limited</span>
|
||||
<span v-if="silenced" class="silenced">Silenced</span>
|
||||
<span v-if="moderator" class="moderator">Moderator</span>
|
||||
</span>
|
||||
@ -219,6 +220,7 @@ let ips = $ref(null);
|
||||
let ap = $ref(null);
|
||||
let moderator = $ref(false);
|
||||
let silenced = $ref(false);
|
||||
let limited = $ref(false);
|
||||
let suspended = $ref(false);
|
||||
let moderationNote = $ref('');
|
||||
const filesPagination = {
|
||||
@ -244,6 +246,7 @@ function createFetcher() {
|
||||
ips = _ips;
|
||||
moderator = info.isModerator;
|
||||
silenced = info.isSilenced;
|
||||
limited = info.isLimited;
|
||||
suspended = info.isSuspended;
|
||||
moderationNote = info.moderationNote;
|
||||
|
||||
@ -485,7 +488,7 @@ definePageMetadata(computed(() => ({
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .suspended, > .silenced, > .moderator {
|
||||
> .suspended, > .limited, > .silenced, > .moderator {
|
||||
display: inline-block;
|
||||
border: solid 1px;
|
||||
border-radius: 6px;
|
||||
@ -498,6 +501,11 @@ definePageMetadata(computed(() => ({
|
||||
border-color: var(--error);
|
||||
}
|
||||
|
||||
> .limited {
|
||||
color: var(--error);
|
||||
border-color: var(--error);
|
||||
}
|
||||
|
||||
> .silenced {
|
||||
color: var(--warn);
|
||||
border-color: var(--warn);
|
||||
|
@ -2770,6 +2770,7 @@ type UserDetailed = UserLite & {
|
||||
isModerator: boolean;
|
||||
isMuted: boolean;
|
||||
isSilenced: boolean;
|
||||
isLimited: boolean;
|
||||
isSuspended: boolean;
|
||||
lang: string | null;
|
||||
lastFetchedAt?: DateString;
|
||||
|
@ -53,6 +53,7 @@ export type UserDetailed = UserLite & {
|
||||
isModerator: boolean;
|
||||
isMuted: boolean;
|
||||
isSilenced: boolean;
|
||||
isLimited: boolean;
|
||||
isSuspended: boolean;
|
||||
lang: string | null;
|
||||
lastFetchedAt?: DateString;
|
||||
@ -410,7 +411,7 @@ export type Announcement = {
|
||||
imageUrl: string | null;
|
||||
isRead?: boolean;
|
||||
isPrivate: boolean;
|
||||
closeDuration: number;
|
||||
closeDuration: number;
|
||||
};
|
||||
|
||||
export type Antenna = {
|
||||
|
Loading…
Reference in New Issue
Block a user