From 8818648740921b678095eff483a368677b58c4ad Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Wed, 5 Feb 2020 10:15:09 +0900
Subject: [PATCH] =?UTF-8?q?=E3=83=97=E3=83=AD=E3=82=AD=E3=82=B7=E3=82=A2?=
 =?UTF-8?q?=E3=82=AB=E3=82=A6=E3=83=B3=E3=83=88=E3=82=92=E3=83=A6=E3=83=BC?=
 =?UTF-8?q?=E3=82=B6=E3=83=BC=E5=90=8D=E3=81=A7=E3=81=AF=E3=81=AA=E3=81=8F?=
 =?UTF-8?q?ID=E3=81=A7=E4=BF=9D=E5=AD=98=E3=81=99=E3=82=8B=E3=82=88?=
 =?UTF-8?q?=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 CHANGELOG.md                                  |  1 +
 migration/1580864313253-v12-14.ts             | 20 +++++++++++++++
 src/client/pages/instance/index.vue           | 25 ++++++++++++++-----
 src/misc/fetch-proxy-account.ts               |  6 ++---
 src/models/entities/meta.ts                   | 18 +++++++++----
 src/server/api/endpoints/admin/update-meta.ts | 11 ++++----
 src/server/api/endpoints/meta.ts              |  2 +-
 src/services/user-list/push.ts                |  6 +++--
 8 files changed, 67 insertions(+), 22 deletions(-)
 create mode 100644 migration/1580864313253-v12-14.ts

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 25b6dedf6b..34a8211fd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ v12ではいくつかインスタンスにとって破壊的な変更があり
 * 通知がリセットされます。
 * アカウントの外部サービス連携情報がリセットされます。
 * インスタンスの閉鎖情報がリセットされます。
+* プロキシアカウント設定情報がリセットされます。
 * モデレーターがインスタンス設定を閲覧したり変更したりできなくなります(それらができるのはAdminのみになります)。
 	* モデレーターが出来るのは、ユーザーのサイレンス/凍結などに限られます。
 	* 従来と同じ権限を与えたい場合、モデレーターをAdminに設定することを検討してください(Adminは複数人設定可能です)。
diff --git a/migration/1580864313253-v12-14.ts b/migration/1580864313253-v12-14.ts
new file mode 100644
index 0000000000..7bf38e5c65
--- /dev/null
+++ b/migration/1580864313253-v12-14.ts
@@ -0,0 +1,20 @@
+import {MigrationInterface, QueryRunner} from "typeorm";
+
+export class v12141580864313253 implements MigrationInterface {
+    name = 'v12141580864313253'
+
+    public async up(queryRunner: QueryRunner): Promise<any> {
+        await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "proxyAccount" TO "proxyAccountId"`, undefined);
+        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyAccountId"`, undefined);
+        await queryRunner.query(`ALTER TABLE "meta" ADD "proxyAccountId" character varying(32)`, undefined);
+        await queryRunner.query(`ALTER TABLE "meta" ADD CONSTRAINT "FK_ab1bc0c1e209daa77b8e8d212ad" FOREIGN KEY ("proxyAccountId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`, undefined);
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<any> {
+        await queryRunner.query(`ALTER TABLE "meta" DROP CONSTRAINT "FK_ab1bc0c1e209daa77b8e8d212ad"`, undefined);
+        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyAccountId"`, undefined);
+        await queryRunner.query(`ALTER TABLE "meta" ADD "proxyAccountId" character varying(128)`, undefined);
+        await queryRunner.query(`ALTER TABLE "meta" RENAME COLUMN "proxyAccountId" TO "proxyAccount"`, undefined);
+    }
+
+}
diff --git a/src/client/pages/instance/index.vue b/src/client/pages/instance/index.vue
index bdd04b635b..3d0f10705a 100644
--- a/src/client/pages/instance/index.vue
+++ b/src/client/pages/instance/index.vue
@@ -100,10 +100,8 @@
 	<section class="_card">
 		<div class="_title"><fa :icon="faGhost"/> {{ $t('proxyAccount') }}</div>
 		<div class="_content">
