From f02125dd4755df1120eae0469a8344f1fbdabcf2 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 7 Mar 2019 13:03:46 +0900 Subject: [PATCH] Resolve #4437 --- .../desktop/views/components/note-detail.vue | 4 +- .../app/desktop/views/components/note.vue | 4 +- .../mobile/views/components/note-detail.vue | 4 +- .../app/mobile/views/components/note.vue | 4 +- src/server/api/endpoints/notes/children.ts | 132 ++++++++++++++++++ 5 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 src/server/api/endpoints/notes/children.ts diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue index f4494c395b..bcff8c8774 100644 --- a/src/client/app/desktop/views/components/note-detail.vue +++ b/src/client/app/desktop/views/components/note-detail.vue @@ -129,9 +129,9 @@ export default Vue.extend({ mounted() { // Get replies if (!this.compact) { - this.$root.api('notes/replies', { + this.$root.api('notes/children', { noteId: this.appearNote.id, - limit: 8 + limit: 30 }).then(replies => { this.replies = replies; }); diff --git a/src/client/app/desktop/views/components/note.vue b/src/client/app/desktop/views/components/note.vue index 9dc831db73..7e00087b9f 100644 --- a/src/client/app/desktop/views/components/note.vue +++ b/src/client/app/desktop/views/components/note.vue @@ -123,9 +123,9 @@ export default Vue.extend({ created() { if (this.detail) { - this.$root.api('notes/replies', { + this.$root.api('notes/children', { noteId: this.appearNote.id, - limit: 8 + limit: 30 }).then(replies => { this.replies = replies; }); diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue index b6f9dc4434..e14e1beff8 100644 --- a/src/client/app/mobile/views/components/note-detail.vue +++ b/src/client/app/mobile/views/components/note-detail.vue @@ -135,9 +135,9 @@ export default Vue.extend({ methods: { fetchReplies() { if (this.compact) return; - this.$root.api('notes/replies', { + this.$root.api('notes/children', { noteId: this.appearNote.id, - limit: 8 + limit: 30 }).then(replies => { this.replies = replies; }); diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue index de556f170c..c207eb10d7 100644 --- a/src/client/app/mobile/views/components/note.vue +++ b/src/client/app/mobile/views/components/note.vue @@ -115,9 +115,9 @@ export default Vue.extend({ created() { if (this.detail) { - this.$root.api('notes/replies', { + this.$root.api('notes/children', { noteId: this.appearNote.id, - limit: 8 + limit: 30 }).then(replies => { this.replies = replies; }); diff --git a/src/server/api/endpoints/notes/children.ts b/src/server/api/endpoints/notes/children.ts new file mode 100644 index 0000000000..3738459b71 --- /dev/null +++ b/src/server/api/endpoints/notes/children.ts @@ -0,0 +1,132 @@ +import $ from 'cafy'; +import ID, { transform } from '../../../../misc/cafy-id'; +import Note, { packMany } from '../../../../models/note'; +import define from '../../define'; +import { getFriends } from '../../common/get-friends'; +import { getHideUserIds } from '../../common/get-hide-users'; + +export const meta = { + desc: { + 'ja-JP': '指定した投稿への返信/引用を取得します。', + 'en-US': 'Get replies/quotes of a note.' + }, + + tags: ['notes'], + + requireCredential: false, + + params: { + noteId: { + validator: $.type(ID), + transform: transform, + desc: { + 'ja-JP': '対象の投稿のID', + 'en-US': 'Target note ID' + } + }, + + limit: { + validator: $.optional.num.range(1, 100), + default: 10 + }, + + sinceId: { + validator: $.optional.type(ID), + transform: transform, + }, + + untilId: { + validator: $.optional.type(ID), + transform: transform, + }, + }, + + res: { + type: 'array', + items: { + type: 'Note', + }, + }, +}; + +export default define(meta, async (ps, user) => { + const [followings, hideUserIds] = await Promise.all([ + // フォローを取得 + // Fetch following + user ? getFriends(user._id) : [], + + // 隠すユーザーを取得 + getHideUserIds(user) + ]); + + const visibleQuery = user == null ? [{ + visibility: { $in: [ 'public', 'home' ] } + }] : [{ + visibility: { $in: [ 'public', 'home' ] } + }, { + // myself (for followers/specified/private) + userId: user._id + }, { + // to me (for specified) + visibleUserIds: { $in: [ user._id ] } + }, { + visibility: 'followers', + $or: [{ + // フォロワーの投稿 + userId: { $in: followings.map(f => f.id) }, + }, { + // 自分の投稿へのリプライ + '_reply.userId': user._id, + }, { + // 自分へのメンションが含まれている + mentions: { $in: [ user._id ] } + }] + }]; + + const q = { + $and: [{ + $or: [{ + replyId: ps.noteId, + }, { + renoteId: ps.noteId, + $or: [{ + text: { $ne: null } + }, { + fileIds: { $ne: [] } + }, { + poll: { $ne: null } + }] + }] + }, { + $or: visibleQuery + }] + } as any; + + if (hideUserIds && hideUserIds.length > 0) { + q['userId'] = { + $nin: hideUserIds + }; + } + + const sort = { + _id: -1 + }; + + if (ps.sinceId) { + sort._id = 1; + q._id = { + $gt: ps.sinceId + }; + } else if (ps.untilId) { + q._id = { + $lt: ps.untilId + }; + } + + const notes = await Note.find(q, { + limit: ps.limit, + sort: sort + }); + + return await packMany(notes, user); +});