This commit is contained in:
syuilo 2025-02-21 20:34:20 +09:00
parent dde1230235
commit 271ca3f5c9
11 changed files with 55 additions and 72 deletions

4
locales/index.d.ts vendored
View File

@ -10058,6 +10058,10 @@ export interface Locale extends ILocale {
* 稿
*/
"deleteGalleryPost": string;
/**
*
*/
"updateProxyAccountDescription": string;
};
"_fileViewer": {
/**

View File

@ -2664,6 +2664,7 @@ _moderationLogTypes:
deletePage: "ページを削除"
deleteFlash: "Playを削除"
deleteGalleryPost: "ギャラリーの投稿を削除"
updateProxyAccountDescription: "プロキシアカウントの説明を更新"
_fileViewer:
title: "ファイルの詳細"

View File

@ -133,7 +133,7 @@ const $meta: Provider = {
for (const key in body.after) {
(meta as any)[key] = (body.after as any)[key];
}
meta.proxyAccount = null; // joinなカラムは通常取ってこないので
meta.rootUser = null; // joinなカラムは通常取ってこないので
break;
}
default:

View File

@ -20,10 +20,10 @@ import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ProxyAccountService } from '@/core/ProxyAccountService.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import InstanceChart from '@/core/chart/charts/instance.js';
import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
import { SystemAccountService } from '@/core/SystemAccountService.js';
@Injectable()
export class AccountMoveService {
@ -55,12 +55,12 @@ export class AccountMoveService {
private apRendererService: ApRendererService,
private apDeliverManagerService: ApDeliverManagerService,
private globalEventService: GlobalEventService,
private proxyAccountService: ProxyAccountService,
private perUserFollowingChart: PerUserFollowingChart,
private federatedInstanceService: FederatedInstanceService,
private instanceChart: InstanceChart,
private relayService: RelayService,
private queueService: QueueService,
private systemAccountService: SystemAccountService,
) {
}
@ -126,11 +126,11 @@ export class AccountMoveService {
}
// follow the new account
const proxy = await this.proxyAccountService.fetch();
const proxy = await this.systemAccountService.fetch('proxy');
const followings = await this.followingsRepository.findBy({
followeeId: src.id,
followerHost: IsNull(), // follower is local
followerId: proxy ? Not(proxy.id) : undefined,
followerId: Not(proxy.id),
});
const followJobs = followings.map(following => ({
from: { id: following.followerId },
@ -250,10 +250,8 @@ export class AccountMoveService {
// Have the proxy account follow the new account in the same way as UserListService.push
if (this.userEntityService.isRemoteUser(dst)) {
const proxy = await this.proxyAccountService.fetch();
if (proxy) {
this.queueService.createFollowJob([{ from: { id: proxy.id }, to: { id: dst.id } }]);
}
const proxy = await this.systemAccountService.fetch('proxy');
this.queueService.createFollowJob([{ from: { id: proxy.id }, to: { id: dst.id } }]);
}
}

View File

@ -53,7 +53,7 @@ export class MetaService implements OnApplicationShutdown {
case 'metaUpdated': {
this.cache = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...(body.after),
proxyAccount: null, // joinなカラムは通常取ってこないので
rootUser: null, // joinなカラムは通常取ってこないので
};
break;
}

View File

@ -9,7 +9,7 @@ import { DataSource, IsNull } from 'typeorm';
import bcrypt from 'bcryptjs';
import { MiLocalUser, MiUser } from '@/models/User.js';
import { MiSystemAccount, MiUsedUsername, MiUserKeypair, MiUserProfile, type UsersRepository, type SystemAccountsRepository } from '@/models/_.js';
import type { UserProfilesRepository } from '@/models/_.js';
import type { MiMeta, UserProfilesRepository } from '@/models/_.js';
import { MemoryKVCache } from '@/misc/cache.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
@ -27,6 +27,9 @@ export class SystemAccountService {
@Inject(DI.db)
private db: DataSource,
@Inject(DI.meta)
private meta: MiMeta,
@Inject(DI.systemAccountsRepository)
private systemAccountsRepository: SystemAccountsRepository,
@ -64,6 +67,7 @@ export class SystemAccountService {
} else {
const created = await this.createCorrespondingUser(type, {
username: `system.${type}`,
name: this.meta.name,
});
this.cache.set(type, created);
return created;
@ -72,8 +76,8 @@ export class SystemAccountService {
@bindThis
private async createCorrespondingUser(type: typeof SYSTEM_ACCOUNT_TYPES[number], extra: {
username: string;
name?: string;
username: MiUser['username'];
name?: MiUser['name'];
}): Promise<MiLocalUser> {
const password = randomUUID();
@ -139,7 +143,7 @@ export class SystemAccountService {
@bindThis
public async updateCorrespondingUserProfile(type: typeof SYSTEM_ACCOUNT_TYPES[number], extra: {
name?: string;
description?: string;
description?: MiUserProfile['description'];
}): Promise<MiLocalUser> {
const user = await this.fetch(type);

View File

@ -15,11 +15,11 @@ import type { GlobalEvents } from '@/core/GlobalEventService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ProxyAccountService } from '@/core/ProxyAccountService.js';
import { bindThis } from '@/decorators.js';
import { QueueService } from '@/core/QueueService.js';
import { RedisKVCache } from '@/misc/cache.js';
import { RoleService } from '@/core/RoleService.js';
import { SystemAccountService } from '@/core/SystemAccountService.js';
@Injectable()
export class UserListService implements OnApplicationShutdown, OnModuleInit {
@ -43,8 +43,8 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit {
private userEntityService: UserEntityService,
private idService: IdService,
private globalEventService: GlobalEventService,
private proxyAccountService: ProxyAccountService,
private queueService: QueueService,
private systemAccountService: SystemAccountService,
) {
this.membersCache = new RedisKVCache<Set<string>>(this.redisClient, 'userListMembers', {
lifetime: 1000 * 60 * 30, // 30m
@ -111,10 +111,8 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit {
// このインスタンス内にこのリモートユーザーをフォローしているユーザーがいなくても投稿を受け取るためにダミーのユーザーがフォローしたということにする
if (this.userEntityService.isRemoteUser(target)) {
const proxy = await this.proxyAccountService.fetch();
if (proxy) {
this.queueService.createFollowJob([{ from: { id: proxy.id }, to: { id: target.id } }]);
}
const proxy = await this.systemAccountService.fetch('proxy');
this.queueService.createFollowJob([{ from: { id: proxy.id }, to: { id: target.id } }]);
}
}

View File

@ -3,18 +3,11 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import type {
UsersRepository,
} from '@/models/_.js';
import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
import { RoleService } from '@/core/RoleService.js';
import {
descriptionSchema,
nameSchema,
} from '@/models/User.js';
import { ApiError } from '@/server/api/error.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { SystemAccountService } from '@/core/SystemAccountService.js';
@ -24,52 +17,30 @@ export const meta = {
requireCredential: true,
requireModerator: true,
kind: 'write:admin:update-proxy-account',
errors: {
accessDenied: {
message: 'Only administrators can edit members of the role.',
code: 'ACCESS_DENIED',
id: '101f9105-27cb-489c-842a-69b6d2092c03',
},
},
kind: 'write:admin:account',
res: {
type: 'object',
nullable: false, optional: false,
ref: 'UserDetailed',
},
required: [],
} as const;
export const paramDef = {
type: 'object',
properties: {
name: { ...nameSchema, nullable: true },
description: { ...descriptionSchema, nullable: true },
avatarId: { type: 'string', format: 'misskey:id', nullable: true },
bannerId: { type: 'string', format: 'misskey:id', nullable: true },
},
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private roleService: RoleService,
private userEntityService: UserEntityService,
private moderationLogService: ModerationLogService,
private systemAccountService: SystemAccountService,
) {
super(meta, paramDef, async (ps, me) => {
const _me = await this.usersRepository.findOneByOrFail({ id: me.id });
if (!await this.roleService.isModerator(_me)) {
throw new ApiError(meta.errors.accessDenied);
}
const proxy = await this.systemAccountService.updateCorrespondingUserProfile('proxy', {
description: ps.description,
});
@ -78,11 +49,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
schema: 'MeDetailed',
});
this.moderationLogService.log(me, 'updateUser', {
userId: proxy.id,
userUsername: proxy.username,
userHost: proxy.host,
});
if (ps.description !== undefined) {
this.moderationLogService.log(me, 'updateProxyAccountDescription', {
before: null, //TODO
after: ps.description,
});
}
return updated;
});

View File

@ -122,6 +122,7 @@ export const moderationLogTypes = [
'deletePage',
'deleteFlash',
'deleteGalleryPost',
'updateProxyAccountDescription',
] as const;
export type ModerationLogPayloads = {
@ -374,25 +375,29 @@ export type ModerationLogPayloads = {
postUserUsername: string;
post: any;
};
updateProxyAccountDescription: {
before: string | null;
after: string | null;
};
};
export type Serialized<T> = {
[K in keyof T]:
T[K] extends Date
? string
: T[K] extends (Date | null)
? (string | null)
: T[K] extends Record<string, any>
? Serialized<T[K]>
: T[K] extends (Record<string, any> | null)
T[K] extends Date
? string
: T[K] extends (Date | null)
? (string | null)
: T[K] extends Record<string, any>
? Serialized<T[K]>
: T[K] extends (Record<string, any> | null)
? (Serialized<T[K]> | null)
: T[K] extends (Record<string, any> | undefined)
: T[K] extends (Record<string, any> | undefined)
? (Serialized<T[K]> | undefined)
: T[K];
: T[K];
};
export type FilterUnionByProperty<
Union,
Property extends string | number | symbol,
Condition
Union,
Property extends string | number | symbol,
Condition,
> = Union extends Record<Property, Condition> ? Union : never;

View File

@ -170,6 +170,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<CodeDiff :context="5" :hideHeader="true" :oldString="log.info.before ?? ''" :newString="log.info.after ?? ''" maxHeight="300px"/>
</div>
</template>
<template v-else-if="log.type === 'updateProxyAccountDescription'">
<div :class="$style.diff">
<CodeDiff :context="5" :hideHeader="true" :oldString="log.info.before ?? ''" :newString="log.info.after ?? ''" maxHeight="300px"/>
</div>
</template>
<details>
<summary>raw</summary>

View File

@ -8282,8 +8282,6 @@ export type operations = {
sensitiveMediaDetectionSensitivity: string;
setSensitiveFlagAutomatically: boolean;
enableSensitiveMediaDetectionForVideos: boolean;
/** Format: id */
proxyAccountId: string | null;
email: string | null;
smtpSecure: boolean;
smtpHost: string | null;
@ -10623,8 +10621,6 @@ export type operations = {
sensitiveMediaDetectionSensitivity?: 'medium' | 'low' | 'high' | 'veryLow' | 'veryHigh';
setSensitiveFlagAutomatically?: boolean;
enableSensitiveMediaDetectionForVideos?: boolean;
/** Format: misskey:id */
proxyAccountId?: string | null;
maintainerName?: string | null;
maintainerEmail?: string | null;
langs?: string[];