diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2018-08-17 14:48:38 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-17 14:48:38 +0900 |
| commit | 4a3d74c608867602ff7452312b38251089ddf537 (patch) | |
| tree | 6c084dcb9e1b8658d0ed12dd498021b6015e32ab /src/server/api | |
| parent | New translations ja.yml (Catalan) (diff) | |
| parent | Merge pull request #2279 from syuilo/enhance-note-footer (diff) | |
| download | misskey-4a3d74c608867602ff7452312b38251089ddf537.tar.gz misskey-4a3d74c608867602ff7452312b38251089ddf537.tar.bz2 misskey-4a3d74c608867602ff7452312b38251089ddf537.zip | |
Merge branch 'master' into l10n_master
Diffstat (limited to 'src/server/api')
| -rw-r--r-- | src/server/api/call.ts | 8 | ||||
| -rw-r--r-- | src/server/api/endpoints.ts | 5 | ||||
| -rw-r--r-- | src/server/api/endpoints/admin/suspend-user.ts | 46 | ||||
| -rw-r--r-- | src/server/api/endpoints/admin/unsuspend-user.ts | 46 | ||||
| -rw-r--r-- | src/server/api/endpoints/app/create.ts | 4 | ||||
| -rw-r--r-- | src/server/api/endpoints/messaging/history.ts | 3 | ||||
| -rw-r--r-- | src/server/api/endpoints/messaging/messages/read.ts | 43 | ||||
| -rw-r--r-- | src/server/api/endpoints/notes/hybrid-timeline.ts | 23 | ||||
| -rw-r--r-- | src/server/api/endpoints/notes/timeline.ts | 29 | ||||
| -rw-r--r-- | src/server/api/endpoints/notes/user-list-timeline.ts | 139 | ||||
| -rw-r--r-- | src/server/api/endpoints/users/notes.ts | 6 | ||||
| -rw-r--r-- | src/server/api/private/signup.ts | 2 |
12 files changed, 291 insertions, 63 deletions
diff --git a/src/server/api/call.ts b/src/server/api/call.ts index 1d0e858762..e4bb30b695 100644 --- a/src/server/api/call.ts +++ b/src/server/api/call.ts @@ -1,6 +1,6 @@ import { performance } from 'perf_hooks'; import limitter from './limitter'; -import { IUser } from '../../models/user'; +import { IUser, isLocalUser } from '../../models/user'; import { IApp } from '../../models/app'; import endpoints from './endpoints'; @@ -21,6 +21,10 @@ export default (endpoint: string, user: IUser, app: IApp, data: any, file?: any) return rej('YOUR_ACCOUNT_HAS_BEEN_SUSPENDED'); } + if (ep.meta.requireAdmin && !(isLocalUser(user) && user.isAdmin)) { + return rej('YOU_ARE_NOT_ADMIN'); + } + if (app && ep.meta.kind) { if (!app.permission.some(p => p === ep.meta.kind)) { return rej('PERMISSION_DENIED'); @@ -53,7 +57,7 @@ export default (endpoint: string, user: IUser, app: IApp, data: any, file?: any) const time = after - before; if (time > 1000) { - console.warn(`SLOW API CALL DETECTED: ${ep.name} (${ time }ms)`); + console.warn(`SLOW API CALL DETECTED: ${ep.name} (${time}ms)`); } } catch (e) { rej(e); diff --git a/src/server/api/endpoints.ts b/src/server/api/endpoints.ts index 332a051ae1..d4a44070e6 100644 --- a/src/server/api/endpoints.ts +++ b/src/server/api/endpoints.ts @@ -15,6 +15,11 @@ export interface IEndpointMeta { requireCredential?: boolean; /** + * 管理者のみ使えるエンドポイントか否か + */ + requireAdmin?: boolean; + + /** * エンドポイントのリミテーションに関するやつ * 省略した場合はリミテーションは無いものとして解釈されます。 * また、withCredential が false の場合はリミテーションを行うことはできません。 diff --git a/src/server/api/endpoints/admin/suspend-user.ts b/src/server/api/endpoints/admin/suspend-user.ts new file mode 100644 index 0000000000..8698120cdb --- /dev/null +++ b/src/server/api/endpoints/admin/suspend-user.ts @@ -0,0 +1,46 @@ +import $ from 'cafy'; +import ID from '../../../../misc/cafy-id'; +import getParams from '../../get-params'; +import User from '../../../../models/user'; + +export const meta = { + desc: { + ja: '指定したユーザーを凍結します。', + en: 'Suspend a user.' + }, + + requireCredential: true, + requireAdmin: true, + + params: { + userId: $.type(ID).note({ + desc: { + ja: '対象のユーザーID', + en: 'The user ID which you want to suspend' + } + }), + } +}; + +export default (params: any) => new Promise(async (res, rej) => { + const [ps, psErr] = getParams(meta, params); + if (psErr) return rej(psErr); + + const user = await User.findOne({ + _id: ps.userId + }); + + if (user == null) { + return rej('user not found'); + } + + await User.findOneAndUpdate({ + _id: user._id + }, { + $set: { + isSuspended: true + } + }); + + res(); +}); diff --git a/src/server/api/endpoints/admin/unsuspend-user.ts b/src/server/api/endpoints/admin/unsuspend-user.ts new file mode 100644 index 0000000000..8409bd1b76 --- /dev/null +++ b/src/server/api/endpoints/admin/unsuspend-user.ts @@ -0,0 +1,46 @@ +import $ from 'cafy'; +import ID from '../../../../misc/cafy-id'; +import getParams from '../../get-params'; +import User from '../../../../models/user'; + +export const meta = { + desc: { + ja: '指定したユーザーの凍結を解除します。', + en: 'Unsuspend a user.' + }, + + requireCredential: true, + requireAdmin: true, + + params: { + userId: $.type(ID).note({ + desc: { + ja: '対象のユーザーID', + en: 'The user ID which you want to unsuspend' + } + }), + } +}; + +export default (params: any) => new Promise(async (res, rej) => { + const [ps, psErr] = getParams(meta, params); + if (psErr) return rej(psErr); + + const user = await User.findOne({ + _id: ps.userId + }); + + if (user == null) { + return rej('user not found'); + } + + await User.findOneAndUpdate({ + _id: user._id + }, { + $set: { + isSuspended: false + } + }); + + res(); +}); diff --git a/src/server/api/endpoints/app/create.ts b/src/server/api/endpoints/app/create.ts index 5df8bd2f25..b2a5fb73c1 100644 --- a/src/server/api/endpoints/app/create.ts +++ b/src/server/api/endpoints/app/create.ts @@ -4,7 +4,7 @@ import App, { isValidNameId, pack } from '../../../../models/app'; import { ILocalUser } from '../../../../models/user'; export const meta = { - requireCredential: true + requireCredential: false }; /** @@ -38,7 +38,7 @@ export default async (params: any, user: ILocalUser) => new Promise(async (res, // Create account const app = await App.insert({ createdAt: new Date(), - userId: user._id, + userId: user && user._id, name: name, nameId: nameId, nameIdLower: nameId.toLowerCase(), diff --git a/src/server/api/endpoints/messaging/history.ts b/src/server/api/endpoints/messaging/history.ts index 66798d50c5..43cceacf95 100644 --- a/src/server/api/endpoints/messaging/history.ts +++ b/src/server/api/endpoints/messaging/history.ts @@ -40,6 +40,5 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) = }); // Serialize - res(await Promise.all(history.map(async h => - await pack(h.messageId, user)))); + res(await Promise.all(history.map(h => pack(h.messageId, user)))); }); diff --git a/src/server/api/endpoints/messaging/messages/read.ts b/src/server/api/endpoints/messaging/messages/read.ts new file mode 100644 index 0000000000..f609337523 --- /dev/null +++ b/src/server/api/endpoints/messaging/messages/read.ts @@ -0,0 +1,43 @@ +import $ from 'cafy'; import ID from '../../../../../misc/cafy-id'; +import Message from '../../../../../models/messaging-message'; +import { ILocalUser } from '../../../../../models/user'; +import read from '../../../common/read-messaging-message'; +import getParams from '../../../get-params'; + +export const meta = { + desc: { + ja: '指定した自分宛てのメッセージを既読にします。', + en: 'Mark as read a message of messaging.' + }, + + requireCredential: true, + + kind: 'messaging-write', + + params: { + messageId: $.type(ID).note({ + desc: { + ja: '既読にするメッセージのID', + en: 'The ID of a message that you want to mark as read' + } + }) + } +}; + +export default (params: any, user: ILocalUser) => new Promise(async (res, rej) => { + const [ps, psErr] = getParams(meta, params); + if (psErr) throw psErr; + + const message = await Message.findOne({ + _id: ps.messageId, + recipientId: user._id + }); + + if (message == null) { + return rej('message not found'); + } + + read(user._id, message.userId, message); + + res(); +}); diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts index 036f84b54b..3fce4fb9af 100644 --- a/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -59,6 +59,13 @@ export const meta = { } }), + includeLocalRenotes: $.bool.optional.note({ + default: true, + desc: { + ja: 'Renoteされたローカルの投稿を含めるかどうか' + } + }), + mediaOnly: $.bool.optional.note({ desc: { ja: 'true にすると、メディアが添付された投稿だけ取得します' @@ -180,6 +187,22 @@ export default async (params: any, user: ILocalUser) => { }); } + if (ps.includeLocalRenotes === false) { + query.$and.push({ + $or: [{ + '_renote.user.host': { $ne: null } + }, { + renoteId: null + }, { + text: { $ne: null } + }, { + mediaIds: { $ne: [] } + }, { + poll: { $ne: null } + }] + }); + } + if (ps.mediaOnly) { query.$and.push({ mediaIds: { $exists: true, $ne: [] } diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts index faa8ccf3ca..3e3fa8c4aa 100644 --- a/src/server/api/endpoints/notes/timeline.ts +++ b/src/server/api/endpoints/notes/timeline.ts @@ -8,7 +8,8 @@ import getParams from '../../get-params'; export const meta = { desc: { - ja: 'タイムラインを取得します。' + ja: 'タイムラインを取得します。', + en: 'Get timeline of myself.' }, requireCredential: true, @@ -59,6 +60,13 @@ export const meta = { } }), + includeLocalRenotes: $.bool.optional.note({ + default: true, + desc: { + ja: 'Renoteされたローカルの投稿を含めるかどうか' + } + }), + mediaOnly: $.bool.optional.note({ desc: { ja: 'true にすると、メディアが添付された投稿だけ取得します' @@ -67,9 +75,6 @@ export const meta = { } }; -/** - * Get timeline of myself - */ export default async (params: any, user: ILocalUser) => { const [ps, psErr] = getParams(meta, params); if (psErr) throw psErr; @@ -172,6 +177,22 @@ export default async (params: any, user: ILocalUser) => { }); } + if (ps.includeLocalRenotes === false) { + query.$and.push({ + $or: [{ + '_renote.user.host': { $ne: null } + }, { + renoteId: null + }, { + text: { $ne: null } + }, { + mediaIds: { $ne: [] } + }, { + poll: { $ne: null } + }] + }); + } + if (ps.mediaOnly) { query.$and.push({ mediaIds: { $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 5837a9a301..dcef548666 100644 --- a/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/src/server/api/endpoints/notes/user-list-timeline.ts @@ -4,6 +4,7 @@ import Mute from '../../../../models/mute'; import { pack } from '../../../../models/note'; import UserList from '../../../../models/user-list'; import { ILocalUser } from '../../../../models/user'; +import getParams from '../../get-params'; export const meta = { desc: { @@ -11,56 +12,84 @@ export const meta = { en: 'Get timeline of a user list.' }, - requireCredential: true -}; + requireCredential: true, -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'; + params: { + listId: $.type(ID).note({ + desc: { + ja: 'リストのID' + } + }), - // Get 'sinceId' parameter - const [sinceId, sinceIdErr] = $.type(ID).optional.get(params.sinceId); - if (sinceIdErr) throw 'invalid sinceId param'; + limit: $.num.optional.range(1, 100).note({ + default: 10, + desc: { + ja: '最大数' + } + }), - // Get 'untilId' parameter - const [untilId, untilIdErr] = $.type(ID).optional.get(params.untilId); - if (untilIdErr) throw 'invalid untilId param'; + sinceId: $.type(ID).optional.note({ + desc: { + ja: '指定すると、この投稿を基点としてより新しい投稿を取得します' + } + }), - // Get 'sinceDate' parameter - const [sinceDate, sinceDateErr] = $.num.optional.get(params.sinceDate); - if (sinceDateErr) throw 'invalid sinceDate param'; + untilId: $.type(ID).optional.note({ + desc: { + ja: '指定すると、この投稿を基点としてより古い投稿を取得します' + } + }), - // Get 'untilDate' parameter - const [untilDate, untilDateErr] = $.num.optional.get(params.untilDate); - if (untilDateErr) throw 'invalid untilDate param'; + sinceDate: $.num.optional.note({ + desc: { + ja: '指定した時間を基点としてより新しい投稿を取得します。数値は、1970年1月1日 00:00:00 UTC から指定した日時までの経過時間をミリ秒単位で表します。' + } + }), - // Check if only one of sinceId, untilId, sinceDate, untilDate specified - if ([sinceId, untilId, sinceDate, untilDate].filter(x => x != null).length > 1) { - throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; - } + untilDate: $.num.optional.note({ + desc: { + ja: '指定した時間を基点としてより古い投稿を取得します。数値は、1970年1月1日 00:00:00 UTC から指定した日時までの経過時間をミリ秒単位で表します。' + } + }), - // Get 'includeMyRenotes' parameter - const [includeMyRenotes = true, includeMyRenotesErr] = $.bool.optional.get(params.includeMyRenotes); - if (includeMyRenotesErr) throw 'invalid includeMyRenotes param'; + includeMyRenotes: $.bool.optional.note({ + default: true, + desc: { + ja: '自分の行ったRenoteを含めるかどうか' + } + }), - // Get 'includeRenotedMyNotes' parameter - const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional.get(params.includeRenotedMyNotes); - if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param'; + includeRenotedMyNotes: $.bool.optional.note({ + default: true, + desc: { + ja: 'Renoteされた自分の投稿を含めるかどうか' + } + }), - // Get 'mediaOnly' parameter - const [mediaOnly, mediaOnlyErr] = $.bool.optional.get(params.mediaOnly); - if (mediaOnlyErr) throw 'invalid mediaOnly param'; + includeLocalRenotes: $.bool.optional.note({ + default: true, + desc: { + ja: 'Renoteされたローカルの投稿を含めるかどうか' + } + }), - // Get 'listId' parameter - const [listId, listIdErr] = $.type(ID).get(params.listId); - if (listIdErr) throw 'invalid listId param'; + mediaOnly: $.bool.optional.note({ + desc: { + ja: 'true にすると、メディアが添付された投稿だけ取得します' + } + }), + } +}; + +export default async (params: any, user: ILocalUser) => { + const [ps, psErr] = getParams(meta, params); + if (psErr) throw psErr; const [list, mutedUserIds] = await Promise.all([ // リストを取得 // Fetch the list UserList.findOne({ - _id: listId, + _id: ps.listId, userId: user._id }), @@ -122,7 +151,7 @@ export default async (params: any, user: ILocalUser) => { // つまり、「『自分の投稿かつRenote』ではない」を「『自分の投稿ではない』または『Renoteではない』」と表現します。 // for details: https://en.wikipedia.org/wiki/De_Morgan%27s_laws - if (includeMyRenotes === false) { + if (ps.includeMyRenotes === false) { query.$and.push({ $or: [{ userId: { $ne: user._id } @@ -138,7 +167,7 @@ export default async (params: any, user: ILocalUser) => { }); } - if (includeRenotedMyNotes === false) { + if (ps.includeRenotedMyNotes === false) { query.$and.push({ $or: [{ '_renote.userId': { $ne: user._id } @@ -154,29 +183,45 @@ export default async (params: any, user: ILocalUser) => { }); } - if (mediaOnly) { + if (ps.includeLocalRenotes === false) { + query.$and.push({ + $or: [{ + '_renote.user.host': { $ne: null } + }, { + renoteId: null + }, { + text: { $ne: null } + }, { + mediaIds: { $ne: [] } + }, { + poll: { $ne: null } + }] + }); + } + + if (ps.mediaOnly) { query.$and.push({ mediaIds: { $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 @@ -184,7 +229,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/users/notes.ts b/src/server/api/endpoints/users/notes.ts index c60050d3cd..ff7855bde0 100644 --- a/src/server/api/endpoints/users/notes.ts +++ b/src/server/api/endpoints/users/notes.ts @@ -16,17 +16,13 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => if (usernameErr) return rej('invalid username param'); if (userId === undefined && username === undefined) { - return rej('userId or pair of username and host is required'); + 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'); - if (userId === undefined && host === undefined) { - return rej('userId or pair of username and host is required'); - } - // Get 'includeReplies' parameter const [includeReplies = true, includeRepliesErr] = $.bool.optional.get(params.includeReplies); if (includeRepliesErr) return rej('invalid includeReplies param'); diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts index 563b6ca845..16ec33bcbf 100644 --- a/src/server/api/private/signup.ts +++ b/src/server/api/private/signup.ts @@ -92,7 +92,7 @@ export default async (ctx: Koa.Context) => { weight: null }, settings: { - autoWatch: true + autoWatch: false } }); |