操作ブロックの挙動をサービス側に移動

This commit is contained in:
kakkokari-gtyih 2024-10-18 17:41:51 +09:00
parent 0978aa429a
commit a3d77f3185
10 changed files with 110 additions and 61 deletions

View File

@ -8,6 +8,8 @@ import { ModuleRef } from '@nestjs/core';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import type { MiUser } from '@/models/User.js'; import type { MiUser } from '@/models/User.js';
import type { MiBlocking } from '@/models/Blocking.js'; import type { MiBlocking } from '@/models/Blocking.js';
import type { MiMeta } from '@/models/Meta.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { QueueService } from '@/core/QueueService.js'; import { QueueService } from '@/core/QueueService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
@ -20,6 +22,7 @@ import { UserWebhookService } from '@/core/UserWebhookService.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { CacheService } from '@/core/CacheService.js'; import { CacheService } from '@/core/CacheService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js';
import { RoleService } from '@/core/RoleService.js';
@Injectable() @Injectable()
export class UserBlockingService implements OnModuleInit { export class UserBlockingService implements OnModuleInit {
@ -29,6 +32,9 @@ export class UserBlockingService implements OnModuleInit {
constructor( constructor(
private moduleRef: ModuleRef, private moduleRef: ModuleRef,
@Inject(DI.meta)
private serverSettings: MiMeta,
@Inject(DI.followRequestsRepository) @Inject(DI.followRequestsRepository)
private followRequestsRepository: FollowRequestsRepository, private followRequestsRepository: FollowRequestsRepository,
@ -41,6 +47,7 @@ export class UserBlockingService implements OnModuleInit {
@Inject(DI.userListMembershipsRepository) @Inject(DI.userListMembershipsRepository)
private userListMembershipsRepository: UserListMembershipsRepository, private userListMembershipsRepository: UserListMembershipsRepository,
private roleService: RoleService,
private cacheService: CacheService, private cacheService: CacheService,
private userEntityService: UserEntityService, private userEntityService: UserEntityService,
private idService: IdService, private idService: IdService,
@ -59,6 +66,15 @@ export class UserBlockingService implements OnModuleInit {
@bindThis @bindThis
public async block(blocker: MiUser, blockee: MiUser, silent = false) { public async block(blocker: MiUser, blockee: MiUser, silent = false) {
// フォロー解除できない(=ブロックもできない)ユーザーの場合
if (
this.serverSettings.forciblyFollowedUsers.includes(blockee.id) &&
!await this.roleService.isModerator(blocker)
) {
throw new IdentifiableError('e2f04d25-0d94-4ac3-a4d8-ba401062741b', 'You cannot block that user due to server policy.');
}
await Promise.all([ await Promise.all([
this.cancelRequest(blocker, blockee, silent), this.cancelRequest(blocker, blockee, silent),
this.cancelRequest(blockee, blocker, silent), this.cancelRequest(blockee, blocker, silent),

View File

@ -27,6 +27,7 @@ import { CacheService } from '@/core/CacheService.js';
import type { Config } from '@/config.js'; import type { Config } from '@/config.js';
import { AccountMoveService } from '@/core/AccountMoveService.js'; import { AccountMoveService } from '@/core/AccountMoveService.js';
import { UtilityService } from '@/core/UtilityService.js'; import { UtilityService } from '@/core/UtilityService.js';
import { RoleService } from '@/core/RoleService.js';
import type { ThinUser } from '@/queue/types.js'; import type { ThinUser } from '@/queue/types.js';
import Logger from '../logger.js'; import Logger from '../logger.js';
@ -73,6 +74,7 @@ export class UserFollowingService implements OnModuleInit {
@Inject(DI.instancesRepository) @Inject(DI.instancesRepository)
private instancesRepository: InstancesRepository, private instancesRepository: InstancesRepository,
private roleService: RoleService,
private cacheService: CacheService, private cacheService: CacheService,
private utilityService: UtilityService, private utilityService: UtilityService,
private userEntityService: UserEntityService, private userEntityService: UserEntityService,
@ -365,13 +367,22 @@ export class UserFollowingService implements OnModuleInit {
@bindThis @bindThis
public async unfollow( public async unfollow(
follower: { follower: {
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox']; id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; isRoot: MiUser['isRoot']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
}, },
followee: { followee: {
id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox']; id: MiUser['id']; host: MiUser['host']; uri: MiUser['host']; inbox: MiUser['inbox']; sharedInbox: MiUser['sharedInbox'];
}, },
silent = false, silent = false,
): Promise<void> { ): Promise<void> {
// フォロー解除できないユーザーの場合
if (
this.meta.forciblyFollowedUsers.includes(followee.id) &&
!await this.roleService.isModerator(follower)
) {
throw new IdentifiableError('19f25f61-0141-4683-99dc-217a88d633cb', 'You cannot unfollow that user due to server policy.');
}
const following = await this.followingsRepository.findOne({ const following = await this.followingsRepository.findOne({
relations: { relations: {
follower: true, follower: true,

View File

@ -5,19 +5,26 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { In } from 'typeorm'; import { In } from 'typeorm';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import type { MutingsRepository, MiMuting } from '@/models/_.js'; import type { MutingsRepository, MiMuting } from '@/models/_.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import type { MiUser } from '@/models/User.js'; import type { MiUser } from '@/models/User.js';
import type { MiMeta } from '@/models/Meta.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { CacheService } from '@/core/CacheService.js'; import { CacheService } from '@/core/CacheService.js';
@Injectable() @Injectable()
export class UserMutingService { export class UserMutingService {
constructor( constructor(
@Inject(DI.meta)
private serverSettings: MiMeta,
@Inject(DI.mutingsRepository) @Inject(DI.mutingsRepository)
private mutingsRepository: MutingsRepository, private mutingsRepository: MutingsRepository,
private roleService: RoleService,
private idService: IdService, private idService: IdService,
private cacheService: CacheService, private cacheService: CacheService,
) { ) {
@ -25,6 +32,15 @@ export class UserMutingService {
@bindThis @bindThis
public async mute(user: MiUser, target: MiUser, expiresAt: Date | null = null): Promise<void> { public async mute(user: MiUser, target: MiUser, expiresAt: Date | null = null): Promise<void> {
// フォロー解除できない(=ミュートもできない)ユーザーの場合
if (
this.serverSettings.forciblyFollowedUsers.includes(target.id) &&
!await this.roleService.isModerator(user)
) {
throw new IdentifiableError('15273a89-374d-49fa-8df6-8bb3feeea455', 'You cannot mute that user due to server policy.');
}
await this.mutingsRepository.insert({ await this.mutingsRepository.insert({
id: this.idService.gen(), id: this.idService.gen(),
expiresAt: expiresAt ?? null, expiresAt: expiresAt ?? null,

View File

@ -10,16 +10,23 @@ import type { MiRenoteMuting } from '@/models/RenoteMuting.js';
import { IdService } from '@/core/IdService.js'; import { IdService } from '@/core/IdService.js';
import type { MiUser } from '@/models/User.js'; import type { MiUser } from '@/models/User.js';
import type { MiMeta } from '@/models/Meta.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { CacheService } from '@/core/CacheService.js'; import { CacheService } from '@/core/CacheService.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
@Injectable() @Injectable()
export class UserRenoteMutingService { export class UserRenoteMutingService {
constructor( constructor(
@Inject(DI.meta)
private serverSettings: MiMeta,
@Inject(DI.renoteMutingsRepository) @Inject(DI.renoteMutingsRepository)
private renoteMutingsRepository: RenoteMutingsRepository, private renoteMutingsRepository: RenoteMutingsRepository,
private roleService: RoleService,
private idService: IdService, private idService: IdService,
private cacheService: CacheService, private cacheService: CacheService,
) { ) {
@ -27,6 +34,15 @@ export class UserRenoteMutingService {
@bindThis @bindThis
public async mute(user: MiUser, target: MiUser, expiresAt: Date | null = null): Promise<void> { public async mute(user: MiUser, target: MiUser, expiresAt: Date | null = null): Promise<void> {
// フォロー解除できない(=リノートミュートもできない)ユーザーの場合
if (
this.serverSettings.forciblyFollowedUsers.includes(target.id) &&
!await this.roleService.isModerator(user)
) {
throw new IdentifiableError('15273a89-374d-49fa-8df6-8bb3feeea455', 'You cannot mute that user due to server policy.');
}
await this.renoteMutingsRepository.insert({ await this.renoteMutingsRepository.insert({
id: this.idService.gen(), id: this.idService.gen(),
muterId: user.id, muterId: user.id,

View File

@ -17,6 +17,7 @@ import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js'; import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq'; import type * as Bull from 'bullmq';
import type { DbUserImportJobData } from '../types.js'; import type { DbUserImportJobData } from '../types.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
@Injectable() @Injectable()
export class ImportMutingProcessorService { export class ImportMutingProcessorService {
@ -90,7 +91,13 @@ export class ImportMutingProcessorService {
this.logger.info(`Mute[${linenum}] ${target.id} ...`); this.logger.info(`Mute[${linenum}] ${target.id} ...`);
await this.userMutingService.mute(user, target); await this.userMutingService.mute(user, target).catch((err) => {
if (err instanceof IdentifiableError && err.id === '15273a89-374d-49fa-8df6-8bb3feeea455') {
// フォロー解除できない(=ミュートもできない)ユーザー。動作は正常のため、エラーを無視する
return;
}
throw err;
});
} catch (e) { } catch (e) {
this.logger.warn(`Error in line:${linenum} ${e}`); this.logger.warn(`Error in line:${linenum} ${e}`);
} }

View File

@ -16,6 +16,7 @@ import { MiLocalUser, MiRemoteUser } from '@/models/User.js';
import { RelationshipJobData } from '../types.js'; import { RelationshipJobData } from '../types.js';
import { QueueLoggerService } from '../QueueLoggerService.js'; import { QueueLoggerService } from '../QueueLoggerService.js';
import type * as Bull from 'bullmq'; import type * as Bull from 'bullmq';
import { IdentifiableError } from '@/misc/identifiable-error.js';
@Injectable() @Injectable()
export class RelationshipProcessorService { export class RelationshipProcessorService {
@ -50,7 +51,13 @@ export class RelationshipProcessorService {
this.usersRepository.findOneByOrFail({ id: job.data.from.id }), this.usersRepository.findOneByOrFail({ id: job.data.from.id }),
this.usersRepository.findOneByOrFail({ id: job.data.to.id }), this.usersRepository.findOneByOrFail({ id: job.data.to.id }),
]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser]; ]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
await this.userFollowingService.unfollow(follower, followee, job.data.silent); await this.userFollowingService.unfollow(follower, followee, job.data.silent).catch((err) => {
if (err instanceof IdentifiableError && err.id === '19f25f61-0141-4683-99dc-217a88d633cb') {
// フォロー解除できないユーザー。動作は正常のため、エラーを無視する
return;
}
throw err;
});
return 'ok'; return 'ok';
} }
@ -61,7 +68,13 @@ export class RelationshipProcessorService {
this.usersRepository.findOneByOrFail({ id: job.data.from.id }), this.usersRepository.findOneByOrFail({ id: job.data.from.id }),
this.usersRepository.findOneByOrFail({ id: job.data.to.id }), this.usersRepository.findOneByOrFail({ id: job.data.to.id }),
]); ]);
await this.userBlockingService.block(blockee, blocker, job.data.silent); await this.userBlockingService.block(blockee, blocker, job.data.silent).catch((err) => {
if (err instanceof IdentifiableError && err.id === 'e2f04d25-0d94-4ac3-a4d8-ba401062741b') {
// フォロー解除できない(=ブロックもできない)ユーザー。動作は正常のため、エラーを無視する
return;
}
throw err;
});
return 'ok'; return 'ok';
} }

View File

@ -7,13 +7,12 @@ import ms from 'ms';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository, BlockingsRepository } from '@/models/_.js'; import type { UsersRepository, BlockingsRepository } from '@/models/_.js';
import type { MiMeta } from '@/models/Meta.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js';
import { RoleService } from '@/core/RoleService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js'; import { ApiError } from '../../error.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
export const meta = { export const meta = {
tags: ['account'], tags: ['account'],
@ -72,16 +71,12 @@ export const paramDef = {
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.meta)
private serverSettings: MiMeta,
@Inject(DI.usersRepository) @Inject(DI.usersRepository)
private usersRepository: UsersRepository, private usersRepository: UsersRepository,
@Inject(DI.blockingsRepository) @Inject(DI.blockingsRepository)
private blockingsRepository: BlockingsRepository, private blockingsRepository: BlockingsRepository,
private roleService: RoleService,
private userEntityService: UserEntityService, private userEntityService: UserEntityService,
private getterService: GetterService, private getterService: GetterService,
private userBlockingService: UserBlockingService, private userBlockingService: UserBlockingService,
@ -96,7 +91,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
// Get blockee // Get blockee
const blockee = await this.getterService.getUser(ps.userId).catch(err => { const blockee = await this.getterService.getUser(ps.userId).catch(err => {
if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); if (err instanceof IdentifiableError && err.id === '15348ddd-432d-49c2-8a5a-8069753becff') {
throw new ApiError(meta.errors.noSuchUser);
}
throw err; throw err;
}); });
@ -112,14 +109,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.alreadyBlocking); throw new ApiError(meta.errors.alreadyBlocking);
} }
if ( await this.userBlockingService.block(blocker, blockee).catch((err) => {
this.serverSettings.forciblyFollowedUsers.includes(blockee.id) && if (err instanceof IdentifiableError && err.id === meta.errors.cannotBlockDueToServerPolicy.id) {
!await this.roleService.isModerator(blocker) throw new ApiError(meta.errors.cannotBlockDueToServerPolicy);
) { }
throw new ApiError(meta.errors.cannotBlockDueToServerPolicy); });
}
await this.userBlockingService.block(blocker, blockee);
return await this.userEntityService.pack(blockee.id, blocker, { return await this.userEntityService.pack(blockee.id, blocker, {
schema: 'UserDetailedNotMe', schema: 'UserDetailedNotMe',

View File

@ -7,10 +7,9 @@ import ms from 'ms';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import type { FollowingsRepository } from '@/models/_.js'; import type { FollowingsRepository } from '@/models/_.js';
import type { MiMeta } from '@/models/Meta.js'; import { IdentifiableError } from '@/misc/identifiable-error.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js';
import { RoleService } from '@/core/RoleService.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js'; import { ApiError } from '../../error.js';
@ -72,13 +71,9 @@ export const paramDef = {
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.meta)
private serverSettings: MiMeta,
@Inject(DI.followingsRepository) @Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository, private followingsRepository: FollowingsRepository,
private roleService: RoleService,
private userEntityService: UserEntityService, private userEntityService: UserEntityService,
private getterService: GetterService, private getterService: GetterService,
private userFollowingService: UserFollowingService, private userFollowingService: UserFollowingService,
@ -109,14 +104,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.notFollowing); throw new ApiError(meta.errors.notFollowing);
} }
if ( await this.userFollowingService.unfollow(follower, followee).catch((err) => {
this.serverSettings.forciblyFollowedUsers.includes(followee.id) && if (err instanceof IdentifiableError && err.id === meta.errors.cannotUnfollowDueToServerPolicy.id) {
!await this.roleService.isModerator(follower) throw new ApiError(meta.errors.cannotUnfollowDueToServerPolicy);
) { }
throw new ApiError(meta.errors.cannotUnfollowDueToServerPolicy); });
}
await this.userFollowingService.unfollow(follower, followee);
return await this.userEntityService.pack(followee.id, me); return await this.userEntityService.pack(followee.id, me);
}); });

View File

@ -7,12 +7,11 @@ import { Inject, Injectable } from '@nestjs/common';
import ms from 'ms'; import ms from 'ms';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import type { MutingsRepository } from '@/models/_.js'; import type { MutingsRepository } from '@/models/_.js';
import type { MiMeta } from '@/models/Meta.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { UserMutingService } from '@/core/UserMutingService.js'; import { UserMutingService } from '@/core/UserMutingService.js';
import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../error.js'; import { ApiError } from '../../error.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
export const meta = { export const meta = {
tags: ['account'], tags: ['account'],
@ -71,13 +70,9 @@ export const paramDef = {
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.meta)
private serverSettings: MiMeta,
@Inject(DI.mutingsRepository) @Inject(DI.mutingsRepository)
private mutingsRepository: MutingsRepository, private mutingsRepository: MutingsRepository,
private roleService: RoleService,
private getterService: GetterService, private getterService: GetterService,
private userMutingService: UserMutingService, private userMutingService: UserMutingService,
) { ) {
@ -107,18 +102,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.alreadyMuting); throw new ApiError(meta.errors.alreadyMuting);
} }
if (
this.serverSettings.forciblyFollowedUsers.includes(mutee.id) &&
!await this.roleService.isModerator(muter)
) {
throw new ApiError(meta.errors.cannotMuteDueToServerPolicy);
}
if (ps.expiresAt && ps.expiresAt <= Date.now()) { if (ps.expiresAt && ps.expiresAt <= Date.now()) {
return; return;
} }
await this.userMutingService.mute(muter, mutee, ps.expiresAt ? new Date(ps.expiresAt) : null); await this.userMutingService.mute(muter, mutee, ps.expiresAt ? new Date(ps.expiresAt) : null).catch((err) => {
if (err instanceof IdentifiableError && err.id === meta.errors.cannotMuteDueToServerPolicy.id) {
throw new ApiError(meta.errors.cannotMuteDueToServerPolicy);
}
});
}); });
} }
} }

View File

@ -9,10 +9,9 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { GetterService } from '@/server/api/GetterService.js'; import { GetterService } from '@/server/api/GetterService.js';
import { ApiError } from '../../error.js'; import { ApiError } from '../../error.js';
import { RoleService } from '@/core/RoleService.js';
import { UserRenoteMutingService } from '@/core/UserRenoteMutingService.js'; import { UserRenoteMutingService } from '@/core/UserRenoteMutingService.js';
import type { RenoteMutingsRepository } from '@/models/_.js'; import type { RenoteMutingsRepository } from '@/models/_.js';
import type { MiMeta } from '@/models/Meta.js'; import { IdentifiableError } from '@/misc/identifiable-error.js';
export const meta = { export const meta = {
tags: ['account'], tags: ['account'],
@ -66,13 +65,9 @@ export const paramDef = {
@Injectable() @Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor( constructor(
@Inject(DI.meta)
private serverSettings: MiMeta,
@Inject(DI.renoteMutingsRepository) @Inject(DI.renoteMutingsRepository)
private renoteMutingsRepository: RenoteMutingsRepository, private renoteMutingsRepository: RenoteMutingsRepository,
private roleService: RoleService,
private getterService: GetterService, private getterService: GetterService,
private userRenoteMutingService: UserRenoteMutingService, private userRenoteMutingService: UserRenoteMutingService,
) { ) {
@ -102,15 +97,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.alreadyMuting); throw new ApiError(meta.errors.alreadyMuting);
} }
if (
this.serverSettings.forciblyFollowedUsers.includes(mutee.id) &&
!await this.roleService.isModerator(muter)
) {
throw new ApiError(meta.errors.cannotMuteDueToServerPolicy);
}
// Create mute // Create mute
await this.userRenoteMutingService.mute(muter, mutee); await this.userRenoteMutingService.mute(muter, mutee).catch((err) => {
if (err instanceof IdentifiableError && err.id === meta.errors.cannotMuteDueToServerPolicy.id) {
throw new ApiError(meta.errors.cannotMuteDueToServerPolicy);
}
});
}); });
} }
} }