summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2018-10-31 11:17:24 +0900
committerGitHub <noreply@github.com>2018-10-31 11:17:24 +0900
commit5e3372e9329883aefa19fa572715077d79eac5be (patch)
treec259467122fa4d2add35aa413b4e9986ab6fd7ce /src
parentImplement /api/v1/instance (#3045) (diff)
parent良い感じに (diff)
downloadsharkey-5e3372e9329883aefa19fa572715077d79eac5be.tar.gz
sharkey-5e3372e9329883aefa19fa572715077d79eac5be.tar.bz2
sharkey-5e3372e9329883aefa19fa572715077d79eac5be.zip
Merge pull request #3047 from mei23/mei-1031-blokings-list
blockings list
Diffstat (limited to 'src')
-rw-r--r--src/client/app/common/views/components/index.ts2
-rw-r--r--src/client/app/common/views/components/mute-and-block.vue56
-rw-r--r--src/client/app/desktop/views/components/settings.mute.vue31
-rw-r--r--src/client/app/desktop/views/components/settings.vue13
-rw-r--r--src/client/app/mobile/views/pages/settings.vue2
-rw-r--r--src/models/blocking.ts41
-rw-r--r--src/models/mute.ts41
-rw-r--r--src/server/api/endpoints/blocking/list.ts64
-rw-r--r--src/server/api/endpoints/mute/list.ts80
9 files changed, 245 insertions, 85 deletions
diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts
index 33216e459d..2f2217f8d2 100644
--- a/src/client/app/common/views/components/index.ts
+++ b/src/client/app/common/views/components/index.ts
@@ -1,5 +1,6 @@
import Vue from 'vue';
+import muteAndBlock from './mute-and-block.vue';
import error from './error.vue';
import apiSettings from './api-settings.vue';
import driveSettings from './drive-settings.vue';
@@ -50,6 +51,7 @@ import uiInfo from './ui/info.vue';
import formButton from './ui/form/button.vue';
import formRadio from './ui/form/radio.vue';
+Vue.component('mk-mute-and-block', muteAndBlock);
Vue.component('mk-error', error);
Vue.component('mk-api-settings', apiSettings);
Vue.component('mk-drive-settings', driveSettings);
diff --git a/src/client/app/common/views/components/mute-and-block.vue b/src/client/app/common/views/components/mute-and-block.vue
new file mode 100644
index 0000000000..b244f975bb
--- /dev/null
+++ b/src/client/app/common/views/components/mute-and-block.vue
@@ -0,0 +1,56 @@
+<template>
+<ui-card>
+ <div slot="title">%fa:ban% %i18n:@mute-and-block%</div>
+
+ <section>
+ <header>%i18n:@mute%</header>
+ <ui-info v-if="!muteFetching && mute.length == 0">
+ <p>%i18n:@no-muted-users%</p>
+ </ui-info>
+ <div class="users" v-if="mute.length != 0">
+ <div v-for="user in mute" :key="user.id">
+ <p><b>{{ user | userName }}</b> @{{ user | acct }}</p>
+ </div>
+ </div>
+ </section>
+
+ <section>
+ <header>%i18n:@block%</header>
+ <ui-info v-if="!blockFetching && block.length == 0">
+ <p>%i18n:@no-blocked-users%</p>
+ </ui-info>
+ <div class="users" v-if="block.length != 0">
+ <div v-for="user in block" :key="user.id">
+ <p><b>{{ user | userName }}</b> @{{ user | acct }}</p>
+ </div>
+ </div>
+ </section>
+</ui-card>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+
+export default Vue.extend({
+ data() {
+ return {
+ muteFetching: true,
+ blockFetching: true,
+ mute: [],
+ block: []
+ };
+ },
+
+ mounted() {
+ (this as any).api('mute/list').then(mute => {
+ this.mute = mute.map(x => x.mutee);
+ this.muteFetching = false;
+ });
+
+ (this as any).api('blocking/list').then(blocking => {
+ this.block = blocking.map(x => x.blockee);
+ this.blockFetching = false;
+ });
+ }
+});
+</script>
diff --git a/src/client/app/desktop/views/components/settings.mute.vue b/src/client/app/desktop/views/components/settings.mute.vue
deleted file mode 100644
index 792afa923f..0000000000
--- a/src/client/app/desktop/views/components/settings.mute.vue
+++ /dev/null
@@ -1,31 +0,0 @@
-<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('mute/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..74cedf9ecc 100644
--- a/src/client/app/desktop/views/components/settings.vue
+++ b/src/client/app/desktop/views/components/settings.vue
@@ -7,7 +7,7 @@
<p :class="{ active: page == 'notification' }" @mousedown="page = 'notification'">%fa:R bell .fw%%i18n:@notification%</p>
<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 == 'muteAndBlock' }" @mousedown="page = 'muteAndBlock'">%fa:ban .fw%%i18n:@mute-and-block%</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>
@@ -200,12 +200,9 @@
</section>
</ui-card>
- <ui-card class="mute" v-show="page == 'mute'">
- <div slot="title">%fa:ban% %i18n:@mute%</div>
- <section>
- <x-mute/>
- </section>
- </ui-card>
+ <div class="muteAndBlock" v-show="page == 'muteAndBlock'">
+ <mk-mute-and-block/>
+ </div>
<ui-card class="apps" v-show="page == 'apps'">
<div slot="title">%fa:puzzle-piece% %i18n:@apps%</div>
@@ -289,7 +286,6 @@
<script lang="ts">
import Vue from 'vue';
-import XMute from './settings.mute.vue';
import XPassword from './settings.password.vue';
import X2fa from './settings.2fa.vue';
import XApps from './settings.apps.vue';
@@ -300,7 +296,6 @@ import checkForUpdate from '../../../common/scripts/check-for-update';
export default Vue.extend({
components: {
- XMute,
XPassword,
X2fa,
XApps,
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index b96ed59311..a77f5d4c3a 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -85,6 +85,8 @@
<mk-drive-settings/>
+ <mk-mute-and-block/>
+
<ui-card>
<div slot="title">%fa:volume-up% %i18n:@sound%</div>
diff --git a/src/models/blocking.ts b/src/models/blocking.ts
index 2974b53554..3eace3989a 100644
--- a/src/models/blocking.ts
+++ b/src/models/blocking.ts
@@ -1,7 +1,12 @@
import * as mongo from 'mongodb';
import db from '../db/mongodb';
+import isObjectId from '../misc/is-objectid';
+const deepcopy = require('deepcopy');
+import { pack as packUser } from './user';
const Blocking = db.get<IBlocking>('blocking');
+Blocking.createIndex('blockerId');
+Blocking.createIndex('blockeeId');
Blocking.createIndex(['blockerId', 'blockeeId'], { unique: true });
export default Blocking;
@@ -11,3 +16,39 @@ export type IBlocking = {
blockeeId: mongo.ObjectID;
blockerId: mongo.ObjectID;
};
+
+export const packMany = async (
+ blockings: (string | mongo.ObjectID | IBlocking)[],
+ me?: string | mongo.ObjectID | IUser
+) => {
+ return (await Promise.all(blockings.map(x => pack(x, me)))).filter(x => x != null);
+};
+
+export const pack = (
+ blocking: any,
+ me?: any
+) => new Promise<any>(async (resolve, reject) => {
+ let _blocking: any;
+
+ // Populate the blocking if 'blocking' is ID
+ if (isObjectId(blocking)) {
+ _blocking = await Blocking.findOne({
+ _id: blocking
+ });
+ } else if (typeof blocking === 'string') {
+ _blocking = await Blocking.findOne({
+ _id: new mongo.ObjectID(blocking)
+ });
+ } else {
+ _blocking = deepcopy(blocking);
+ }
+
+ // Rename _id to id
+ _blocking.id = _blocking._id;
+ delete _blocking._id;
+
+ // Populate blockee
+ _blocking.blockee = await packUser(_blocking.blockeeId, me);
+
+ resolve(_blocking);
+});
diff --git a/src/models/mute.ts b/src/models/mute.ts
index 4bad3d3d31..58536d4b9c 100644
--- a/src/models/mute.ts
+++ b/src/models/mute.ts
@@ -1,7 +1,12 @@
import * as mongo from 'mongodb';
import db from '../db/mongodb';
+import isObjectId from '../misc/is-objectid';
+const deepcopy = require('deepcopy');
+import { pack as packUser } from './user';
const Mute = db.get<IMute>('mute');
+Mute.createIndex('muterId');
+Mute.createIndex('muteeId');
Mute.createIndex(['muterId', 'muteeId'], { unique: true });
export default Mute;
@@ -11,3 +16,39 @@ export interface IMute {
muterId: mongo.ObjectID;
muteeId: mongo.ObjectID;
}
+
+export const packMany = async (
+ mutes: (string | mongo.ObjectID | IMute)[],
+ me?: string | mongo.ObjectID | IUser
+) => {
+ return (await Promise.all(mutes.map(x => pack(x, me)))).filter(x => x != null);
+};
+
+export const pack = (
+ mute: any,
+ me?: any
+) => new Promise<any>(async (resolve, reject) => {
+ let _mute: any;
+
+ // Populate the mute if 'mute' is ID
+ if (isObjectId(mute)) {
+ _mute = await Mute.findOne({
+ _id: mute
+ });
+ } else if (typeof mute === 'string') {
+ _mute = await Mute.findOne({
+ _id: new mongo.ObjectID(mute)
+ });
+ } else {
+ _mute = deepcopy(mute);
+ }
+
+ // Rename _id to id
+ _mute.id = _mute._id;
+ delete _mute._id;
+
+ // Populate mutee
+ _mute.mutee = await packUser(_mute.muteeId, me);
+
+ resolve(_mute);
+});
diff --git a/src/server/api/endpoints/blocking/list.ts b/src/server/api/endpoints/blocking/list.ts
new file mode 100644
index 0000000000..a0bef38b58
--- /dev/null
+++ b/src/server/api/endpoints/blocking/list.ts
@@ -0,0 +1,64 @@
+import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
+import Blocking, { packMany } from '../../../../models/blocking';
+import { ILocalUser } from '../../../../models/user';
+import getParams from '../../get-params';
+
+export const meta = {
+ desc: {
+ 'ja-JP': 'ブロックしているユーザー一覧を取得します。',
+ 'en-US': 'Get blocking users.'
+ },
+
+ requireCredential: true,
+
+ kind: 'following-read',
+
+ params: {
+ limit: $.num.optional.range(1, 100).note({
+ default: 30
+ }),
+
+ sinceId: $.type(ID).optional.note({
+ }),
+
+ untilId: $.type(ID).optional.note({
+ }),
+ }
+};
+
+export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
+ const [ps, psErr] = getParams(meta, params);
+ if (psErr) return rej(psErr);
+
+ // Check if both of sinceId and untilId is specified
+ if (ps.sinceId && ps.untilId) {
+ return rej('cannot set sinceId and untilId');
+ }
+
+ const query = {
+ blockerId: me._id
+ } as any;
+
+ const sort = {
+ _id: -1
+ };
+
+ if (ps.sinceId) {
+ sort._id = 1;
+ query._id = {
+ $gt: ps.sinceId
+ };
+ } else if (ps.untilId) {
+ query._id = {
+ $lt: ps.untilId
+ };
+ }
+
+ const blockings = await Blocking
+ .find(query, {
+ limit: ps.limit,
+ sort: sort
+ });
+
+ res(await packMany(blockings, me));
+});
diff --git a/src/server/api/endpoints/mute/list.ts b/src/server/api/endpoints/mute/list.ts
index 387b2396f5..4653877621 100644
--- a/src/server/api/endpoints/mute/list.ts
+++ b/src/server/api/endpoints/mute/list.ts
@@ -1,7 +1,7 @@
import $ from 'cafy'; import ID from '../../../../misc/cafy-id';
-import Mute from '../../../../models/mute';
-import { pack, ILocalUser } from '../../../../models/user';
-import { getFriendIds } from '../../common/get-friends';
+import Mute, { packMany } from '../../../../models/mute';
+import { ILocalUser } from '../../../../models/user';
+import getParams from '../../get-params';
export const meta = {
desc: {
@@ -11,64 +11,54 @@ export const meta = {
requireCredential: true,
- kind: 'account/read'
+ kind: 'account/read',
+
+ params: {
+ limit: $.num.optional.range(1, 100).note({
+ default: 30
+ }),
+
+ sinceId: $.type(ID).optional.note({
+ }),
+
+ untilId: $.type(ID).optional.note({
+ }),
+ }
};
export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
- // Get 'iknow' parameter
- const [iknow = false, iknowErr] = $.bool.optional.get(params.iknow);
- if (iknowErr) return rej('invalid iknow param');
-
- // Get 'limit' parameter
- const [limit = 30, limitErr] = $.num.optional.range(1, 100).get(params.limit);
- if (limitErr) return rej('invalid limit param');
+ const [ps, psErr] = getParams(meta, params);
+ if (psErr) return rej(psErr);
- // Get 'cursor' parameter
- const [cursor = null, cursorErr] = $.type(ID).optional.get(params.cursor);
- if (cursorErr) return rej('invalid cursor param');
+ // Check if both of sinceId and untilId is specified
+ if (ps.sinceId && ps.untilId) {
+ return rej('cannot set sinceId and untilId');
+ }
- // Construct query
const query = {
- muterId: me._id,
- deletedAt: { $exists: false }
+ muterId: me._id
} as any;
- if (iknow) {
- // Get my friends
- const myFriends = await getFriendIds(me._id);
+ const sort = {
+ _id: -1
+ };
- query.muteeId = {
- $in: myFriends
+ if (ps.sinceId) {
+ sort._id = 1;
+ query._id = {
+ $gt: ps.sinceId
};
- }
-
- // カーソルが指定されている場合
- if (cursor) {
+ } else if (ps.untilId) {
query._id = {
- $lt: cursor
+ $lt: ps.untilId
};
}
- // Get mutes
const mutes = await Mute
.find(query, {
- limit: limit + 1,
- sort: { _id: -1 }
+ limit: ps.limit,
+ sort: sort
});
- // 「次のページ」があるかどうか
- const inStock = mutes.length === limit + 1;
- if (inStock) {
- mutes.pop();
- }
-
- // Serialize
- const users = await Promise.all(mutes.map(async m =>
- await pack(m.muteeId, me, { detail: true })));
-
- // Response
- res({
- users: users,
- next: inStock ? mutes[mutes.length - 1]._id : null,
- });
+ res(await packMany(mutes, me));
});