diff options
| author | ha-dai <contact@haradai.net> | 2018-05-04 02:49:46 +0900 |
|---|---|---|
| committer | ha-dai <contact@haradai.net> | 2018-05-04 02:49:46 +0900 |
| commit | f850283147072c681df1b39c57f8bd0b14f18016 (patch) | |
| tree | 63ff533c91097da2d8ca2070fc67a28f67ee33da /src/server/api/endpoints/messaging | |
| parent | Merge branch 'master' of github.com:syuilo/misskey (diff) | |
| parent | 1.7.0 (diff) | |
| download | misskey-f850283147072c681df1b39c57f8bd0b14f18016.tar.gz misskey-f850283147072c681df1b39c57f8bd0b14f18016.tar.bz2 misskey-f850283147072c681df1b39c57f8bd0b14f18016.zip | |
Merge branch 'master' of github.com:syuilo/misskey
Diffstat (limited to 'src/server/api/endpoints/messaging')
| -rw-r--r-- | src/server/api/endpoints/messaging/history.ts | 39 | ||||
| -rw-r--r-- | src/server/api/endpoints/messaging/messages.ts | 102 | ||||
| -rw-r--r-- | src/server/api/endpoints/messaging/messages/create.ts | 153 | ||||
| -rw-r--r-- | src/server/api/endpoints/messaging/unread.ts | 29 |
4 files changed, 323 insertions, 0 deletions
diff --git a/src/server/api/endpoints/messaging/history.ts b/src/server/api/endpoints/messaging/history.ts new file mode 100644 index 0000000000..ec97642f17 --- /dev/null +++ b/src/server/api/endpoints/messaging/history.ts @@ -0,0 +1,39 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; +import History from '../../../../models/messaging-history'; +import Mute from '../../../../models/mute'; +import { pack } from '../../../../models/messaging-message'; + +/** + * Show messaging history + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'limit' parameter + const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit); + if (limitErr) return rej('invalid limit param'); + + const mute = await Mute.find({ + muterId: user._id, + deletedAt: { $exists: false } + }); + + // Get history + const history = await History + .find({ + userId: user._id, + partnerId: { + $nin: mute.map(m => m.muteeId) + } + }, { + limit: limit, + sort: { + updatedAt: -1 + } + }); + + // Serialize + res(await Promise.all(history.map(async h => + await pack(h.messageId, user)))); +}); diff --git a/src/server/api/endpoints/messaging/messages.ts b/src/server/api/endpoints/messaging/messages.ts new file mode 100644 index 0000000000..0338aba68a --- /dev/null +++ b/src/server/api/endpoints/messaging/messages.ts @@ -0,0 +1,102 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../cafy-id'; +import Message from '../../../../models/messaging-message'; +import User from '../../../../models/user'; +import { pack } from '../../../../models/messaging-message'; +import read from '../../common/read-messaging-message'; + +/** + * Get messages + * + * @param {any} params + * @param {any} user + * @return {Promise<any>} + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'userId' parameter + const [recipientId, recipientIdErr] = $.type(ID).get(params.userId); + if (recipientIdErr) return rej('invalid userId param'); + + // Fetch recipient + const recipient = await User.findOne({ + _id: recipientId + }, { + fields: { + _id: true + } + }); + + if (recipient === null) { + return rej('user not found'); + } + + // Get 'markAsRead' parameter + const [markAsRead = true, markAsReadErr] = $.bool.optional().get(params.markAsRead); + if (markAsReadErr) return rej('invalid markAsRead 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'); + + // Check if both of sinceId and untilId is specified + if (sinceId && untilId) { + return rej('cannot set sinceId and untilId'); + } + + const query = { + $or: [{ + userId: user._id, + recipientId: recipient._id + }, { + userId: recipient._id, + recipientId: user._id + }] + } as any; + + const sort = { + _id: -1 + }; + + if (sinceId) { + sort._id = 1; + query._id = { + $gt: sinceId + }; + } else if (untilId) { + query._id = { + $lt: untilId + }; + } + + // Issue query + const messages = await Message + .find(query, { + limit: limit, + sort: sort + }); + + // Serialize + res(await Promise.all(messages.map(async message => + await pack(message, user, { + populateRecipient: false + })))); + + if (messages.length === 0) { + return; + } + + // Mark as read all + if (markAsRead) { + read(user._id, recipient._id, messages); + } +}); diff --git a/src/server/api/endpoints/messaging/messages/create.ts b/src/server/api/endpoints/messaging/messages/create.ts new file mode 100644 index 0000000000..db471839e7 --- /dev/null +++ b/src/server/api/endpoints/messaging/messages/create.ts @@ -0,0 +1,153 @@ +/** + * Module dependencies + */ +import $ from 'cafy'; import ID from '../../../../../cafy-id'; +import Message from '../../../../../models/messaging-message'; +import { isValidText } from '../../../../../models/messaging-message'; +import History from '../../../../../models/messaging-history'; +import User from '../../../../../models/user'; +import Mute from '../../../../../models/mute'; +import DriveFile from '../../../../../models/drive-file'; +import { pack } from '../../../../../models/messaging-message'; +import publishUserStream from '../../../../../publishers/stream'; +import { publishMessagingStream, publishMessagingIndexStream } from '../../../../../publishers/stream'; +import pushSw from '../../../../../publishers/push-sw'; +import config from '../../../../../config'; + +/** + * Create a message + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'userId' parameter + const [recipientId, recipientIdErr] = $.type(ID).get(params.userId); + if (recipientIdErr) return rej('invalid userId param'); + + // Myself + if (recipientId.equals(user._id)) { + return rej('cannot send message to myself'); + } + + // Fetch recipient + const recipient = await User.findOne({ + _id: recipientId + }, { + fields: { + _id: true + } + }); + + if (recipient === null) { + return rej('user not found'); + } + + // Get 'text' parameter + const [text, textErr] = $.str.optional().pipe(isValidText).get(params.text); + if (textErr) return rej('invalid text'); + + // Get 'fileId' parameter + const [fileId, fileIdErr] = $.type(ID).optional().get(params.fileId); + if (fileIdErr) return rej('invalid fileId param'); + + let file = null; + if (fileId !== undefined) { + file = await DriveFile.findOne({ + _id: fileId, + 'metadata.userId': user._id + }); + + if (file === null) { + return rej('file not found'); + } + } + + // テキストが無いかつ添付ファイルも無かったらエラー + if (text === undefined && file === null) { + return rej('text or file is required'); + } + + // メッセージを作成 + const message = await Message.insert({ + createdAt: new Date(), + fileId: file ? file._id : undefined, + recipientId: recipient._id, + text: text ? text : undefined, + userId: user._id, + isRead: false + }); + + // Serialize + const messageObj = await pack(message); + + // Reponse + res(messageObj); + + // 自分のストリーム + publishMessagingStream(message.userId, message.recipientId, 'message', messageObj); + publishMessagingIndexStream(message.userId, 'message', messageObj); + publishUserStream(message.userId, 'messaging_message', messageObj); + + // 相手のストリーム + publishMessagingStream(message.recipientId, message.userId, 'message', messageObj); + publishMessagingIndexStream(message.recipientId, 'message', messageObj); + publishUserStream(message.recipientId, 'messaging_message', messageObj); + + // 3秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する + setTimeout(async () => { + const freshMessage = await Message.findOne({ _id: message._id }, { isRead: true }); + if (!freshMessage.isRead) { + //#region ただしミュートされているなら発行しない + const mute = await Mute.find({ + muterId: recipient._id, + deletedAt: { $exists: false } + }); + const mutedUserIds = mute.map(m => m.muteeId.toString()); + if (mutedUserIds.indexOf(user._id.toString()) != -1) { + return; + } + //#endregion + + publishUserStream(message.recipientId, 'unread_messaging_message', messageObj); + pushSw(message.recipientId, 'unread_messaging_message', messageObj); + } + }, 3000); + + // Register to search database + if (message.text && config.elasticsearch.enable) { + const es = require('../../../db/elasticsearch'); + + es.index({ + index: 'misskey', + type: 'messaging_message', + id: message._id.toString(), + body: { + text: message.text + } + }); + } + + // 履歴作成(自分) + History.update({ + userId: user._id, + partnerId: recipient._id + }, { + updatedAt: new Date(), + userId: user._id, + partnerId: recipient._id, + messageId: message._id + }, { + upsert: true + }); + + // 履歴作成(相手) + History.update({ + userId: recipient._id, + partnerId: user._id + }, { + updatedAt: new Date(), + userId: recipient._id, + partnerId: user._id, + messageId: message._id + }, { + upsert: true + }); +}); diff --git a/src/server/api/endpoints/messaging/unread.ts b/src/server/api/endpoints/messaging/unread.ts new file mode 100644 index 0000000000..1d83af501d --- /dev/null +++ b/src/server/api/endpoints/messaging/unread.ts @@ -0,0 +1,29 @@ +/** + * Module dependencies + */ +import Message from '../../../../models/messaging-message'; +import Mute from '../../../../models/mute'; + +/** + * Get count of unread messages + */ +module.exports = (params, user) => new Promise(async (res, rej) => { + const mute = await Mute.find({ + muterId: user._id, + deletedAt: { $exists: false } + }); + const mutedUserIds = mute.map(m => m.muteeId); + + const count = await Message + .count({ + userId: { + $nin: mutedUserIds + }, + recipientId: user._id, + isRead: false + }); + + res({ + count: count + }); +}); |