diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue index f4494c395..bcff8c877 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 9dc831db7..7e00087b9 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 b6f9dc443..e14e1beff 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 de556f170..c207eb10d 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 000000000..3738459b7 --- /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); +});