From 560bb6538413a1e969a1177a739b18bfa91391e3 Mon Sep 17 00:00:00 2001
From: mei23 <m@m544.net>
Date: Wed, 31 Oct 2018 04:59:01 +0900
Subject: [PATCH] blockings list

---
 locales/ja-JP.yml                             |  4 ++
 .../views/components/settings.blocking.vue    | 31 ++++++++++
 .../app/desktop/views/components/settings.vue | 10 ++++
 src/server/api/endpoints/blocking/list.ts     | 59 +++++++++++++++++++
 4 files changed, 104 insertions(+)
 create mode 100644 src/client/app/desktop/views/components/settings.blocking.vue
 create mode 100644 src/server/api/endpoints/blocking/list.ts

diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index bc7559b14b..69fde53f54 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -833,6 +833,7 @@ desktop/views/components/settings.vue:
   notification: "通知"
   apps: "アプリ"
   mute: "ミュート"
+  blocking: "ブロック"
   security: "セキュリティ"
   signin: "サインイン履歴"
   password: "パスワード"
@@ -976,6 +977,9 @@ common/views/components/drive-settings.vue:
 desktop/views/components/settings.mute.vue:
   no-users: "ミュートしているユーザーはいません"
 
+desktop/views/components/settings.blocking.vue:
+  no-users: "ブロックしているユーザーはいません"
+
 desktop/views/components/settings.password.vue:
   reset: "パスワードを変更する"
   enter-current-password: "現在のパスワードを入力してください"
diff --git a/src/client/app/desktop/views/components/settings.blocking.vue b/src/client/app/desktop/views/components/settings.blocking.vue
new file mode 100644
index 0000000000..43e4bf9209
--- /dev/null
+++ b/src/client/app/desktop/views/components/settings.blocking.vue
@@ -0,0 +1,31 @@
+<template>
+<div>
+	<div class="none ui info" v-if="!fetching && users.length == 0">
+		<p>%fa:info-circle%%i18n:@no-users%</p>
+	</div>
+	<div class="users" v-if="users.length != 0">
+		<div v-for="user in users" :key="user.id">
+			<p><b>{{ user | userName }}</b> @{{ user | acct }}</p>
+		</div>
+	</div>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+
+export default Vue.extend({
+	data() {
+		return {
+			fetching: true,
+			users: []
+		};
+	},
+	mounted() {
+		(this as any).api('blocking/list').then(x => {
+			this.users = x.users;
+			this.fetching = false;
+		});
+	}
+});
+</script>
diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue
index b5c02e486e..e77320bef3 100644
--- a/src/client/app/desktop/views/components/settings.vue
+++ b/src/client/app/desktop/views/components/settings.vue
@@ -8,6 +8,7 @@
 		<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'">%fa:cloud .fw%%i18n:common.drive%</p>
 		<p :class="{ active: page == 'hashtags' }" @mousedown="page = 'hashtags'">%fa:hashtag .fw%%i18n:@tags%</p>
 		<p :class="{ active: page == 'mute' }" @mousedown="page = 'mute'">%fa:ban .fw%%i18n:@mute%</p>
+		<p :class="{ active: page == 'blocking' }" @mousedown="page = 'blocking'">%fa:ban .fw%%i18n:@blocking%</p>
 		<p :class="{ active: page == 'apps' }" @mousedown="page = 'apps'">%fa:puzzle-piece .fw%%i18n:@apps%</p>
 		<p :class="{ active: page == 'security' }" @mousedown="page = 'security'">%fa:unlock-alt .fw%%i18n:@security%</p>
 		<p :class="{ active: page == 'api' }" @mousedown="page = 'api'">%fa:key .fw%API</p>
@@ -207,6 +208,13 @@
 			</section>
 		</ui-card>
 
+		<ui-card class="blocking" v-show="page == 'blocking'">
+			<div slot="title">%fa:ban% %i18n:@blocking%</div>
+			<section>
+				<x-blocking/>
+			</section>
+		</ui-card>
+
 		<ui-card class="apps" v-show="page == 'apps'">
 			<div slot="title">%fa:puzzle-piece% %i18n:@apps%</div>
 			<section>
@@ -290,6 +298,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import XMute from './settings.mute.vue';
+import XBlocking from './settings.blocking.vue';
 import XPassword from './settings.password.vue';
 import X2fa from './settings.2fa.vue';
 import XApps from './settings.apps.vue';
@@ -301,6 +310,7 @@ import checkForUpdate from '../../../common/scripts/check-for-update';
 export default Vue.extend({
 	components: {
 		XMute,
+		XBlocking,
 		XPassword,
 		X2fa,
 		XApps,
diff --git a/src/server/api/endpoints/blocking/list.ts b/src/server/api/endpoints/blocking/list.ts
new file mode 100644
index 0000000000..ba1c77d2c7
--- /dev/null
+++ b/src/server/api/endpoints/blocking/list.ts
@@ -0,0 +1,59 @@
+import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
+import Blocking from '../../../../models/blocking';
+import { pack, ILocalUser } from '../../../../models/user';
+
+export const meta = {
+	desc: {
+		'ja-JP': 'ブロックしているユーザー一覧を取得します。',
+		'en-US': 'Get blocking users.'
+	},
+
+	requireCredential: true,
+
+	kind: 'following-read'
+};
+
+export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
+	// Get 'limit' parameter
+	const [limit = 30, limitErr] = $.num.optional.range(1, 100).get(params.limit);
+	if (limitErr) return rej('invalid limit param');
+
+	// Get 'cursor' parameter
+	const [cursor = null, cursorErr] = $.type(ID).optional.get(params.cursor);
+	if (cursorErr) return rej('invalid cursor param');
+
+	// Construct query
+	const query = {
+		blockerId: me._id
+	} as any;
+
+	// カーソルが指定されている場合
+	if (cursor) {
+		query._id = {
+			$lt: cursor
+		};
+	}
+
+	// Get blockings
+	const blockings = await Blocking
+		.find(query, {
+			limit: limit + 1,
+			sort: { _id: -1 }
+		});
+
+	// 「次のページ」があるかどうか
+	const inStock = blockings.length === limit + 1;
+	if (inStock) {
+		blockings.pop();
+	}
+
+	// Serialize
+	const users = await Promise.all(blockings.map(async m =>
+		await pack(m.blockeeId, me, { detail: true })));
+
+	// Response
+	res({
+		users: users,
+		next: inStock ? blockings[blockings.length - 1]._id : null,
+	});
+});