-			<mk-input v-model="proxyAccount" style="margin: 0;"><template #prefix>@</template>{{ $t('proxyAccount') }}<template #desc>{{ $t('proxyAccountDescription') }}</template></mk-input>
-		</div>
-		<div class="_footer">
-			<mk-button primary @click="save(true)"><fa :icon="faSave"/> {{ $t('save') }}</mk-button>
+			<mk-input :value="proxyAccount ? proxyAccount.username : null" style="margin: 0;" disabled><template #prefix>@</template>{{ $t('proxyAccount') }}<template #desc>{{ $t('proxyAccountDescription') }}</template></mk-input>
+			<mk-button primary @click="chooseProxyAccount">{{ $t('chooseProxyAccount') }}</mk-button>
 		</div>
 	</section>
 
@@ -210,6 +208,7 @@ export default Vue.extend({
 			stats: null,
 			serverInfo: null,
 			proxyAccount: null,
+			proxyAccountId: null,
 			cacheRemoteFiles: false,
 			proxyRemoteFiles: false,
 			localDriveCapacityMb: 0,
@@ -261,7 +260,7 @@ export default Vue.extend({
 			this.enableRecaptcha = this.meta.enableRecaptcha;
 			this.recaptchaSiteKey = this.meta.recaptchaSiteKey;
 			this.recaptchaSecretKey = this.meta.recaptchaSecretKey;
-			this.proxyAccount = this.meta.proxyAccount;
+			this.proxyAccountId = this.meta.proxyAccountId;
 			this.cacheRemoteFiles = this.meta.cacheRemoteFiles;
 			this.proxyRemoteFiles = this.meta.proxyRemoteFiles;
 			this.localDriveCapacityMb = this.meta.driveCapacityPerLocalUserMb;
@@ -280,6 +279,12 @@ export default Vue.extend({
 			this.enableDiscordIntegration = this.meta.enableDiscordIntegration;
 			this.discordClientId = this.meta.discordClientId;
 			this.discordClientSecret = this.meta.discordClientSecret;
+
+			if (this.proxyAccountId) {
+				this.$root.api('users/show', { userId: this.proxyAccountId }).then(proxyAccount => {
+					this.proxyAccount = proxyAccount;
+				});
+			}
 		});
 
 		this.$root.api('admin/server-info').then(res => {
@@ -324,6 +329,14 @@ export default Vue.extend({
 			});
 		},
 
+		chooseProxyAccount() {
+			this.$root.new(MkUserSelect, {}).$once('selected', user => {
+				this.proxyAccount = user;
+				this.proxyAccountId = user.id;
+				this.save(true);
+			});
+		},
+
 		save(withDialog = false) {
 			this.$root.api('admin/update-meta', {
 				name: this.name,
@@ -339,7 +352,7 @@ export default Vue.extend({
 				enableRecaptcha: this.enableRecaptcha,
 				recaptchaSiteKey: this.recaptchaSiteKey,
 				recaptchaSecretKey: this.recaptchaSecretKey,
-				proxyAccount: this.proxyAccount,
+				proxyAccountId: this.proxyAccountId,
 				cacheRemoteFiles: this.cacheRemoteFiles,
 				proxyRemoteFiles: this.proxyRemoteFiles,
 				localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
diff --git a/src/misc/fetch-proxy-account.ts b/src/misc/fetch-proxy-account.ts
index 075873091c..a042c116a6 100644
--- a/src/misc/fetch-proxy-account.ts
+++ b/src/misc/fetch-proxy-account.ts
@@ -1,9 +1,9 @@
 import { fetchMeta } from './fetch-meta';
 import { ILocalUser } from '../models/entities/user';
 import { Users } from '../models';
-import { ensure } from '../prelude/ensure';
 
-export async function fetchProxyAccount(): Promise<ILocalUser> {
+export async function fetchProxyAccount(): Promise<ILocalUser | null> {
+	if (meta.proxyAccountId == null) return null;
 	const meta = await fetchMeta();
-	return await Users.findOne({ username: meta.proxyAccount!, host: null }).then(ensure) as ILocalUser;
+	return await Users.findOne(meta.proxyAccountId);
 }
diff --git a/src/models/entities/meta.ts b/src/models/entities/meta.ts
index 4063c81139..ee62cb24ba 100644
--- a/src/models/entities/meta.ts
+++ b/src/models/entities/meta.ts
@@ -1,4 +1,6 @@
-import { Entity, Column, PrimaryColumn } from 'typeorm';
+import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm';
+import { User } from './user';
+import { id } from '../id';
 
 @Entity()
 export class Meta {
@@ -110,11 +112,17 @@ export class Meta {
 	})
 	public proxyRemoteFiles: boolean;
 
-	@Column('varchar', {
-		length: 128,
-		nullable: true
+	@Column({
+		...id(),
+		nullable: true,
 	})
-	public proxyAccount: string | null;
+	public proxyAccountId: User['id'] | null;
+
+	@ManyToOne(type => User, {
+		onDelete: 'SET NULL'
+	})
+	@JoinColumn()
+	public proxyAccount: User | null;
 
 	@Column('boolean', {
 		default: false,
diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts
index 65650f1295..adcd34bd50 100644
--- a/src/server/api/endpoints/admin/update-meta.ts
+++ b/src/server/api/endpoints/admin/update-meta.ts
@@ -4,6 +4,7 @@ import { getConnection } from 'typeorm';
 import { Meta } from '../../../../models/entities/meta';
 import { insertModerationLog } from '../../../../services/insert-moderation-log';
 import { DB_MAX_NOTE_TEXT_LENGTH } from '../../../../misc/hard-limits';
+import { ID } from '../../../../misc/cafy-id';
 
 export const meta = {
 	desc: {
@@ -165,10 +166,10 @@ export const meta = {
 			}
 		},
 
-		proxyAccount: {
-			validator: $.optional.nullable.str,
+		proxyAccountId: {
+			validator: $.optional.nullable.type(ID),
 			desc: {
-				'ja-JP': 'プロキシアカウントのユーザー名'
+				'ja-JP': 'プロキシアカウントのID'
 			}
 		},
 
@@ -479,8 +480,8 @@ export default define(meta, async (ps, me) => {
 		set.recaptchaSecretKey = ps.recaptchaSecretKey;
 	}
 
-	if (ps.proxyAccount !== undefined) {
-		set.proxyAccount = ps.proxyAccount;
+	if (ps.proxyAccountId !== undefined) {
+		set.proxyAccountId = ps.proxyAccountId;
 	}
 
 	if (ps.maintainerName !== undefined) {
diff --git a/src/server/api/endpoints/meta.ts b/src/server/api/endpoints/meta.ts
index 2c605a6f0b..281d58ba9d 100644
--- a/src/server/api/endpoints/meta.ts
+++ b/src/server/api/endpoints/meta.ts
@@ -170,7 +170,7 @@ export default define(meta, async (ps, me) => {
 		response.hiddenTags = instance.hiddenTags;
 		response.blockedHosts = instance.blockedHosts;
 		response.recaptchaSecretKey = instance.recaptchaSecretKey;
-		response.proxyAccount = instance.proxyAccount;
+		response.proxyAccountId = instance.proxyAccountId;
 		response.twitterConsumerKey = instance.twitterConsumerKey;
 		response.twitterConsumerSecret = instance.twitterConsumerSecret;
 		response.githubClientId = instance.githubClientId;
diff --git a/src/services/user-list/push.ts b/src/services/user-list/push.ts
index 958d54b090..0fbeae79f0 100644
--- a/src/services/user-list/push.ts
+++ b/src/services/user-list/push.ts
@@ -22,7 +22,9 @@ export async function pushUserToUserList(target: User, list: UserList) {
 	// このインスタンス内にこのリモートユーザーをフォローしているユーザーがいなくても投稿を受け取るためにダミーのユーザーがフォローしたということにする
 	if (Users.isRemoteUser(target)) {
 		const proxy = await fetchProxyAccount();
-		const content = renderActivity(renderFollow(proxy, target));
-		deliver(proxy, content, target.inbox);
+		if (proxy) {
+			const content = renderActivity(renderFollow(proxy, target));
+			deliver(proxy, content, target.inbox);
+		}
 	}
 }