diff --git a/src/server/api/endpoints/notes.ts b/src/server/api/endpoints/notes.ts index 4d15e9483fe36186e66309029b6367d8401321fc..5fa58d19debf1b9281063d94e3bcaaa37420ae4f 100644 --- a/src/server/api/endpoints/notes.ts +++ b/src/server/api/endpoints/notes.ts @@ -1,51 +1,65 @@ -/** - * Module dependencies - */ import $ from 'cafy'; import ID from '../../../misc/cafy-id'; import Note, { pack } from '../../../models/note'; +import getParams from '../get-params'; + +export const meta = { + desc: { + 'ja-JP': '投稿をå–å¾—ã—ã¾ã™ã€‚' + }, + + params: { + local: $.bool.optional.note({ + desc: { + 'ja-JP': 'ãƒãƒ¼ã‚«ãƒ«ã®æŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), + + reply: $.bool.optional.note({ + desc: { + 'ja-JP': '返信ã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), + + renote: $.bool.optional.note({ + desc: { + 'ja-JP': 'Renoteã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), + + withFiles: $.bool.optional.note({ + desc: { + 'ja-JP': 'ファイルãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), + + media: $.bool.optional.note({ + desc: { + 'ja-JP': 'ファイルãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹ (ã“ã®ãƒ‘ラメータã¯å»ƒæ¢äºˆå®šã§ã™ã€‚代ã‚ã‚Šã« withFiles を使ã£ã¦ãã ã•ã„。)' + } + }), + + poll: $.bool.optional.note({ + desc: { + 'ja-JP': 'アンケートãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), + + limit: $.num.optional.range(1, 100).note({ + default: 10 + }), + + sinceId: $.type(ID).optional.note({}), + + untilId: $.type(ID).optional.note({}), + } +}; -/** - * Get all notes - */ export default (params: any) => new Promise(async (res, rej) => { - // Get 'local' parameter - const [local, localErr] = $.bool.optional.get(params.local); - if (localErr) return rej('invalid local param'); - - // Get 'reply' parameter - const [reply, replyErr] = $.bool.optional.get(params.reply); - if (replyErr) return rej('invalid reply param'); - - // Get 'renote' parameter - const [renote, renoteErr] = $.bool.optional.get(params.renote); - if (renoteErr) return rej('invalid renote param'); - - // Get 'files' parameter - const [files, filesErr] = $.bool.optional.get(params.files); - if (filesErr) return rej('invalid files param'); - - // Get 'poll' parameter - const [poll, pollErr] = $.bool.optional.get(params.poll); - if (pollErr) return rej('invalid poll param'); - - // Get 'bot' parameter - //const [bot, botErr] = $.bool.optional.get(params.bot); - //if (botErr) return rej('invalid bot param'); - - // Get 'limit' parameter - const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit); - if (limitErr) return rej('invalid limit param'); - - // Get 'sinceId' parameter - const [sinceId, sinceIdErr] = $.type(ID).optional.get(params.sinceId); - if (sinceIdErr) return rej('invalid sinceId param'); - - // Get 'untilId' parameter - const [untilId, untilIdErr] = $.type(ID).optional.get(params.untilId); - if (untilIdErr) return rej('invalid untilId param'); + const [ps, psErr] = getParams(meta, params); + if (psErr) throw psErr; // Check if both of sinceId and untilId is specified - if (sinceId && untilId) { + if (ps.sinceId && ps.untilId) { return rej('cannot set sinceId and untilId'); } @@ -56,35 +70,37 @@ export default (params: any) => new Promise(async (res, rej) => { const query = { visibility: 'public' } as any; - if (sinceId) { + if (ps.sinceId) { sort._id = 1; query._id = { - $gt: sinceId + $gt: ps.sinceId }; - } else if (untilId) { + } else if (ps.untilId) { query._id = { - $lt: untilId + $lt: ps.untilId }; } - if (local) { + if (ps.local) { query['_user.host'] = null; } - if (reply != undefined) { - query.replyId = reply ? { $exists: true, $ne: null } : null; + if (ps.reply != undefined) { + query.replyId = ps.reply ? { $exists: true, $ne: null } : null; } - if (renote != undefined) { - query.renoteId = renote ? { $exists: true, $ne: null } : null; + if (ps.renote != undefined) { + query.renoteId = ps.renote ? { $exists: true, $ne: null } : null; } - if (files != undefined) { - query.fileIds = files ? { $exists: true, $ne: null } : []; + const withFiles = ps.withFiles != undefined ? ps.withFiles : ps.media; + + if (withFiles) { + query.fileIds = withFiles ? { $exists: true, $ne: null } : []; } - if (poll != undefined) { - query.poll = poll ? { $exists: true, $ne: null } : null; + if (ps.poll != undefined) { + query.poll = ps.poll ? { $exists: true, $ne: null } : null; } // TODO @@ -95,7 +111,7 @@ export default (params: any) => new Promise(async (res, rej) => { // Issue query const notes = await Note .find(query, { - limit: limit, + limit: ps.limit, sort: sort }); diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts index 554245a0f408584f27b6b10848fc423f3d0d9459..e70fc5d76f4f4287e794b00b2c72883e1ea164f2 100644 --- a/src/server/api/endpoints/notes/global-timeline.ts +++ b/src/server/api/endpoints/notes/global-timeline.ts @@ -3,40 +3,49 @@ import Note from '../../../../models/note'; import Mute from '../../../../models/mute'; import { pack } from '../../../../models/note'; import { ILocalUser } from '../../../../models/user'; +import getParams from '../../get-params'; -/** - * Get timeline of global - */ -export default async (params: any, user: ILocalUser) => { - // Get 'limit' parameter - const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit); - if (limitErr) throw 'invalid limit param'; +export const meta = { + desc: { + 'ja-JP': 'ã‚°ãƒãƒ¼ãƒãƒ«ã‚¿ã‚¤ãƒ ラインをå–å¾—ã—ã¾ã™ã€‚' + }, + + params: { + withFiles: $.bool.optional.note({ + desc: { + 'ja-JP': 'ファイルãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), + + mediaOnly: $.bool.optional.note({ + desc: { + 'ja-JP': 'ファイルãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹ (ã“ã®ãƒ‘ラメータã¯å»ƒæ¢äºˆå®šã§ã™ã€‚代ã‚ã‚Šã« withFiles を使ã£ã¦ãã ã•ã„。)' + } + }), + + limit: $.num.optional.range(1, 100).note({ + default: 10 + }), + + sinceId: $.type(ID).optional.note({}), - // Get 'sinceId' parameter - const [sinceId, sinceIdErr] = $.type(ID).optional.get(params.sinceId); - if (sinceIdErr) throw 'invalid sinceId param'; + untilId: $.type(ID).optional.note({}), - // Get 'untilId' parameter - const [untilId, untilIdErr] = $.type(ID).optional.get(params.untilId); - if (untilIdErr) throw 'invalid untilId param'; + sinceDate: $.num.optional.note({}), - // Get 'sinceDate' parameter - const [sinceDate, sinceDateErr] = $.num.optional.get(params.sinceDate); - if (sinceDateErr) throw 'invalid sinceDate param'; + untilDate: $.num.optional.note({}), + } +}; - // Get 'untilDate' parameter - const [untilDate, untilDateErr] = $.num.optional.get(params.untilDate); - if (untilDateErr) throw 'invalid untilDate param'; +export default async (params: any, user: ILocalUser) => { + const [ps, psErr] = getParams(meta, params); + if (psErr) throw psErr; // Check if only one of sinceId, untilId, sinceDate, untilDate specified - if ([sinceId, untilId, sinceDate, untilDate].filter(x => x != null).length > 1) { + if ([ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate].filter(x => x != null).length > 1) { throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; } - // Get 'withFiles' parameter - const [withFiles, withFilesErr] = $.bool.optional.get(params.withFiles); - if (withFilesErr) throw 'invalid withFiles param'; - // ミュートã—ã¦ã„るユーザーをå–å¾— const mutedUserIds = user ? (await Mute.find({ muterId: user._id @@ -68,27 +77,29 @@ export default async (params: any, user: ILocalUser) => { }; } + const withFiles = ps.withFiles != null ? ps.withFiles : ps.mediaOnly; + if (withFiles) { query.fileIds = { $exists: true, $ne: [] }; } - if (sinceId) { + if (ps.sinceId) { sort._id = 1; query._id = { - $gt: sinceId + $gt: ps.sinceId }; - } else if (untilId) { + } else if (ps.untilId) { query._id = { - $lt: untilId + $lt: ps.untilId }; - } else if (sinceDate) { + } else if (ps.sinceDate) { sort._id = 1; query.createdAt = { - $gt: new Date(sinceDate) + $gt: new Date(ps.sinceDate) }; - } else if (untilDate) { + } else if (ps.untilDate) { query.createdAt = { - $lt: new Date(untilDate) + $lt: new Date(ps.untilDate) }; } //#endregion @@ -96,7 +107,7 @@ export default async (params: any, user: ILocalUser) => { // Issue query const timeline = await Note .find(query, { - limit: limit, + limit: ps.limit, sort: sort }); diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts index 106079268354eb1d4c84150ff3e3e02144769118..16cec8679750b78fb4d424d53c2c2e4a29429eb4 100644 --- a/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -7,8 +7,6 @@ import { ILocalUser } from '../../../../models/user'; import getParams from '../../get-params'; export const meta = { - name: 'notes/hybrid-timeline', - desc: { 'ja-JP': 'ãƒã‚¤ãƒ–リッドタイムラインをå–å¾—ã—ã¾ã™ã€‚' }, @@ -68,7 +66,13 @@ export const meta = { withFiles: $.bool.optional.note({ desc: { - 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ¡ãƒ‡ã‚£ã‚¢ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™' + 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™' + } + }), + + mediaOnly: $.bool.optional.note({ + desc: { + 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™ (ã“ã®ãƒ‘ラメータã¯å»ƒæ¢äºˆå®šã§ã™ã€‚代ã‚ã‚Šã« withFiles を使ã£ã¦ãã ã•ã„。)' } }), } @@ -203,7 +207,7 @@ export default async (params: any, user: ILocalUser) => { }); } - if (ps.withFiles) { + if (ps.withFiles || ps.mediaOnly) { query.$and.push({ fileIds: { $exists: true, $ne: [] } }); diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts index 018e636ab5eb5e5890e0fc49e1a341cde3c52ac3..2458a70556409fdbade0c2a05fd681c1a72edaa2 100644 --- a/src/server/api/endpoints/notes/local-timeline.ts +++ b/src/server/api/endpoints/notes/local-timeline.ts @@ -3,40 +3,49 @@ import Note from '../../../../models/note'; import Mute from '../../../../models/mute'; import { pack } from '../../../../models/note'; import { ILocalUser } from '../../../../models/user'; +import getParams from '../../get-params'; -/** - * Get timeline of local - */ -export default async (params: any, user: ILocalUser) => { - // Get 'limit' parameter - const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit); - if (limitErr) throw 'invalid limit param'; +export const meta = { + desc: { + 'ja-JP': 'ãƒãƒ¼ã‚«ãƒ«ã‚¿ã‚¤ãƒ ラインをå–å¾—ã—ã¾ã™ã€‚' + }, + + params: { + withFiles: $.bool.optional.note({ + desc: { + 'ja-JP': 'ファイルãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), + + mediaOnly: $.bool.optional.note({ + desc: { + 'ja-JP': 'ファイルãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹ (ã“ã®ãƒ‘ラメータã¯å»ƒæ¢äºˆå®šã§ã™ã€‚代ã‚ã‚Šã« withFiles を使ã£ã¦ãã ã•ã„。)' + } + }), + + limit: $.num.optional.range(1, 100).note({ + default: 10 + }), + + sinceId: $.type(ID).optional.note({}), - // Get 'sinceId' parameter - const [sinceId, sinceIdErr] = $.type(ID).optional.get(params.sinceId); - if (sinceIdErr) throw 'invalid sinceId param'; + untilId: $.type(ID).optional.note({}), - // Get 'untilId' parameter - const [untilId, untilIdErr] = $.type(ID).optional.get(params.untilId); - if (untilIdErr) throw 'invalid untilId param'; + sinceDate: $.num.optional.note({}), - // Get 'sinceDate' parameter - const [sinceDate, sinceDateErr] = $.num.optional.get(params.sinceDate); - if (sinceDateErr) throw 'invalid sinceDate param'; + untilDate: $.num.optional.note({}), + } +}; - // Get 'untilDate' parameter - const [untilDate, untilDateErr] = $.num.optional.get(params.untilDate); - if (untilDateErr) throw 'invalid untilDate param'; +export default async (params: any, user: ILocalUser) => { + const [ps, psErr] = getParams(meta, params); + if (psErr) throw psErr; // Check if only one of sinceId, untilId, sinceDate, untilDate specified - if ([sinceId, untilId, sinceDate, untilDate].filter(x => x != null).length > 1) { + if ([ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate].filter(x => x != null).length > 1) { throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; } - // Get 'withFiles' parameter - const [withFiles, withFilesErr] = $.bool.optional.get(params.withFiles); - if (withFilesErr) throw 'invalid withFiles param'; - // ミュートã—ã¦ã„るユーザーをå–å¾— const mutedUserIds = user ? (await Mute.find({ muterId: user._id @@ -69,27 +78,29 @@ export default async (params: any, user: ILocalUser) => { }; } + const withFiles = ps.withFiles != null ? ps.withFiles : ps.mediaOnly; + if (withFiles) { query.fileIds = { $exists: true, $ne: [] }; } - if (sinceId) { + if (ps.sinceId) { sort._id = 1; query._id = { - $gt: sinceId + $gt: ps.sinceId }; - } else if (untilId) { + } else if (ps.untilId) { query._id = { - $lt: untilId + $lt: ps.untilId }; - } else if (sinceDate) { + } else if (ps.sinceDate) { sort._id = 1; query.createdAt = { - $gt: new Date(sinceDate) + $gt: new Date(ps.sinceDate) }; - } else if (untilDate) { + } else if (ps.untilDate) { query.createdAt = { - $lt: new Date(untilDate) + $lt: new Date(ps.untilDate) }; } //#endregion @@ -97,7 +108,7 @@ export default async (params: any, user: ILocalUser) => { // Issue query const timeline = await Note .find(query, { - limit: limit, + limit: ps.limit, sort: sort }); diff --git a/src/server/api/endpoints/notes/search_by_tag.ts b/src/server/api/endpoints/notes/search_by_tag.ts index f982dc01e9239178bf43072e6d157b2a96a67c86..82f11a9775fb39db7f02fef9f846aa90563d1949 100644 --- a/src/server/api/endpoints/notes/search_by_tag.ts +++ b/src/server/api/endpoints/notes/search_by_tag.ts @@ -4,119 +4,152 @@ import User, { ILocalUser } from '../../../../models/user'; import Mute from '../../../../models/mute'; import { getFriendIds } from '../../common/get-friends'; import { pack } from '../../../../models/note'; +import getParams from '../../get-params'; -/** - * Search notes by tag - */ -export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => { - // Get 'tag' parameter - const [tag, tagError] = $.str.get(params.tag); - if (tagError) return rej('invalid tag param'); +export const meta = { + desc: { + 'ja-JP': '指定ã•ã‚ŒãŸã‚¿ã‚°ãŒä»˜ã‘られãŸæŠ•ç¨¿ã‚’å–å¾—ã—ã¾ã™ã€‚' + }, + + params: { + tag: $.str.note({ + desc: { + 'ja-JP': 'ã‚¿ã‚°' + } + }), + + includeUserIds: $.arr($.type(ID)).optional.note({ + default: [] + }), + + excludeUserIds: $.arr($.type(ID)).optional.note({ + default: [] + }), + + includeUserUsernames: $.arr($.str).optional.note({ + default: [] + }), + + excludeUserUsernames: $.arr($.str).optional.note({ + default: [] + }), + + following: $.bool.optional.nullable.note({ + default: null + }), + + mute: $.str.optional.note({ + default: 'mute_all' + }), - // Get 'includeUserIds' parameter - const [includeUserIds = [], includeUserIdsErr] = $.arr($.type(ID)).optional.get(params.includeUserIds); - if (includeUserIdsErr) return rej('invalid includeUserIds param'); + reply: $.bool.optional.nullable.note({ + default: null, - // Get 'excludeUserIds' parameter - const [excludeUserIds = [], excludeUserIdsErr] = $.arr($.type(ID)).optional.get(params.excludeUserIds); - if (excludeUserIdsErr) return rej('invalid excludeUserIds param'); + desc: { + 'ja-JP': '返信ã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), - // Get 'includeUserUsernames' parameter - const [includeUserUsernames = [], includeUserUsernamesErr] = $.arr($.str).optional.get(params.includeUserUsernames); - if (includeUserUsernamesErr) return rej('invalid includeUserUsernames param'); + renote: $.bool.optional.nullable.note({ + default: null, - // Get 'excludeUserUsernames' parameter - const [excludeUserUsernames = [], excludeUserUsernamesErr] = $.arr($.str).optional.get(params.excludeUserUsernames); - if (excludeUserUsernamesErr) return rej('invalid excludeUserUsernames param'); + desc: { + 'ja-JP': 'Renoteã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), - // Get 'following' parameter - const [following = null, followingErr] = $.bool.optional.nullable.get(params.following); - if (followingErr) return rej('invalid following param'); + withFiles: $.bool.optional.nullable.note({ + default: null, - // Get 'mute' parameter - const [mute = 'mute_all', muteErr] = $.str.optional.get(params.mute); - if (muteErr) return rej('invalid mute param'); + desc: { + 'ja-JP': 'ファイルãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), - // Get 'reply' parameter - const [reply = null, replyErr] = $.bool.optional.nullable.get(params.reply); - if (replyErr) return rej('invalid reply param'); + media: $.bool.optional.nullable.note({ + default: null, - // Get 'renote' parameter - const [renote = null, renoteErr] = $.bool.optional.nullable.get(params.renote); - if (renoteErr) return rej('invalid renote param'); + desc: { + 'ja-JP': 'ファイルãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹ (ã“ã®ãƒ‘ラメータã¯å»ƒæ¢äºˆå®šã§ã™ã€‚代ã‚ã‚Šã« withFiles を使ã£ã¦ãã ã•ã„。)' + } + }), - // Get 'withFiles' parameter - const [withFiles = null, withFilesErr] = $.bool.optional.nullable.get(params.withFiles); - if (withFilesErr) return rej('invalid withFiles param'); + poll: $.bool.optional.nullable.note({ + default: null, - // Get 'poll' parameter - const [poll = null, pollErr] = $.bool.optional.nullable.get(params.poll); - if (pollErr) return rej('invalid poll param'); + desc: { + 'ja-JP': 'アンケートãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã«é™å®šã™ã‚‹ã‹å¦ã‹' + } + }), - // Get 'sinceDate' parameter - const [sinceDate, sinceDateErr] = $.num.optional.get(params.sinceDate); - if (sinceDateErr) throw 'invalid sinceDate param'; + sinceDate: $.num.optional.note({ + }), - // Get 'untilDate' parameter - const [untilDate, untilDateErr] = $.num.optional.get(params.untilDate); - if (untilDateErr) throw 'invalid untilDate param'; + untilDate: $.num.optional.note({ + }), - // Get 'offset' parameter - const [offset = 0, offsetErr] = $.num.optional.min(0).get(params.offset); - if (offsetErr) return rej('invalid offset param'); + offset: $.num.optional.min(0).note({ + default: 0 + }), - // Get 'limit' parameter - const [limit = 10, limitErr] = $.num.optional.range(1, 30).get(params.limit); - if (limitErr) return rej('invalid limit param'); + limit: $.num.optional.range(1, 30).note({ + default: 10 + }), + } +}; + +export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => { + const [ps, psErr] = getParams(meta, params); + if (psErr) throw psErr; - if (includeUserUsernames != null) { - const ids = (await Promise.all(includeUserUsernames.map(async (username) => { + if (ps.includeUserUsernames != null) { + const ids = (await Promise.all(ps.includeUserUsernames.map(async (username) => { const _user = await User.findOne({ usernameLower: username.toLowerCase() }); return _user ? _user._id : null; }))).filter(id => id != null); - ids.forEach(id => includeUserIds.push(id)); + ids.forEach(id => ps.includeUserIds.push(id)); } - if (excludeUserUsernames != null) { - const ids = (await Promise.all(excludeUserUsernames.map(async (username) => { + if (ps.excludeUserUsernames != null) { + const ids = (await Promise.all(ps.excludeUserUsernames.map(async (username) => { const _user = await User.findOne({ usernameLower: username.toLowerCase() }); return _user ? _user._id : null; }))).filter(id => id != null); - ids.forEach(id => excludeUserIds.push(id)); + ids.forEach(id => ps.excludeUserIds.push(id)); } let q: any = { $and: [{ - tagsLower: tag.toLowerCase() + tagsLower: ps.tag.toLowerCase() }] }; const push = (x: any) => q.$and.push(x); - if (includeUserIds && includeUserIds.length != 0) { + if (ps.includeUserIds && ps.includeUserIds.length != 0) { push({ userId: { - $in: includeUserIds + $in: ps.includeUserIds } }); - } else if (excludeUserIds && excludeUserIds.length != 0) { + } else if (ps.excludeUserIds && ps.excludeUserIds.length != 0) { push({ userId: { - $nin: excludeUserIds + $nin: ps.excludeUserIds } }); } - if (following != null && me != null) { + if (ps.following != null && me != null) { const ids = await getFriendIds(me._id, false); push({ - userId: following ? { + userId: ps.following ? { $in: ids } : { $nin: ids.concat(me._id) @@ -131,7 +164,7 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => }); const mutedUserIds = mutes.map(m => m.muteeId); - switch (mute) { + switch (ps.mute) { case 'mute_all': push({ userId: { @@ -202,8 +235,8 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => } } - if (reply != null) { - if (reply) { + if (ps.reply != null) { + if (ps.reply) { push({ replyId: { $exists: true, @@ -223,8 +256,8 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => } } - if (renote != null) { - if (renote) { + if (ps.renote != null) { + if (ps.renote) { push({ renoteId: { $exists: true, @@ -244,6 +277,8 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => } } + const withFiles = ps.withFiles != null ? ps.withFiles : ps.media; + if (withFiles != null) { if (withFiles) { push({ @@ -265,8 +300,8 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => } } - if (poll != null) { - if (poll) { + if (ps.poll != null) { + if (ps.poll) { push({ poll: { $exists: true, @@ -286,18 +321,18 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => } } - if (sinceDate) { + if (ps.sinceDate) { push({ createdAt: { - $gt: new Date(sinceDate) + $gt: new Date(ps.sinceDate) } }); } - if (untilDate) { + if (ps.untilDate) { push({ createdAt: { - $lt: new Date(untilDate) + $lt: new Date(ps.untilDate) } }); } @@ -312,8 +347,8 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => sort: { _id: -1 }, - limit: limit, - skip: offset + limit: ps.limit, + skip: ps.offset }); // Serialize diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts index 145f648c560eb93e6940b864601c1266f73333a4..089e7a182a9bb0a23ee130fe3d3f5f5f3b617b59 100644 --- a/src/server/api/endpoints/notes/timeline.ts +++ b/src/server/api/endpoints/notes/timeline.ts @@ -69,7 +69,13 @@ export const meta = { withFiles: $.bool.optional.note({ desc: { - 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ¡ãƒ‡ã‚£ã‚¢ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™' + 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™' + } + }), + + mediaOnly: $.bool.optional.note({ + desc: { + 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™ (ã“ã®ãƒ‘ラメータã¯å»ƒæ¢äºˆå®šã§ã™ã€‚代ã‚ã‚Šã« withFiles を使ã£ã¦ãã ã•ã„。)' } }), } @@ -193,7 +199,9 @@ export default async (params: any, user: ILocalUser) => { }); } - if (ps.withFiles) { + const withFiles = ps.withFiles != null ? ps.withFiles : ps.mediaOnly; + + if (withFiles) { query.$and.push({ fileIds: { $exists: true, $ne: [] } }); diff --git a/src/server/api/endpoints/notes/user-list-timeline.ts b/src/server/api/endpoints/notes/user-list-timeline.ts index e00a7de3717cea1baaea8b5651f5d5c91a376968..61192d7d3e922f7a74a830a57ed7eb224f164c87 100644 --- a/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/src/server/api/endpoints/notes/user-list-timeline.ts @@ -75,7 +75,13 @@ export const meta = { withFiles: $.bool.optional.note({ desc: { - 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ¡ãƒ‡ã‚£ã‚¢ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™' + 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™' + } + }), + + mediaOnly: $.bool.optional.note({ + desc: { + 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™ (ã“ã®ãƒ‘ラメータã¯å»ƒæ¢äºˆå®šã§ã™ã€‚代ã‚ã‚Šã« withFiles を使ã£ã¦ãã ã•ã„。)' } }), } @@ -199,7 +205,9 @@ export default async (params: any, user: ILocalUser) => { }); } - if (ps.withFiles) { + const withFiles = ps.withFiles != null ? ps.withFiles : ps.mediaOnly; + + if (withFiles) { query.$and.push({ fileIds: { $exists: true, $ne: [] } }); diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts index d894e52dba47380a17785659302177ad821c2a51..42c31189d61b614c98c3285fe312f71a8d5ec6d4 100644 --- a/src/server/api/endpoints/users/notes.ts +++ b/src/server/api/endpoints/users/notes.ts @@ -2,63 +2,121 @@ import $ from 'cafy'; import ID from '../../../../misc/cafy-id'; import getHostLower from '../../common/get-host-lower'; import Note, { pack } from '../../../../models/note'; import User, { ILocalUser } from '../../../../models/user'; +import getParams from '../../get-params'; + +export const meta = { + desc: { + 'ja-JP': '指定ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã‚¿ã‚¤ãƒ ラインをå–å¾—ã—ã¾ã™ã€‚' + }, + + params: { + userId: $.type(ID).optional.note({ + desc: { + 'ja-JP': 'ユーザーID' + } + }), + + username: $.str.optional.note({ + desc: { + 'ja-JP': 'ユーザーå' + } + }), + + host: $.str.optional.note({ + }), + + includeReplies: $.bool.optional.note({ + default: true, + + desc: { + 'ja-JP': 'リプライをå«ã‚ã‚‹ã‹å¦ã‹' + } + }), + + limit: $.num.optional.range(1, 100).note({ + default: 10, + desc: { + 'ja-JP': '最大数' + } + }), + + sinceId: $.type(ID).optional.note({ + desc: { + 'ja-JP': '指定ã™ã‚‹ã¨ã€ã“ã®æŠ•ç¨¿ã‚’基点ã¨ã—ã¦ã‚ˆã‚Šæ–°ã—ã„投稿をå–å¾—ã—ã¾ã™' + } + }), + + untilId: $.type(ID).optional.note({ + desc: { + 'ja-JP': '指定ã™ã‚‹ã¨ã€ã“ã®æŠ•ç¨¿ã‚’基点ã¨ã—ã¦ã‚ˆã‚Šå¤ã„投稿をå–å¾—ã—ã¾ã™' + } + }), + + sinceDate: $.num.optional.note({ + desc: { + 'ja-JP': '指定ã—ãŸæ™‚間を基点ã¨ã—ã¦ã‚ˆã‚Šæ–°ã—ã„投稿をå–å¾—ã—ã¾ã™ã€‚数値ã¯ã€1970å¹´1月1æ—¥ 00:00:00 UTC ã‹ã‚‰æŒ‡å®šã—ãŸæ—¥æ™‚ã¾ã§ã®çµŒéŽæ™‚間をミリ秒å˜ä½ã§è¡¨ã—ã¾ã™ã€‚' + } + }), + + untilDate: $.num.optional.note({ + desc: { + 'ja-JP': '指定ã—ãŸæ™‚間を基点ã¨ã—ã¦ã‚ˆã‚Šå¤ã„投稿をå–å¾—ã—ã¾ã™ã€‚数値ã¯ã€1970å¹´1月1æ—¥ 00:00:00 UTC ã‹ã‚‰æŒ‡å®šã—ãŸæ—¥æ™‚ã¾ã§ã®çµŒéŽæ™‚間をミリ秒å˜ä½ã§è¡¨ã—ã¾ã™ã€‚' + } + }), + + includeMyRenotes: $.bool.optional.note({ + default: true, + desc: { + 'ja-JP': '自分ã®è¡Œã£ãŸRenoteã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹' + } + }), + + includeRenotedMyNotes: $.bool.optional.note({ + default: true, + desc: { + 'ja-JP': 'Renoteã•ã‚ŒãŸè‡ªåˆ†ã®æŠ•ç¨¿ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹' + } + }), + + includeLocalRenotes: $.bool.optional.note({ + default: true, + desc: { + 'ja-JP': 'Renoteã•ã‚ŒãŸãƒãƒ¼ã‚«ãƒ«ã®æŠ•ç¨¿ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹' + } + }), + + withFiles: $.bool.optional.note({ + default: false, + desc: { + 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™' + } + }), + + mediaOnly: $.bool.optional.note({ + default: false, + desc: { + 'ja-JP': 'true ã«ã™ã‚‹ã¨ã€ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ·»ä»˜ã•ã‚ŒãŸæŠ•ç¨¿ã ã‘å–å¾—ã—ã¾ã™ (ã“ã®ãƒ‘ラメータã¯å»ƒæ¢äºˆå®šã§ã™ã€‚代ã‚ã‚Šã« withFiles を使ã£ã¦ãã ã•ã„。)' + } + }), + } +}; -/** - * Get notes of a user - */ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => { - // Get 'userId' parameter - const [userId, userIdErr] = $.type(ID).optional.get(params.userId); - if (userIdErr) return rej('invalid userId param'); - - // Get 'username' parameter - const [username, usernameErr] = $.str.optional.get(params.username); - if (usernameErr) return rej('invalid username param'); + const [ps, psErr] = getParams(meta, params); + if (psErr) throw psErr; - if (userId === undefined && username === undefined) { + if (ps.userId === undefined && ps.username === undefined) { return rej('userId or username is required'); } - // Get 'host' parameter - const [host, hostErr] = $.str.optional.get(params.host); - if (hostErr) return rej('invalid host param'); - - // Get 'includeReplies' parameter - const [includeReplies = true, includeRepliesErr] = $.bool.optional.get(params.includeReplies); - if (includeRepliesErr) return rej('invalid includeReplies param'); - - // Get 'withFiles' parameter - const [withFiles = false, withFilesErr] = $.bool.optional.get(params.withFiles); - if (withFilesErr) return rej('invalid withFiles param'); - - // Get 'limit' parameter - const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit); - if (limitErr) return rej('invalid limit param'); - - // Get 'sinceId' parameter - const [sinceId, sinceIdErr] = $.type(ID).optional.get(params.sinceId); - if (sinceIdErr) return rej('invalid sinceId param'); - - // Get 'untilId' parameter - const [untilId, untilIdErr] = $.type(ID).optional.get(params.untilId); - if (untilIdErr) return rej('invalid untilId param'); - - // Get 'sinceDate' parameter - const [sinceDate, sinceDateErr] = $.num.optional.get(params.sinceDate); - if (sinceDateErr) throw 'invalid sinceDate param'; - - // Get 'untilDate' parameter - const [untilDate, untilDateErr] = $.num.optional.get(params.untilDate); - if (untilDateErr) throw 'invalid untilDate param'; - // Check if only one of sinceId, untilId, sinceDate, untilDate specified - if ([sinceId, untilId, sinceDate, untilDate].filter(x => x != null).length > 1) { + if ([ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate].filter(x => x != null).length > 1) { throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; } - const q = userId !== undefined - ? { _id: userId } - : { usernameLower: username.toLowerCase(), host: getHostLower(host) } ; + const q = ps.userId !== undefined + ? { _id: ps.userId } + : { usernameLower: ps.username.toLowerCase(), host: getHostLower(ps.host) } ; // Lookup user const user = await User.findOne(q, { @@ -80,30 +138,32 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => userId: user._id } as any; - if (sinceId) { + if (ps.sinceId) { sort._id = 1; query._id = { - $gt: sinceId + $gt: ps.sinceId }; - } else if (untilId) { + } else if (ps.untilId) { query._id = { - $lt: untilId + $lt: ps.untilId }; - } else if (sinceDate) { + } else if (ps.sinceDate) { sort._id = 1; query.createdAt = { - $gt: new Date(sinceDate) + $gt: new Date(ps.sinceDate) }; - } else if (untilDate) { + } else if (ps.untilDate) { query.createdAt = { - $lt: new Date(untilDate) + $lt: new Date(ps.untilDate) }; } - if (!includeReplies) { + if (!ps.includeReplies) { query.replyId = null; } + const withFiles = ps.withFiles != null ? ps.withFiles : ps.mediaOnly; + if (withFiles) { query.fileIds = { $exists: true, @@ -115,12 +175,10 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => // Issue query const notes = await Note .find(query, { - limit: limit, + limit: ps.limit, sort: sort }); // Serialize - res(await Promise.all(notes.map(async (note) => - await pack(note, me) - ))); + res(await Promise.all(notes.map(note => pack(note, me)))); });