summaryrefslogtreecommitdiff
path: root/src/server/api/endpoints/messaging
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2018-03-29 14:51:06 +0900
committerGitHub <noreply@github.com>2018-03-29 14:51:06 +0900
commit0b5597c873d2d9d45be94a18e1b74f44d9925185 (patch)
tree8b4dac3a56cf703650c8207f9279028a8560a96b /src/server/api/endpoints/messaging
parentoops (diff)
parentResolve conflicts (diff)
downloadmisskey-0b5597c873d2d9d45be94a18e1b74f44d9925185.tar.gz
misskey-0b5597c873d2d9d45be94a18e1b74f44d9925185.tar.bz2
misskey-0b5597c873d2d9d45be94a18e1b74f44d9925185.zip
Merge pull request #1332 from syuilo/pr/1327
Pr/1327
Diffstat (limited to 'src/server/api/endpoints/messaging')
-rw-r--r--src/server/api/endpoints/messaging/history.ts43
-rw-r--r--src/server/api/endpoints/messaging/messages.ts102
-rw-r--r--src/server/api/endpoints/messaging/messages/create.ts156
-rw-r--r--src/server/api/endpoints/messaging/unread.ts33
4 files changed, 334 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..2bf3ed996d
--- /dev/null
+++ b/src/server/api/endpoints/messaging/history.ts
@@ -0,0 +1,43 @@
+/**
+ * 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
+ *
+ * @param {any} params
+ * @param {any} user
+ * @return {Promise<any>}
+ */
+module.exports = (params, user) => new Promise(async (res, rej) => {
+ // Get 'limit' parameter
+ const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ 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..dd80e41d03
--- /dev/null
+++ b/src/server/api/endpoints/messaging/messages.ts
@@ -0,0 +1,102 @@
+/**
+ * Module dependencies
+ */
+import $ from 'cafy';
+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] = $(params.userId).id().$;
+ 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] = $(params.markAsRead).optional.boolean().$;
+ if (markAsReadErr) return rej('invalid markAsRead param');
+
+ // Get 'limit' parameter
+ const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ if (limitErr) return rej('invalid limit param');
+
+ // Get 'sinceId' parameter
+ const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ if (sinceIdErr) return rej('invalid sinceId param');
+
+ // Get 'untilId' parameter
+ const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ 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..4edd726552
--- /dev/null
+++ b/src/server/api/endpoints/messaging/messages/create.ts
@@ -0,0 +1,156 @@
+/**
+ * Module dependencies
+ */
+import $ from 'cafy';
+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 '../../../event';
+import { publishMessagingStream, publishMessagingIndexStream, pushSw } from '../../../event';
+import config from '../../../../../conf';
+
+/**
+ * Create a message
+ *
+ * @param {any} params
+ * @param {any} user
+ * @return {Promise<any>}
+ */
+module.exports = (params, user) => new Promise(async (res, rej) => {
+ // Get 'userId' parameter
+ const [recipientId, recipientIdErr] = $(params.userId).id().$;
+ 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] = $(params.text).optional.string().pipe(isValidText).$;
+ if (textErr) return rej('invalid text');
+
+ // Get 'fileId' parameter
+ const [fileId, fileIdErr] = $(params.fileId).optional.id().$;
+ 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..f7f4047b67
--- /dev/null
+++ b/src/server/api/endpoints/messaging/unread.ts
@@ -0,0 +1,33 @@
+/**
+ * Module dependencies
+ */
+import Message from '../../models/messaging-message';
+import Mute from '../../models/mute';
+
+/**
+ * Get count of unread messages
+ *
+ * @param {any} params
+ * @param {any} user
+ * @return {Promise<any>}
+ */
+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
+ });
+});