diff --git a/src/api/common/add-file-to-drive.ts b/src/api/common/add-file-to-drive.ts index 23cbc44e6..1ee455c09 100644 --- a/src/api/common/add-file-to-drive.ts +++ b/src/api/common/add-file-to-drive.ts @@ -12,7 +12,7 @@ import prominence = require('prominence'); import DriveFile, { getGridFSBucket } from '../models/drive-file'; import DriveFolder from '../models/drive-folder'; -import serialize from '../serializers/drive-file'; +import { pack } from '../models/drive-file'; import event, { publishDriveStream } from '../event'; import config from '../../conf'; @@ -282,7 +282,7 @@ export default (user: any, file: string | stream.Readable, ...args) => new Promi log(`drive file has been created ${file._id}`); resolve(file); - serialize(file).then(serializedFile => { + pack(file).then(serializedFile => { // Publish drive_file_created event event(user._id, 'drive_file_created', serializedFile); publishDriveStream(user._id, 'file_created', serializedFile); diff --git a/src/api/common/notify.ts b/src/api/common/notify.ts index 2b79416a3..ae5669b84 100644 --- a/src/api/common/notify.ts +++ b/src/api/common/notify.ts @@ -2,7 +2,7 @@ import * as mongo from 'mongodb'; import Notification from '../models/notification'; import Mute from '../models/mute'; import event from '../event'; -import serialize from '../serializers/notification'; +import { pack } from '../models/notification'; export default ( notifiee: mongo.ObjectID, @@ -27,7 +27,7 @@ export default ( // Publish notification event event(notifiee, 'notification', - await serialize(notification)); + await pack(notification)); // 3秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する setTimeout(async () => { @@ -44,7 +44,7 @@ export default ( } //#endregion - event(notifiee, 'unread_notification', await serialize(notification)); + event(notifiee, 'unread_notification', await pack(notification)); } }, 3000); }); diff --git a/src/api/endpoints/aggregation/posts/reactions.ts b/src/api/endpoints/aggregation/posts/reactions.ts index 2cd4588ae..790b523be 100644 --- a/src/api/endpoints/aggregation/posts/reactions.ts +++ b/src/api/endpoints/aggregation/posts/reactions.ts @@ -35,10 +35,13 @@ module.exports = (params) => new Promise(async (res, rej) => { { deleted_at: { $gt: startTime } } ] }, { - _id: false, - post_id: false - }, { - sort: { created_at: -1 } + sort: { + _id: -1 + }, + fields: { + _id: false, + post_id: false + } }); const graph = []; diff --git a/src/api/endpoints/aggregation/users.ts b/src/api/endpoints/aggregation/users.ts index 9eb2d035e..e38ce92ff 100644 --- a/src/api/endpoints/aggregation/users.ts +++ b/src/api/endpoints/aggregation/users.ts @@ -17,11 +17,14 @@ module.exports = params => new Promise(async (res, rej) => { const users = await User .find({}, { - _id: false, - created_at: true, - deleted_at: true - }, { - sort: { created_at: -1 } + sort: { + _id: -1 + }, + fields: { + _id: false, + created_at: true, + deleted_at: true + } }); const graph = []; diff --git a/src/api/endpoints/app/create.ts b/src/api/endpoints/app/create.ts index ca684de02..0f688792a 100644 --- a/src/api/endpoints/app/create.ts +++ b/src/api/endpoints/app/create.ts @@ -3,9 +3,7 @@ */ import rndstr from 'rndstr'; import $ from 'cafy'; -import App from '../../models/app'; -import { isValidNameId } from '../../models/app'; -import serialize from '../../serializers/app'; +import App, { isValidNameId, pack } from '../../models/app'; /** * @swagger @@ -106,5 +104,5 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { }); // Response - res(await serialize(app)); + res(await pack(app)); }); diff --git a/src/api/endpoints/app/show.ts b/src/api/endpoints/app/show.ts index 054aab859..8bc3dda42 100644 --- a/src/api/endpoints/app/show.ts +++ b/src/api/endpoints/app/show.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import App from '../../models/app'; -import serialize from '../../serializers/app'; +import App, { pack } from '../../models/app'; /** * @swagger @@ -67,7 +66,7 @@ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => } // Send response - res(await serialize(app, user, { + res(await pack(app, user, { includeSecret: isSecure && app.user_id.equals(user._id) })); }); diff --git a/src/api/endpoints/auth/session/show.ts b/src/api/endpoints/auth/session/show.ts index ede8a6763..73ac3185f 100644 --- a/src/api/endpoints/auth/session/show.ts +++ b/src/api/endpoints/auth/session/show.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import AuthSess from '../../../models/auth-session'; -import serialize from '../../../serializers/auth-session'; +import AuthSess, { pack } from '../../../models/auth-session'; /** * @swagger @@ -67,5 +66,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { } // Response - res(await serialize(session, user)); + res(await pack(session, user)); }); diff --git a/src/api/endpoints/auth/session/userkey.ts b/src/api/endpoints/auth/session/userkey.ts index afd3250b0..fc989bf8c 100644 --- a/src/api/endpoints/auth/session/userkey.ts +++ b/src/api/endpoints/auth/session/userkey.ts @@ -5,7 +5,7 @@ import $ from 'cafy'; import App from '../../../models/app'; import AuthSess from '../../../models/auth-session'; import AccessToken from '../../../models/access-token'; -import serialize from '../../../serializers/user'; +import { pack } from '../../../models/user'; /** * @swagger @@ -102,7 +102,7 @@ module.exports = (params) => new Promise(async (res, rej) => { // Response res({ access_token: accessToken.token, - user: await serialize(session.user_id, null, { + user: await pack(session.user_id, null, { detail: true }) }); diff --git a/src/api/endpoints/channels.ts b/src/api/endpoints/channels.ts index 14817d9bd..b9a7d1b78 100644 --- a/src/api/endpoints/channels.ts +++ b/src/api/endpoints/channels.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import Channel from '../models/channel'; -import serialize from '../serializers/channel'; +import Channel, { pack } from '../models/channel'; /** * Get all channels @@ -55,5 +54,5 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(channels.map(async channel => - await serialize(channel, me)))); + await pack(channel, me)))); }); diff --git a/src/api/endpoints/channels/create.ts b/src/api/endpoints/channels/create.ts index a8d7c29dc..695b4515b 100644 --- a/src/api/endpoints/channels/create.ts +++ b/src/api/endpoints/channels/create.ts @@ -4,7 +4,7 @@ import $ from 'cafy'; import Channel from '../../models/channel'; import Watching from '../../models/channel-watching'; -import serialize from '../../serializers/channel'; +import { pack } from '../../models/channel'; /** * Create a channel @@ -28,7 +28,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { }); // Response - res(await serialize(channel)); + res(await pack(channel)); // Create Watching await Watching.insert({ diff --git a/src/api/endpoints/channels/posts.ts b/src/api/endpoints/channels/posts.ts index 9c2d607ed..d722589c2 100644 --- a/src/api/endpoints/channels/posts.ts +++ b/src/api/endpoints/channels/posts.ts @@ -3,8 +3,7 @@ */ import $ from 'cafy'; import { default as Channel, IChannel } from '../../models/channel'; -import Post from '../../models/post'; -import serialize from '../../serializers/post'; +import Post, { pack } from '../../models/post'; /** * Show a posts of a channel @@ -74,6 +73,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(posts.map(async (post) => - await serialize(post, user) + await pack(post, user) ))); }); diff --git a/src/api/endpoints/channels/show.ts b/src/api/endpoints/channels/show.ts index 8861e5459..332da6467 100644 --- a/src/api/endpoints/channels/show.ts +++ b/src/api/endpoints/channels/show.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import { default as Channel, IChannel } from '../../models/channel'; -import serialize from '../../serializers/channel'; +import Channel, { IChannel, pack } from '../../models/channel'; /** * Show a channel @@ -27,5 +26,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { } // Serialize - res(await serialize(channel, user)); + res(await pack(channel, user)); }); diff --git a/src/api/endpoints/drive/files.ts b/src/api/endpoints/drive/files.ts index 3d5f81339..89915331e 100644 --- a/src/api/endpoints/drive/files.ts +++ b/src/api/endpoints/drive/files.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFile from '../../models/drive-file'; -import serialize from '../../serializers/drive-file'; +import DriveFile, { pack } from '../../models/drive-file'; /** * Get drive files @@ -69,6 +68,6 @@ module.exports = async (params, user, app) => { }); // Serialize - const _files = await Promise.all(files.map(file => serialize(file))); + const _files = await Promise.all(files.map(file => pack(file))); return _files; }; diff --git a/src/api/endpoints/drive/files/create.ts b/src/api/endpoints/drive/files/create.ts index 437348a1e..96bcace88 100644 --- a/src/api/endpoints/drive/files/create.ts +++ b/src/api/endpoints/drive/files/create.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import { validateFileName } from '../../../models/drive-file'; -import serialize from '../../../serializers/drive-file'; +import { validateFileName, pack } from '../../../models/drive-file'; import create from '../../../common/add-file-to-drive'; /** @@ -43,7 +42,7 @@ module.exports = async (file, params, user): Promise => { const driveFile = await create(user, file.path, name, null, folderId); // Serialize - return serialize(driveFile); + return pack(driveFile); } catch (e) { console.error(e); diff --git a/src/api/endpoints/drive/files/find.ts b/src/api/endpoints/drive/files/find.ts index a1cdf1643..e026afe93 100644 --- a/src/api/endpoints/drive/files/find.ts +++ b/src/api/endpoints/drive/files/find.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFile from '../../../models/drive-file'; -import serialize from '../../../serializers/drive-file'; +import DriveFile, { pack } from '../../../models/drive-file'; /** * Find a file(s) @@ -31,5 +30,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(files.map(async file => - await serialize(file)))); + await pack(file)))); }); diff --git a/src/api/endpoints/drive/files/show.ts b/src/api/endpoints/drive/files/show.ts index 3c7cf774f..21664f7ba 100644 --- a/src/api/endpoints/drive/files/show.ts +++ b/src/api/endpoints/drive/files/show.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFile from '../../../models/drive-file'; -import serialize from '../../../serializers/drive-file'; +import DriveFile, { pack } from '../../../models/drive-file'; /** * Show a file @@ -29,7 +28,7 @@ module.exports = async (params, user) => { } // Serialize - const _file = await serialize(file, { + const _file = await pack(file, { detail: true }); diff --git a/src/api/endpoints/drive/files/update.ts b/src/api/endpoints/drive/files/update.ts index f39a420d6..83da46211 100644 --- a/src/api/endpoints/drive/files/update.ts +++ b/src/api/endpoints/drive/files/update.ts @@ -3,9 +3,7 @@ */ import $ from 'cafy'; import DriveFolder from '../../../models/drive-folder'; -import DriveFile from '../../../models/drive-file'; -import { validateFileName } from '../../../models/drive-file'; -import serialize from '../../../serializers/drive-file'; +import DriveFile, { validateFileName, pack } from '../../../models/drive-file'; import { publishDriveStream } from '../../../event'; /** @@ -67,7 +65,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Serialize - const fileObj = await serialize(file); + const fileObj = await pack(file); // Response res(fileObj); diff --git a/src/api/endpoints/drive/files/upload_from_url.ts b/src/api/endpoints/drive/files/upload_from_url.ts index 519e0bdf6..68428747e 100644 --- a/src/api/endpoints/drive/files/upload_from_url.ts +++ b/src/api/endpoints/drive/files/upload_from_url.ts @@ -3,8 +3,7 @@ */ import * as URL from 'url'; import $ from 'cafy'; -import { validateFileName } from '../../../models/drive-file'; -import serialize from '../../../serializers/drive-file'; +import { validateFileName, pack } from '../../../models/drive-file'; import create from '../../../common/add-file-to-drive'; import * as debug from 'debug'; import * as tmp from 'tmp'; @@ -63,5 +62,5 @@ module.exports = async (params, user): Promise => { if (e) log(e.stack); }); - return serialize(driveFile); + return pack(driveFile); }; diff --git a/src/api/endpoints/drive/folders.ts b/src/api/endpoints/drive/folders.ts index 7944e2c6a..428bde350 100644 --- a/src/api/endpoints/drive/folders.ts +++ b/src/api/endpoints/drive/folders.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFolder from '../../models/drive-folder'; -import serialize from '../../serializers/drive-folder'; +import DriveFolder, { pack } from '../../models/drive-folder'; /** * Get drive folders @@ -63,5 +62,5 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(folders.map(async folder => - await serialize(folder)))); + await pack(folder)))); }); diff --git a/src/api/endpoints/drive/folders/create.ts b/src/api/endpoints/drive/folders/create.ts index be847b215..03f396ddc 100644 --- a/src/api/endpoints/drive/folders/create.ts +++ b/src/api/endpoints/drive/folders/create.ts @@ -2,9 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFolder from '../../../models/drive-folder'; -import { isValidFolderName } from '../../../models/drive-folder'; -import serialize from '../../../serializers/drive-folder'; +import DriveFolder, { isValidFolderName, pack } from '../../../models/drive-folder'; import { publishDriveStream } from '../../../event'; /** @@ -47,7 +45,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Serialize - const folderObj = await serialize(folder); + const folderObj = await pack(folder); // Response res(folderObj); diff --git a/src/api/endpoints/drive/folders/find.ts b/src/api/endpoints/drive/folders/find.ts index a5eb8e015..fc84766bc 100644 --- a/src/api/endpoints/drive/folders/find.ts +++ b/src/api/endpoints/drive/folders/find.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFolder from '../../../models/drive-folder'; -import serialize from '../../../serializers/drive-folder'; +import DriveFolder, { pack } from '../../../models/drive-folder'; /** * Find a folder(s) @@ -30,5 +29,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Serialize - res(await Promise.all(folders.map(folder => serialize(folder)))); + res(await Promise.all(folders.map(folder => pack(folder)))); }); diff --git a/src/api/endpoints/drive/folders/show.ts b/src/api/endpoints/drive/folders/show.ts index 9b1c04ca3..e07d14d20 100644 --- a/src/api/endpoints/drive/folders/show.ts +++ b/src/api/endpoints/drive/folders/show.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFolder from '../../../models/drive-folder'; -import serialize from '../../../serializers/drive-folder'; +import DriveFolder, { pack } from '../../../models/drive-folder'; /** * Show a folder @@ -29,7 +28,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { } // Serialize - res(await serialize(folder, { + res(await pack(folder, { detail: true })); }); diff --git a/src/api/endpoints/drive/folders/update.ts b/src/api/endpoints/drive/folders/update.ts index ff673402a..d3df8bdae 100644 --- a/src/api/endpoints/drive/folders/update.ts +++ b/src/api/endpoints/drive/folders/update.ts @@ -2,9 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFolder from '../../../models/drive-folder'; -import { isValidFolderName } from '../../../models/drive-folder'; -import serialize from '../../../serializers/drive-folder'; +import DriveFolder, { isValidFolderName, pack } from '../../../models/drive-folder'; import { publishDriveStream } from '../../../event'; /** @@ -91,7 +89,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Serialize - const folderObj = await serialize(folder); + const folderObj = await pack(folder); // Response res(folderObj); diff --git a/src/api/endpoints/drive/stream.ts b/src/api/endpoints/drive/stream.ts index 5b0eb0a0d..8352c7dd4 100644 --- a/src/api/endpoints/drive/stream.ts +++ b/src/api/endpoints/drive/stream.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFile from '../../models/drive-file'; -import serialize from '../../serializers/drive-file'; +import DriveFile, { pack } from '../../models/drive-file'; /** * Get drive stream @@ -64,5 +63,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(files.map(async file => - await serialize(file)))); + await pack(file)))); }); diff --git a/src/api/endpoints/following/create.ts b/src/api/endpoints/following/create.ts index b4a2217b1..8e1aa3471 100644 --- a/src/api/endpoints/following/create.ts +++ b/src/api/endpoints/following/create.ts @@ -2,11 +2,10 @@ * Module dependencies */ import $ from 'cafy'; -import User from '../../models/user'; +import User, { pack as packUser } from '../../models/user'; import Following from '../../models/following'; import notify from '../../common/notify'; import event from '../../event'; -import serializeUser from '../../serializers/user'; /** * Follow a user @@ -77,8 +76,8 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Publish follow event - event(follower._id, 'follow', await serializeUser(followee, follower)); - event(followee._id, 'followed', await serializeUser(follower, followee)); + event(follower._id, 'follow', await packUser(followee, follower)); + event(followee._id, 'followed', await packUser(follower, followee)); // Notify notify(followee._id, follower._id, 'follow'); diff --git a/src/api/endpoints/following/delete.ts b/src/api/endpoints/following/delete.ts index aa1639ef6..b68cec09d 100644 --- a/src/api/endpoints/following/delete.ts +++ b/src/api/endpoints/following/delete.ts @@ -2,10 +2,9 @@ * Module dependencies */ import $ from 'cafy'; -import User from '../../models/user'; +import User, { pack as packUser } from '../../models/user'; import Following from '../../models/following'; import event from '../../event'; -import serializeUser from '../../serializers/user'; /** * Unfollow a user @@ -78,5 +77,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Publish follow event - event(follower._id, 'unfollow', await serializeUser(followee, follower)); + event(follower._id, 'unfollow', await packUser(followee, follower)); }); diff --git a/src/api/endpoints/i.ts b/src/api/endpoints/i.ts index ae75f11d5..7efdbcd7c 100644 --- a/src/api/endpoints/i.ts +++ b/src/api/endpoints/i.ts @@ -1,8 +1,7 @@ /** * Module dependencies */ -import User from '../models/user'; -import serialize from '../serializers/user'; +import User, { pack } from '../models/user'; /** * Show myself @@ -15,7 +14,7 @@ import serialize from '../serializers/user'; */ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => { // Serialize - res(await serialize(user, user, { + res(await pack(user, user, { detail: true, includeSecrets: isSecure })); diff --git a/src/api/endpoints/i/authorized_apps.ts b/src/api/endpoints/i/authorized_apps.ts index 807ca5b1e..40ce7a68c 100644 --- a/src/api/endpoints/i/authorized_apps.ts +++ b/src/api/endpoints/i/authorized_apps.ts @@ -3,7 +3,7 @@ */ import $ from 'cafy'; import AccessToken from '../../models/access-token'; -import serialize from '../../serializers/app'; +import { pack } from '../../models/app'; /** * Get authorized apps of my account @@ -39,5 +39,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(tokens.map(async token => - await serialize(token.app_id)))); + await pack(token.app_id)))); }); diff --git a/src/api/endpoints/i/favorites.ts b/src/api/endpoints/i/favorites.ts index a66eaa754..eb464cf0f 100644 --- a/src/api/endpoints/i/favorites.ts +++ b/src/api/endpoints/i/favorites.ts @@ -3,7 +3,7 @@ */ import $ from 'cafy'; import Favorite from '../../models/favorite'; -import serialize from '../../serializers/post'; +import { pack } from '../../models/post'; /** * Get followers of a user @@ -39,6 +39,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(favorites.map(async favorite => - await serialize(favorite.post) + await pack(favorite.post) ))); }); diff --git a/src/api/endpoints/i/notifications.ts b/src/api/endpoints/i/notifications.ts index fb9be7f61..688039a0d 100644 --- a/src/api/endpoints/i/notifications.ts +++ b/src/api/endpoints/i/notifications.ts @@ -4,7 +4,7 @@ import $ from 'cafy'; import Notification from '../../models/notification'; import Mute from '../../models/mute'; -import serialize from '../../serializers/notification'; +import { pack } from '../../models/notification'; import getFriends from '../../common/get-friends'; import read from '../../common/read-notification'; @@ -101,7 +101,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(notifications.map(async notification => - await serialize(notification)))); + await pack(notification)))); // Mark as read all if (notifications.length > 0 && markAsRead) { diff --git a/src/api/endpoints/i/pin.ts b/src/api/endpoints/i/pin.ts index a94950d22..ff546fc2b 100644 --- a/src/api/endpoints/i/pin.ts +++ b/src/api/endpoints/i/pin.ts @@ -4,7 +4,7 @@ import $ from 'cafy'; import User from '../../models/user'; import Post from '../../models/post'; -import serialize from '../../serializers/user'; +import { pack } from '../../models/user'; /** * Pin post @@ -35,7 +35,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { }); // Serialize - const iObj = await serialize(user, user, { + const iObj = await pack(user, user, { detail: true }); diff --git a/src/api/endpoints/i/signin_history.ts b/src/api/endpoints/i/signin_history.ts index e38bfa4d9..859e81653 100644 --- a/src/api/endpoints/i/signin_history.ts +++ b/src/api/endpoints/i/signin_history.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import Signin from '../../models/signin'; -import serialize from '../../serializers/signin'; +import Signin, { pack } from '../../models/signin'; /** * Get signin history of my account @@ -58,5 +57,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(history.map(async record => - await serialize(record)))); + await pack(record)))); }); diff --git a/src/api/endpoints/i/update.ts b/src/api/endpoints/i/update.ts index c484c51a9..7bbbf9590 100644 --- a/src/api/endpoints/i/update.ts +++ b/src/api/endpoints/i/update.ts @@ -2,9 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import User from '../../models/user'; -import { isValidName, isValidDescription, isValidLocation, isValidBirthday } from '../../models/user'; -import serialize from '../../serializers/user'; +import User, { isValidName, isValidDescription, isValidLocation, isValidBirthday, pack } from '../../models/user'; import event from '../../event'; import config from '../../../conf'; @@ -65,7 +63,7 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re }); // Serialize - const iObj = await serialize(user, user, { + const iObj = await pack(user, user, { detail: true, includeSecrets: isSecure }); diff --git a/src/api/endpoints/messaging/history.ts b/src/api/endpoints/messaging/history.ts index f14740dff..1683ca7a8 100644 --- a/src/api/endpoints/messaging/history.ts +++ b/src/api/endpoints/messaging/history.ts @@ -4,7 +4,7 @@ import $ from 'cafy'; import History from '../../models/messaging-history'; import Mute from '../../models/mute'; -import serialize from '../../serializers/messaging-message'; +import { pack } from '../../models/messaging-message'; /** * Show messaging history @@ -39,5 +39,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(history.map(async h => - await serialize(h.message, user)))); + await pack(h.message, user)))); }); diff --git a/src/api/endpoints/messaging/messages.ts b/src/api/endpoints/messaging/messages.ts index 3d3c6950a..67ba5e9d6 100644 --- a/src/api/endpoints/messaging/messages.ts +++ b/src/api/endpoints/messaging/messages.ts @@ -4,7 +4,7 @@ import $ from 'cafy'; import Message from '../../models/messaging-message'; import User from '../../models/user'; -import serialize from '../../serializers/messaging-message'; +import { pack } from '../../models/messaging-message'; import read from '../../common/read-messaging-message'; /** @@ -87,7 +87,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(messages.map(async message => - await serialize(message, user, { + await pack(message, user, { populateRecipient: false })))); diff --git a/src/api/endpoints/messaging/messages/create.ts b/src/api/endpoints/messaging/messages/create.ts index 4e9d10197..1b8a5f59e 100644 --- a/src/api/endpoints/messaging/messages/create.ts +++ b/src/api/endpoints/messaging/messages/create.ts @@ -8,7 +8,7 @@ import History from '../../../models/messaging-history'; import User from '../../../models/user'; import Mute from '../../../models/mute'; import DriveFile from '../../../models/drive-file'; -import serialize from '../../../serializers/messaging-message'; +import { pack } from '../../../models/messaging-message'; import publishUserStream from '../../../event'; import { publishMessagingStream, publishMessagingIndexStream, pushSw } from '../../../event'; import config from '../../../../conf'; @@ -79,7 +79,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Serialize - const messageObj = await serialize(message); + const messageObj = await pack(message); // Reponse res(messageObj); diff --git a/src/api/endpoints/mute/list.ts b/src/api/endpoints/mute/list.ts index 740e19f0b..19e3b157e 100644 --- a/src/api/endpoints/mute/list.ts +++ b/src/api/endpoints/mute/list.ts @@ -3,7 +3,7 @@ */ import $ from 'cafy'; import Mute from '../../models/mute'; -import serialize from '../../serializers/user'; +import { pack } from '../../models/user'; import getFriends from '../../common/get-friends'; /** @@ -63,7 +63,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Serialize const users = await Promise.all(mutes.map(async m => - await serialize(m.mutee_id, me, { detail: true }))); + await pack(m.mutee_id, me, { detail: true }))); // Response res({ diff --git a/src/api/endpoints/my/apps.ts b/src/api/endpoints/my/apps.ts index eb9c75876..b23619050 100644 --- a/src/api/endpoints/my/apps.ts +++ b/src/api/endpoints/my/apps.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import App from '../../models/app'; -import serialize from '../../serializers/app'; +import App, { pack } from '../../models/app'; /** * Get my apps @@ -37,5 +36,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Reply res(await Promise.all(apps.map(async app => - await serialize(app)))); + await pack(app)))); }); diff --git a/src/api/endpoints/posts.ts b/src/api/endpoints/posts.ts index db166cd67..3b2942592 100644 --- a/src/api/endpoints/posts.ts +++ b/src/api/endpoints/posts.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import Post from '../models/post'; -import serialize from '../serializers/post'; +import Post, { pack } from '../models/post'; /** * Lists all posts @@ -85,5 +84,5 @@ module.exports = (params) => new Promise(async (res, rej) => { }); // Serialize - res(await Promise.all(posts.map(async post => await serialize(post)))); + res(await Promise.all(posts.map(async post => await pack(post)))); }); diff --git a/src/api/endpoints/posts/context.ts b/src/api/endpoints/posts/context.ts index bad59a6be..5ba375897 100644 --- a/src/api/endpoints/posts/context.ts +++ b/src/api/endpoints/posts/context.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import Post from '../../models/post'; -import serialize from '../../serializers/post'; +import Post, { pack } from '../../models/post'; /** * Show a context of a post @@ -60,5 +59,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(context.map(async post => - await serialize(post, user)))); + await pack(post, user)))); }); diff --git a/src/api/endpoints/posts/create.ts b/src/api/endpoints/posts/create.ts index a1d05c67c..0fa52221f 100644 --- a/src/api/endpoints/posts/create.ts +++ b/src/api/endpoints/posts/create.ts @@ -12,7 +12,7 @@ import Mute from '../../models/mute'; import DriveFile from '../../models/drive-file'; import Watching from '../../models/post-watching'; import ChannelWatching from '../../models/channel-watching'; -import serialize from '../../serializers/post'; +import { pack } from '../../models/post'; import notify from '../../common/notify'; import watch from '../../common/watch-post'; import event, { pushSw, publishChannelStream } from '../../event'; @@ -224,7 +224,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { }); // Serialize - const postObj = await serialize(post); + const postObj = await pack(post); // Reponse res({ diff --git a/src/api/endpoints/posts/mentions.ts b/src/api/endpoints/posts/mentions.ts index 3bb4ec3fa..7127db0ad 100644 --- a/src/api/endpoints/posts/mentions.ts +++ b/src/api/endpoints/posts/mentions.ts @@ -4,7 +4,7 @@ import $ from 'cafy'; import Post from '../../models/post'; import getFriends from '../../common/get-friends'; -import serialize from '../../serializers/post'; +import { pack } from '../../models/post'; /** * Get mentions of myself @@ -73,6 +73,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(mentions.map(async mention => - await serialize(mention, user) + await pack(mention, user) ))); }); diff --git a/src/api/endpoints/posts/polls/recommendation.ts b/src/api/endpoints/posts/polls/recommendation.ts index 9c92d6cac..4a3fa3f55 100644 --- a/src/api/endpoints/posts/polls/recommendation.ts +++ b/src/api/endpoints/posts/polls/recommendation.ts @@ -3,8 +3,7 @@ */ import $ from 'cafy'; import Vote from '../../../models/poll-vote'; -import Post from '../../../models/post'; -import serialize from '../../../serializers/post'; +import Post, { pack } from '../../../models/post'; /** * Get recommended polls @@ -56,5 +55,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(posts.map(async post => - await serialize(post, user, { detail: true })))); + await pack(post, user, { detail: true })))); }); diff --git a/src/api/endpoints/posts/reactions.ts b/src/api/endpoints/posts/reactions.ts index eab5d9b25..feb140ab4 100644 --- a/src/api/endpoints/posts/reactions.ts +++ b/src/api/endpoints/posts/reactions.ts @@ -3,8 +3,7 @@ */ import $ from 'cafy'; import Post from '../../models/post'; -import Reaction from '../../models/post-reaction'; -import serialize from '../../serializers/post-reaction'; +import Reaction, { pack } from '../../models/post-reaction'; /** * Show reactions of a post @@ -54,5 +53,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(reactions.map(async reaction => - await serialize(reaction, user)))); + await pack(reaction, user)))); }); diff --git a/src/api/endpoints/posts/reactions/create.ts b/src/api/endpoints/posts/reactions/create.ts index d537463df..0b0e0e294 100644 --- a/src/api/endpoints/posts/reactions/create.ts +++ b/src/api/endpoints/posts/reactions/create.ts @@ -3,13 +3,12 @@ */ import $ from 'cafy'; import Reaction from '../../../models/post-reaction'; -import Post from '../../../models/post'; +import Post, { pack as packPost } from '../../../models/post'; +import { pack as packUser } from '../../../models/user'; import Watching from '../../../models/post-watching'; import notify from '../../../common/notify'; import watch from '../../../common/watch-post'; import { publishPostStream, pushSw } from '../../../event'; -import serializePost from '../../../serializers/post'; -import serializeUser from '../../../serializers/user'; /** * React to a post @@ -90,8 +89,8 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); pushSw(post.user_id, 'reaction', { - user: await serializeUser(user, post.user_id), - post: await serializePost(post, post.user_id), + user: await packUser(user, post.user_id), + post: await packPost(post, post.user_id), reaction: reaction }); diff --git a/src/api/endpoints/posts/replies.ts b/src/api/endpoints/posts/replies.ts index 3fd6a4676..613c4fa24 100644 --- a/src/api/endpoints/posts/replies.ts +++ b/src/api/endpoints/posts/replies.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import Post from '../../models/post'; -import serialize from '../../serializers/post'; +import Post, { pack } from '../../models/post'; /** * Show a replies of a post @@ -50,5 +49,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(replies.map(async post => - await serialize(post, user)))); + await pack(post, user)))); }); diff --git a/src/api/endpoints/posts/reposts.ts b/src/api/endpoints/posts/reposts.ts index bcc6163a1..89ab0e3d5 100644 --- a/src/api/endpoints/posts/reposts.ts +++ b/src/api/endpoints/posts/reposts.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import Post from '../../models/post'; -import serialize from '../../serializers/post'; +import Post, { pack } from '../../models/post'; /** * Show a reposts of a post @@ -70,5 +69,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(reposts.map(async post => - await serialize(post, user)))); + await pack(post, user)))); }); diff --git a/src/api/endpoints/posts/search.ts b/src/api/endpoints/posts/search.ts index 31c9a8d3c..6e26f5539 100644 --- a/src/api/endpoints/posts/search.ts +++ b/src/api/endpoints/posts/search.ts @@ -7,7 +7,7 @@ import Post from '../../models/post'; import User from '../../models/user'; import Mute from '../../models/mute'; import getFriends from '../../common/get-friends'; -import serialize from '../../serializers/post'; +import { pack } from '../../models/post'; /** * Search a post @@ -351,5 +351,5 @@ async function search( // Serialize res(await Promise.all(posts.map(async post => - await serialize(post, me)))); + await pack(post, me)))); } diff --git a/src/api/endpoints/posts/show.ts b/src/api/endpoints/posts/show.ts index 5bfe4f660..383949059 100644 --- a/src/api/endpoints/posts/show.ts +++ b/src/api/endpoints/posts/show.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import Post from '../../models/post'; -import serialize from '../../serializers/post'; +import Post, { pack } from '../../models/post'; /** * Show a post @@ -27,7 +26,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { } // Serialize - res(await serialize(post, user, { + res(await pack(post, user, { detail: true })); }); diff --git a/src/api/endpoints/posts/timeline.ts b/src/api/endpoints/posts/timeline.ts index da7ffd0c1..c41cfdb8b 100644 --- a/src/api/endpoints/posts/timeline.ts +++ b/src/api/endpoints/posts/timeline.ts @@ -7,7 +7,7 @@ import Post from '../../models/post'; import Mute from '../../models/mute'; import ChannelWatching from '../../models/channel-watching'; import getFriends from '../../common/get-friends'; -import serialize from '../../serializers/post'; +import { pack } from '../../models/post'; /** * Get timeline of myself @@ -128,5 +128,5 @@ module.exports = async (params, user, app) => { }); // Serialize - return await Promise.all(timeline.map(post => serialize(post, user))); + return await Promise.all(timeline.map(post => pack(post, user))); }; diff --git a/src/api/endpoints/posts/trend.ts b/src/api/endpoints/posts/trend.ts index 64a195dff..caded92bf 100644 --- a/src/api/endpoints/posts/trend.ts +++ b/src/api/endpoints/posts/trend.ts @@ -3,8 +3,7 @@ */ const ms = require('ms'); import $ from 'cafy'; -import Post from '../../models/post'; -import serialize from '../../serializers/post'; +import Post, { pack } from '../../models/post'; /** * Get trend posts @@ -76,5 +75,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(posts.map(async post => - await serialize(post, user, { detail: true })))); + await pack(post, user, { detail: true })))); }); diff --git a/src/api/endpoints/users.ts b/src/api/endpoints/users.ts index f3c9b66a5..095b9fe40 100644 --- a/src/api/endpoints/users.ts +++ b/src/api/endpoints/users.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import User from '../models/user'; -import serialize from '../serializers/user'; +import User, { pack } from '../models/user'; /** * Lists all users @@ -55,5 +54,5 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(users.map(async user => - await serialize(user, me)))); + await pack(user, me)))); }); diff --git a/src/api/endpoints/users/followers.ts b/src/api/endpoints/users/followers.ts index 4905323ba..b0fb83c68 100644 --- a/src/api/endpoints/users/followers.ts +++ b/src/api/endpoints/users/followers.ts @@ -4,7 +4,7 @@ import $ from 'cafy'; import User from '../../models/user'; import Following from '../../models/following'; -import serialize from '../../serializers/user'; +import { pack } from '../../models/user'; import getFriends from '../../common/get-friends'; /** @@ -82,7 +82,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Serialize const users = await Promise.all(following.map(async f => - await serialize(f.follower_id, me, { detail: true }))); + await pack(f.follower_id, me, { detail: true }))); // Response res({ diff --git a/src/api/endpoints/users/following.ts b/src/api/endpoints/users/following.ts index dc2ff49bb..8e88431e9 100644 --- a/src/api/endpoints/users/following.ts +++ b/src/api/endpoints/users/following.ts @@ -4,7 +4,7 @@ import $ from 'cafy'; import User from '../../models/user'; import Following from '../../models/following'; -import serialize from '../../serializers/user'; +import { pack } from '../../models/user'; import getFriends from '../../common/get-friends'; /** @@ -82,7 +82,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Serialize const users = await Promise.all(following.map(async f => - await serialize(f.followee_id, me, { detail: true }))); + await pack(f.followee_id, me, { detail: true }))); // Response res({ diff --git a/src/api/endpoints/users/get_frequently_replied_users.ts b/src/api/endpoints/users/get_frequently_replied_users.ts index a8add623d..87f4f77a5 100644 --- a/src/api/endpoints/users/get_frequently_replied_users.ts +++ b/src/api/endpoints/users/get_frequently_replied_users.ts @@ -3,8 +3,7 @@ */ import $ from 'cafy'; import Post from '../../models/post'; -import User from '../../models/user'; -import serialize from '../../serializers/user'; +import User, { pack } from '../../models/user'; module.exports = (params, me) => new Promise(async (res, rej) => { // Get 'user_id' parameter @@ -91,7 +90,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Make replies object (includes weights) const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({ - user: await serialize(user, me, { detail: true }), + user: await pack(user, me, { detail: true }), weight: repliedUsers[user] / peak }))); diff --git a/src/api/endpoints/users/posts.ts b/src/api/endpoints/users/posts.ts index 0d8384a43..0c8bceee3 100644 --- a/src/api/endpoints/users/posts.ts +++ b/src/api/endpoints/users/posts.ts @@ -2,9 +2,8 @@ * Module dependencies */ import $ from 'cafy'; -import Post from '../../models/post'; +import Post, { pack } from '../../models/post'; import User from '../../models/user'; -import serialize from '../../serializers/post'; /** * Get posts of a user @@ -124,6 +123,6 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(posts.map(async (post) => - await serialize(post, me) + await pack(post, me) ))); }); diff --git a/src/api/endpoints/users/recommendation.ts b/src/api/endpoints/users/recommendation.ts index 731d68a7b..736233b34 100644 --- a/src/api/endpoints/users/recommendation.ts +++ b/src/api/endpoints/users/recommendation.ts @@ -3,8 +3,7 @@ */ const ms = require('ms'); import $ from 'cafy'; -import User from '../../models/user'; -import serialize from '../../serializers/user'; +import User, { pack } from '../../models/user'; import getFriends from '../../common/get-friends'; /** @@ -44,5 +43,5 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(users.map(async user => - await serialize(user, me, { detail: true })))); + await pack(user, me, { detail: true })))); }); diff --git a/src/api/endpoints/users/search.ts b/src/api/endpoints/users/search.ts index 73a5db47e..39e2ff989 100644 --- a/src/api/endpoints/users/search.ts +++ b/src/api/endpoints/users/search.ts @@ -3,8 +3,7 @@ */ import * as mongo from 'mongodb'; import $ from 'cafy'; -import User from '../../models/user'; -import serialize from '../../serializers/user'; +import User, { pack } from '../../models/user'; import config from '../../../conf'; const escapeRegexp = require('escape-regexp'); @@ -52,7 +51,7 @@ async function byNative(res, rej, me, query, offset, max) { // Serialize res(await Promise.all(users.map(async user => - await serialize(user, me, { detail: true })))); + await pack(user, me, { detail: true })))); } // Search by Elasticsearch @@ -94,6 +93,6 @@ async function byElasticsearch(res, rej, me, query, offset, max) { // Serialize res(await Promise.all(users.map(async user => - await serialize(user, me, { detail: true })))); + await pack(user, me, { detail: true })))); }); } diff --git a/src/api/endpoints/users/search_by_username.ts b/src/api/endpoints/users/search_by_username.ts index 7f2f42f0a..9c5e1905a 100644 --- a/src/api/endpoints/users/search_by_username.ts +++ b/src/api/endpoints/users/search_by_username.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import User from '../../models/user'; -import serialize from '../../serializers/user'; +import User, { pack } from '../../models/user'; /** * Search a user by username @@ -35,5 +34,5 @@ module.exports = (params, me) => new Promise(async (res, rej) => { // Serialize res(await Promise.all(users.map(async user => - await serialize(user, me, { detail: true })))); + await pack(user, me, { detail: true })))); }); diff --git a/src/api/endpoints/users/show.ts b/src/api/endpoints/users/show.ts index 8e74b0fe3..7aea59296 100644 --- a/src/api/endpoints/users/show.ts +++ b/src/api/endpoints/users/show.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import User from '../../models/user'; -import serialize from '../../serializers/user'; +import User, { pack } from '../../models/user'; /** * Show a user @@ -41,7 +40,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => { } // Send response - res(await serialize(user, me, { + res(await pack(user, me, { detail: true })); }); diff --git a/src/api/models/app.ts b/src/api/models/app.ts index 68f2f448b..34e9867db 100644 --- a/src/api/models/app.ts +++ b/src/api/models/app.ts @@ -1,13 +1,97 @@ +import * as mongo from 'mongodb'; +import deepcopy = require('deepcopy'); +import AccessToken from './access-token'; import db from '../../db/mongodb'; +import config from '../../conf'; -const collection = db.get('apps'); +const App = db.get('apps'); +App.createIndex('name_id'); +App.createIndex('name_id_lower'); +App.createIndex('secret'); +export default App; -(collection as any).createIndex('name_id'); // fuck type definition -(collection as any).createIndex('name_id_lower'); // fuck type definition -(collection as any).createIndex('secret'); // fuck type definition - -export default collection as any; // fuck type definition +export type IApp = { + _id: mongo.ObjectID; + created_at: Date; + user_id: mongo.ObjectID; + secret: string; +}; export function isValidNameId(nameId: string): boolean { return typeof nameId == 'string' && /^[a-zA-Z0-9\-]{3,30}$/.test(nameId); } + +/** + * Pack an app for API response + * + * @param {any} app + * @param {any} me? + * @param {any} options? + * @return {Promise} + */ +export const pack = ( + app: any, + me?: any, + options?: { + includeSecret?: boolean, + includeProfileImageIds?: boolean + } +) => new Promise(async (resolve, reject) => { + const opts = options || { + includeSecret: false, + includeProfileImageIds: false + }; + + let _app: any; + + // Populate the app if 'app' is ID + if (mongo.ObjectID.prototype.isPrototypeOf(app)) { + _app = await App.findOne({ + _id: app + }); + } else if (typeof app === 'string') { + _app = await App.findOne({ + _id: new mongo.ObjectID(app) + }); + } else { + _app = deepcopy(app); + } + + // Me + if (me && !mongo.ObjectID.prototype.isPrototypeOf(me)) { + if (typeof me === 'string') { + me = new mongo.ObjectID(me); + } else { + me = me._id; + } + } + + // Rename _id to id + _app.id = _app._id; + delete _app._id; + + delete _app.name_id_lower; + + // Visible by only owner + if (!opts.includeSecret) { + delete _app.secret; + } + + _app.icon_url = _app.icon != null + ? `${config.drive_url}/${_app.icon}` + : `${config.drive_url}/app-default.jpg`; + + if (me) { + // 既に連携しているか + const exist = await AccessToken.count({ + app_id: _app.id, + user_id: me, + }, { + limit: 1 + }); + + _app.is_authorized = exist === 1; + } + + resolve(_app); +}); diff --git a/src/api/models/auth-session.ts b/src/api/models/auth-session.ts index b264a133e..997ec61c2 100644 --- a/src/api/models/auth-session.ts +++ b/src/api/models/auth-session.ts @@ -1,3 +1,45 @@ +import * as mongo from 'mongodb'; +import deepcopy = require('deepcopy'); import db from '../../db/mongodb'; +import { pack as packApp } from './app'; -export default db.get('auth_sessions') as any; // fuck type definition +const AuthSession = db.get('auth_sessions'); +export default AuthSession; + +export interface IAuthSession { + _id: mongo.ObjectID; +} + +/** + * Pack an auth session for API response + * + * @param {any} session + * @param {any} me? + * @return {Promise} + */ +export const pack = ( + session: any, + me?: any +) => new Promise(async (resolve, reject) => { + let _session: any; + + // TODO: Populate session if it ID + + _session = deepcopy(session); + + // Me + if (me && !mongo.ObjectID.prototype.isPrototypeOf(me)) { + if (typeof me === 'string') { + me = new mongo.ObjectID(me); + } else { + me = me._id; + } + } + + delete _session._id; + + // Populate app + _session.app = await packApp(_session.app_id, me); + + resolve(_session); +}); diff --git a/src/api/models/channel.ts b/src/api/models/channel.ts index c80e84dbc..815d53593 100644 --- a/src/api/models/channel.ts +++ b/src/api/models/channel.ts @@ -1,9 +1,11 @@ import * as mongo from 'mongodb'; +import deepcopy = require('deepcopy'); +import { IUser } from './user'; +import Watching from './channel-watching'; import db from '../../db/mongodb'; -const collection = db.get('channels'); - -export default collection as any; // fuck type definition +const Channel = db.get('channels'); +export default Channel; export type IChannel = { _id: mongo.ObjectID; @@ -12,3 +14,61 @@ export type IChannel = { user_id: mongo.ObjectID; index: number; }; + +/** + * Pack a channel for API response + * + * @param channel target + * @param me? serializee + * @return response + */ +export const pack = ( + channel: string | mongo.ObjectID | IChannel, + me?: string | mongo.ObjectID | IUser +) => new Promise(async (resolve, reject) => { + + let _channel: any; + + // Populate the channel if 'channel' is ID + if (mongo.ObjectID.prototype.isPrototypeOf(channel)) { + _channel = await Channel.findOne({ + _id: channel + }); + } else if (typeof channel === 'string') { + _channel = await Channel.findOne({ + _id: new mongo.ObjectID(channel) + }); + } else { + _channel = deepcopy(channel); + } + + // Rename _id to id + _channel.id = _channel._id; + delete _channel._id; + + // Remove needless properties + delete _channel.user_id; + + // Me + const meId: mongo.ObjectID = me + ? mongo.ObjectID.prototype.isPrototypeOf(me) + ? me as mongo.ObjectID + : typeof me === 'string' + ? new mongo.ObjectID(me) + : (me as IUser)._id + : null; + + if (me) { + //#region Watchしているかどうか + const watch = await Watching.findOne({ + user_id: meId, + channel_id: _channel.id, + deleted_at: { $exists: false } + }); + + _channel.is_watching = watch !== null; + //#endregion + } + + resolve(_channel); +}); diff --git a/src/api/models/drive-file.ts b/src/api/models/drive-file.ts index 802ee5a5f..2a46d8dc4 100644 --- a/src/api/models/drive-file.ts +++ b/src/api/models/drive-file.ts @@ -1,9 +1,12 @@ import * as mongodb from 'mongodb'; +import deepcopy = require('deepcopy'); +import { pack as packFolder } from './drive-folder'; +import config from '../../conf'; import monkDb, { nativeDbConn } from '../../db/mongodb'; -const collection = monkDb.get('drive_files.files'); +const DriveFile = monkDb.get('drive_files.files'); -export default collection as any; // fuck type definition +export default DriveFile; const getGridFSBucket = async (): Promise => { const db = await nativeDbConn(); @@ -15,6 +18,19 @@ const getGridFSBucket = async (): Promise => { export { getGridFSBucket }; +export type IDriveFile = { + _id: mongodb.ObjectID; + uploadDate: Date; + md5: string; + filename: string; + contentType: string; + metadata: { + properties: any; + user_id: mongodb.ObjectID; + folder_id: mongodb.ObjectID; + } +}; + export function validateFileName(name: string): boolean { return ( (name.trim().length > 0) && @@ -24,3 +40,74 @@ export function validateFileName(name: string): boolean { (name.indexOf('..') === -1) ); } + +/** + * Pack a drive file for API response + * + * @param {any} file + * @param {any} options? + * @return {Promise} + */ +export const pack = ( + file: any, + options?: { + detail: boolean + } +) => new Promise(async (resolve, reject) => { + const opts = Object.assign({ + detail: false + }, options); + + let _file: any; + + // Populate the file if 'file' is ID + if (mongodb.ObjectID.prototype.isPrototypeOf(file)) { + _file = await DriveFile.findOne({ + _id: file + }); + } else if (typeof file === 'string') { + _file = await DriveFile.findOne({ + _id: new mongodb.ObjectID(file) + }); + } else { + _file = deepcopy(file); + } + + if (!_file) return reject('invalid file arg.'); + + // rendered target + let _target: any = {}; + + _target.id = _file._id; + _target.created_at = _file.uploadDate; + _target.name = _file.filename; + _target.type = _file.contentType; + _target.datasize = _file.length; + _target.md5 = _file.md5; + + _target = Object.assign(_target, _file.metadata); + + _target.url = `${config.drive_url}/${_target.id}/${encodeURIComponent(_target.name)}`; + + if (_target.properties == null) _target.properties = {}; + + if (opts.detail) { + if (_target.folder_id) { + // Populate folder + _target.folder = await packFolder(_target.folder_id, { + detail: true + }); + } + + /* + if (_target.tags) { + // Populate tags + _target.tags = await _target.tags.map(async (tag: any) => + await serializeDriveTag(tag) + ); + } + */ + } + + resolve(_target); +}); diff --git a/src/api/models/drive-folder.ts b/src/api/models/drive-folder.ts index f81ffe855..54b45049b 100644 --- a/src/api/models/drive-folder.ts +++ b/src/api/models/drive-folder.ts @@ -1,6 +1,18 @@ +import * as mongo from 'mongodb'; +import deepcopy = require('deepcopy'); import db from '../../db/mongodb'; +import DriveFile from './drive-file'; -export default db.get('drive_folders') as any; // fuck type definition +const DriveFolder = db.get('drive_folders'); +export default DriveFolder; + +export type IDriveFolder = { + _id: mongo.ObjectID; + created_at: Date; + name: string; + user_id: mongo.ObjectID; + parent_id: mongo.ObjectID; +}; export function isValidFolderName(name: string): boolean { return ( @@ -8,3 +20,58 @@ export function isValidFolderName(name: string): boolean { (name.length <= 200) ); } + +/** + * Pack a drive folder for API response + * + * @param {any} folder + * @param {any} options? + * @return {Promise} + */ +export const pack = ( + folder: any, + options?: { + detail: boolean + } +) => new Promise(async (resolve, reject) => { + const opts = Object.assign({ + detail: false + }, options); + + let _folder: any; + + // Populate the folder if 'folder' is ID + if (mongo.ObjectID.prototype.isPrototypeOf(folder)) { + _folder = await DriveFolder.findOne({ _id: folder }); + } else if (typeof folder === 'string') { + _folder = await DriveFolder.findOne({ _id: new mongo.ObjectID(folder) }); + } else { + _folder = deepcopy(folder); + } + + // Rename _id to id + _folder.id = _folder._id; + delete _folder._id; + + if (opts.detail) { + const childFoldersCount = await DriveFolder.count({ + parent_id: _folder.id + }); + + const childFilesCount = await DriveFile.count({ + 'metadata.folder_id': _folder.id + }); + + _folder.folders_count = childFoldersCount; + _folder.files_count = childFilesCount; + } + + if (opts.detail && _folder.parent_id) { + // Populate parent folder + _folder.parent = await pack(_folder.parent_id, { + detail: true + }); + } + + resolve(_folder); +}); diff --git a/src/api/models/messaging-message.ts b/src/api/models/messaging-message.ts index 18afa57e4..90cf1cd71 100644 --- a/src/api/models/messaging-message.ts +++ b/src/api/models/messaging-message.ts @@ -1,12 +1,81 @@ import * as mongo from 'mongodb'; +import deepcopy = require('deepcopy'); +import { pack as packUser } from './user'; +import { pack as packFile } from './drive-file'; import db from '../../db/mongodb'; +import parse from '../common/text'; -export default db.get('messaging_messages') as any; // fuck type definition +const MessagingMessage = db.get('messaging_messages'); +export default MessagingMessage; export interface IMessagingMessage { _id: mongo.ObjectID; + created_at: Date; + text: string; + user_id: mongo.ObjectID; + recipient_id: mongo.ObjectID; + is_read: boolean; } export function isValidText(text: string): boolean { return text.length <= 1000 && text.trim() != ''; } + +/** + * Pack a messaging message for API response + * + * @param {any} message + * @param {any} me? + * @param {any} options? + * @return {Promise} + */ +export const pack = ( + message: any, + me?: any, + options?: { + populateRecipient: boolean + } +) => new Promise(async (resolve, reject) => { + const opts = options || { + populateRecipient: true + }; + + let _message: any; + + // Populate the message if 'message' is ID + if (mongo.ObjectID.prototype.isPrototypeOf(message)) { + _message = await MessagingMessage.findOne({ + _id: message + }); + } else if (typeof message === 'string') { + _message = await MessagingMessage.findOne({ + _id: new mongo.ObjectID(message) + }); + } else { + _message = deepcopy(message); + } + + // Rename _id to id + _message.id = _message._id; + delete _message._id; + + // Parse text + if (_message.text) { + _message.ast = parse(_message.text); + } + + // Populate user + _message.user = await packUser(_message.user_id, me); + + if (_message.file) { + // Populate file + _message.file = await packFile(_message.file_id); + } + + if (opts.populateRecipient) { + // Populate recipient + _message.recipient = await packUser(_message.recipient_id, me); + } + + resolve(_message); +}); diff --git a/src/api/models/notification.ts b/src/api/models/notification.ts index e3dc6c70a..fa7049d31 100644 --- a/src/api/models/notification.ts +++ b/src/api/models/notification.ts @@ -1,8 +1,11 @@ import * as mongo from 'mongodb'; +import deepcopy = require('deepcopy'); import db from '../../db/mongodb'; -import { IUser } from './user'; +import { IUser, pack as packUser } from './user'; +import { pack as packPost } from './post'; -export default db.get('notifications') as any; // fuck type definition +const Notification = db.get('notifications'); +export default Notification; export interface INotification { _id: mongo.ObjectID; @@ -45,3 +48,60 @@ export interface INotification { */ is_read: Boolean; } + +/** + * Pack a notification for API response + * + * @param {any} notification + * @return {Promise} + */ +export const pack = (notification: any) => new Promise(async (resolve, reject) => { + let _notification: any; + + // Populate the notification if 'notification' is ID + if (mongo.ObjectID.prototype.isPrototypeOf(notification)) { + _notification = await Notification.findOne({ + _id: notification + }); + } else if (typeof notification === 'string') { + _notification = await Notification.findOne({ + _id: new mongo.ObjectID(notification) + }); + } else { + _notification = deepcopy(notification); + } + + // Rename _id to id + _notification.id = _notification._id; + delete _notification._id; + + // Rename notifier_id to user_id + _notification.user_id = _notification.notifier_id; + delete _notification.notifier_id; + + const me = _notification.notifiee_id; + delete _notification.notifiee_id; + + // Populate notifier + _notification.user = await packUser(_notification.user_id, me); + + switch (_notification.type) { + case 'follow': + // nope + break; + case 'mention': + case 'reply': + case 'repost': + case 'quote': + case 'reaction': + case 'poll_vote': + // Populate post + _notification.post = await packPost(_notification.post_id, me); + break; + default: + console.error(`Unknown type: ${_notification.type}`); + break; + } + + resolve(_notification); +}); diff --git a/src/api/models/post-reaction.ts b/src/api/models/post-reaction.ts index 282ae5bd2..639a70e00 100644 --- a/src/api/models/post-reaction.ts +++ b/src/api/models/post-reaction.ts @@ -1,3 +1,51 @@ +import * as mongo from 'mongodb'; +import deepcopy = require('deepcopy'); import db from '../../db/mongodb'; +import Reaction from './post-reaction'; +import { pack as packUser } from './user'; -export default db.get('post_reactions') as any; // fuck type definition +const PostReaction = db.get('post_reactions'); +export default PostReaction; + +export interface IPostReaction { + _id: mongo.ObjectID; + created_at: Date; + deleted_at: Date; + reaction: string; +} + +/** + * Pack a reaction for API response + * + * @param {any} reaction + * @param {any} me? + * @return {Promise} + */ +export const pack = ( + reaction: any, + me?: any +) => new Promise(async (resolve, reject) => { + let _reaction: any; + + // Populate the reaction if 'reaction' is ID + if (mongo.ObjectID.prototype.isPrototypeOf(reaction)) { + _reaction = await Reaction.findOne({ + _id: reaction + }); + } else if (typeof reaction === 'string') { + _reaction = await Reaction.findOne({ + _id: new mongo.ObjectID(reaction) + }); + } else { + _reaction = deepcopy(reaction); + } + + // Rename _id to id + _reaction.id = _reaction._id; + delete _reaction._id; + + // Populate user + _reaction.user = await packUser(_reaction.user_id, me); + + resolve(_reaction); +}); diff --git a/src/api/models/post.ts b/src/api/models/post.ts index 7584ce182..0bbacebf6 100644 --- a/src/api/models/post.ts +++ b/src/api/models/post.ts @@ -1,8 +1,18 @@ import * as mongo from 'mongodb'; - +import deepcopy = require('deepcopy'); +import rap from '@prezzemolo/rap'; import db from '../../db/mongodb'; +import { IUser, pack as packUser } from './user'; +import { pack as packApp } from './app'; +import { pack as packChannel } from './channel'; +import Vote from './poll-vote'; +import Reaction from './post-reaction'; +import { pack as packFile } from './drive-file'; +import parse from '../common/text'; -export default db.get('posts') as any; // fuck type definition +const Post = db.get('posts'); + +export default Post; export function isValidText(text: string): boolean { return text.length <= 1000 && text.trim() != ''; @@ -15,8 +25,185 @@ export type IPost = { media_ids: mongo.ObjectID[]; reply_id: mongo.ObjectID; repost_id: mongo.ObjectID; - poll: {}; // todo + poll: any; // todo text: string; user_id: mongo.ObjectID; app_id: mongo.ObjectID; + category: string; + is_category_verified: boolean; +}; + +/** + * Pack a post for API response + * + * @param post target + * @param me? serializee + * @param options? serialize options + * @return response + */ +export const pack = async ( + post: string | mongo.ObjectID | IPost, + me?: string | mongo.ObjectID | IUser, + options?: { + detail: boolean + } +) => { + const opts = options || { + detail: true, + }; + + // Me + const meId: mongo.ObjectID = me + ? mongo.ObjectID.prototype.isPrototypeOf(me) + ? me as mongo.ObjectID + : typeof me === 'string' + ? new mongo.ObjectID(me) + : (me as IUser)._id + : null; + + let _post: any; + + // Populate the post if 'post' is ID + if (mongo.ObjectID.prototype.isPrototypeOf(post)) { + _post = await Post.findOne({ + _id: post + }); + } else if (typeof post === 'string') { + _post = await Post.findOne({ + _id: new mongo.ObjectID(post) + }); + } else { + _post = deepcopy(post); + } + + if (!_post) throw 'invalid post arg.'; + + const id = _post._id; + + // Rename _id to id + _post.id = _post._id; + delete _post._id; + + delete _post.mentions; + + // Parse text + if (_post.text) { + _post.ast = parse(_post.text); + } + + // Populate user + _post.user = packUser(_post.user_id, meId); + + // Populate app + if (_post.app_id) { + _post.app = packApp(_post.app_id); + } + + // Populate channel + if (_post.channel_id) { + _post.channel = packChannel(_post.channel_id); + } + + // Populate media + if (_post.media_ids) { + _post.media = Promise.all(_post.media_ids.map(fileId => + packFile(fileId) + )); + } + + // When requested a detailed post data + if (opts.detail) { + // Get previous post info + _post.prev = (async () => { + const prev = await Post.findOne({ + user_id: _post.user_id, + _id: { + $lt: id + } + }, { + fields: { + _id: true + }, + sort: { + _id: -1 + } + }); + return prev ? prev._id : null; + })(); + + // Get next post info + _post.next = (async () => { + const next = await Post.findOne({ + user_id: _post.user_id, + _id: { + $gt: id + } + }, { + fields: { + _id: true + }, + sort: { + _id: 1 + } + }); + return next ? next._id : null; + })(); + + if (_post.reply_id) { + // Populate reply to post + _post.reply = pack(_post.reply_id, meId, { + detail: false + }); + } + + if (_post.repost_id) { + // Populate repost + _post.repost = pack(_post.repost_id, meId, { + detail: _post.text == null + }); + } + + // Poll + if (meId && _post.poll) { + _post.poll = (async (poll) => { + const vote = await Vote + .findOne({ + user_id: meId, + post_id: id + }); + + if (vote != null) { + const myChoice = poll.choices + .filter(c => c.id == vote.choice)[0]; + + myChoice.is_voted = true; + } + + return poll; + })(_post.poll); + } + + // Fetch my reaction + if (meId) { + _post.my_reaction = (async () => { + const reaction = await Reaction + .findOne({ + user_id: meId, + post_id: id, + deleted_at: { $exists: false } + }); + + if (reaction) { + return reaction.reaction; + } + + return null; + })(); + } + } + + // resolve promises in _post object + _post = await rap(_post); + + return _post; }; diff --git a/src/api/models/signin.ts b/src/api/models/signin.ts index 385a348f2..262c8707e 100644 --- a/src/api/models/signin.ts +++ b/src/api/models/signin.ts @@ -1,3 +1,29 @@ +import * as mongo from 'mongodb'; +import deepcopy = require('deepcopy'); import db from '../../db/mongodb'; -export default db.get('signin') as any; // fuck type definition +const Signin = db.get('signin'); +export default Signin; + +export interface ISignin { + _id: mongo.ObjectID; +} + +/** + * Pack a signin record for API response + * + * @param {any} record + * @return {Promise} + */ +export const pack = ( + record: any +) => new Promise(async (resolve, reject) => { + + const _record = deepcopy(record); + + // Rename _id to id + _record.id = _record._id; + delete _record._id; + + resolve(_record); +}); diff --git a/src/api/models/user.ts b/src/api/models/user.ts index 018979158..e92f244dd 100644 --- a/src/api/models/user.ts +++ b/src/api/models/user.ts @@ -1,14 +1,19 @@ import * as mongo from 'mongodb'; - +import deepcopy = require('deepcopy'); +import rap from '@prezzemolo/rap'; import db from '../../db/mongodb'; -import { IPost } from './post'; +import { IPost, pack as packPost } from './post'; +import Following from './following'; +import Mute from './mute'; +import getFriends from '../common/get-friends'; +import config from '../../conf'; -const collection = db.get('users'); +const User = db.get('users'); -(collection as any).createIndex('username'); // fuck type definition -(collection as any).createIndex('token'); // fuck type definition +User.createIndex('username'); +User.createIndex('token'); -export default collection as any; // fuck type definition +export default User; export function validateUsername(username: string): boolean { return typeof username == 'string' && /^[a-zA-Z0-9\-]{3,20}$/.test(username); @@ -37,6 +42,7 @@ export function isValidBirthday(birthday: string): boolean { export type IUser = { _id: mongo.ObjectID; created_at: Date; + deleted_at: Date; email: string; followers_count: number; following_count: number; @@ -83,3 +89,182 @@ export function init(user): IUser { user.pinned_post_id = new mongo.ObjectID(user.pinned_post_id); return user; } + +/** + * Pack a user for API response + * + * @param user target + * @param me? serializee + * @param options? serialize options + * @return Packed user + */ +export const pack = ( + user: string | mongo.ObjectID | IUser, + me?: string | mongo.ObjectID | IUser, + options?: { + detail?: boolean, + includeSecrets?: boolean + } +) => new Promise(async (resolve, reject) => { + + const opts = Object.assign({ + detail: false, + includeSecrets: false + }, options); + + let _user: any; + + const fields = opts.detail ? { + settings: false + } : { + settings: false, + client_settings: false, + profile: false, + keywords: false, + domains: false + }; + + // Populate the user if 'user' is ID + if (mongo.ObjectID.prototype.isPrototypeOf(user)) { + _user = await User.findOne({ + _id: user + }, { fields }); + } else if (typeof user === 'string') { + _user = await User.findOne({ + _id: new mongo.ObjectID(user) + }, { fields }); + } else { + _user = deepcopy(user); + } + + if (!_user) return reject('invalid user arg.'); + + // Me + const meId: mongo.ObjectID = me + ? mongo.ObjectID.prototype.isPrototypeOf(me) + ? me as mongo.ObjectID + : typeof me === 'string' + ? new mongo.ObjectID(me) + : (me as IUser)._id + : null; + + // Rename _id to id + _user.id = _user._id; + delete _user._id; + + // Remove needless properties + delete _user.latest_post; + + // Remove private properties + delete _user.password; + delete _user.token; + delete _user.two_factor_temp_secret; + delete _user.two_factor_secret; + delete _user.username_lower; + if (_user.twitter) { + delete _user.twitter.access_token; + delete _user.twitter.access_token_secret; + } + delete _user.line; + + // Visible via only the official client + if (!opts.includeSecrets) { + delete _user.email; + delete _user.client_settings; + } + + if (!opts.detail) { + delete _user.two_factor_enabled; + } + + _user.avatar_url = _user.avatar_id != null + ? `${config.drive_url}/${_user.avatar_id}` + : `${config.drive_url}/default-avatar.jpg`; + + _user.banner_url = _user.banner_id != null + ? `${config.drive_url}/${_user.banner_id}` + : null; + + if (!meId || !meId.equals(_user.id) || !opts.detail) { + delete _user.avatar_id; + delete _user.banner_id; + + delete _user.drive_capacity; + } + + if (meId && !meId.equals(_user.id)) { + // Whether the user is following + _user.is_following = (async () => { + const follow = await Following.findOne({ + follower_id: meId, + followee_id: _user.id, + deleted_at: { $exists: false } + }); + return follow !== null; + })(); + + // Whether the user is followed + _user.is_followed = (async () => { + const follow2 = await Following.findOne({ + follower_id: _user.id, + followee_id: meId, + deleted_at: { $exists: false } + }); + return follow2 !== null; + })(); + + // Whether the user is muted + _user.is_muted = (async () => { + const mute = await Mute.findOne({ + muter_id: meId, + mutee_id: _user.id, + deleted_at: { $exists: false } + }); + return mute !== null; + })(); + } + + if (opts.detail) { + if (_user.pinned_post_id) { + // Populate pinned post + _user.pinned_post = packPost(_user.pinned_post_id, meId, { + detail: true + }); + } + + if (meId && !meId.equals(_user.id)) { + const myFollowingIds = await getFriends(meId); + + // Get following you know count + _user.following_you_know_count = Following.count({ + followee_id: { $in: myFollowingIds }, + follower_id: _user.id, + deleted_at: { $exists: false } + }); + + // Get followers you know count + _user.followers_you_know_count = Following.count({ + followee_id: _user.id, + follower_id: { $in: myFollowingIds }, + deleted_at: { $exists: false } + }); + } + } + + // resolve promises in _user object + _user = await rap(_user); + + resolve(_user); +}); + +/* +function img(url) { + return { + thumbnail: { + large: `${url}`, + medium: '', + small: '' + } + }; +} +*/ diff --git a/src/api/private/signin.ts b/src/api/private/signin.ts index a26c8f6c5..b49d25d99 100644 --- a/src/api/private/signin.ts +++ b/src/api/private/signin.ts @@ -2,8 +2,7 @@ import * as express from 'express'; import * as bcrypt from 'bcryptjs'; import * as speakeasy from 'speakeasy'; import { default as User, IUser } from '../models/user'; -import Signin from '../models/signin'; -import serialize from '../serializers/signin'; +import Signin, { pack } from '../models/signin'; import event from '../event'; import signin from '../common/signin'; import config from '../../conf'; @@ -85,5 +84,5 @@ export default async (req: express.Request, res: express.Response) => { }); // Publish signin event - event(user._id, 'signin', await serialize(record)); + event(user._id, 'signin', await pack(record)); }; diff --git a/src/api/private/signup.ts b/src/api/private/signup.ts index 466c6a489..8efdb6db4 100644 --- a/src/api/private/signup.ts +++ b/src/api/private/signup.ts @@ -2,9 +2,7 @@ import * as uuid from 'uuid'; import * as express from 'express'; import * as bcrypt from 'bcryptjs'; import recaptcha = require('recaptcha-promise'); -import { default as User, IUser } from '../models/user'; -import { validateUsername, validatePassword } from '../models/user'; -import serialize from '../serializers/user'; +import User, { IUser, validateUsername, validatePassword, pack } from '../models/user'; import generateUserToken from '../common/generate-native-user-token'; import config from '../../conf'; @@ -142,7 +140,7 @@ export default async (req: express.Request, res: express.Response) => { }); // Response - res.send(await serialize(account)); + res.send(await pack(account)); // Create search index if (config.elasticsearch.enable) { diff --git a/src/api/serializers/app.ts b/src/api/serializers/app.ts deleted file mode 100644 index 9d1c46dca..000000000 --- a/src/api/serializers/app.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import deepcopy = require('deepcopy'); -import App from '../models/app'; -import AccessToken from '../models/access-token'; -import config from '../../conf'; - -/** - * Serialize an app - * - * @param {any} app - * @param {any} me? - * @param {any} options? - * @return {Promise} - */ -export default ( - app: any, - me?: any, - options?: { - includeSecret?: boolean, - includeProfileImageIds?: boolean - } -) => new Promise(async (resolve, reject) => { - const opts = options || { - includeSecret: false, - includeProfileImageIds: false - }; - - let _app: any; - - // Populate the app if 'app' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(app)) { - _app = await App.findOne({ - _id: app - }); - } else if (typeof app === 'string') { - _app = await App.findOne({ - _id: new mongo.ObjectID(app) - }); - } else { - _app = deepcopy(app); - } - - // Me - if (me && !mongo.ObjectID.prototype.isPrototypeOf(me)) { - if (typeof me === 'string') { - me = new mongo.ObjectID(me); - } else { - me = me._id; - } - } - - // Rename _id to id - _app.id = _app._id; - delete _app._id; - - delete _app.name_id_lower; - - // Visible by only owner - if (!opts.includeSecret) { - delete _app.secret; - } - - _app.icon_url = _app.icon != null - ? `${config.drive_url}/${_app.icon}` - : `${config.drive_url}/app-default.jpg`; - - if (me) { - // 既に連携しているか - const exist = await AccessToken.count({ - app_id: _app.id, - user_id: me, - }, { - limit: 1 - }); - - _app.is_authorized = exist === 1; - } - - resolve(_app); -}); diff --git a/src/api/serializers/auth-session.ts b/src/api/serializers/auth-session.ts deleted file mode 100644 index a9acf1243..000000000 --- a/src/api/serializers/auth-session.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import deepcopy = require('deepcopy'); -import serializeApp from './app'; - -/** - * Serialize an auth session - * - * @param {any} session - * @param {any} me? - * @return {Promise} - */ -export default ( - session: any, - me?: any -) => new Promise(async (resolve, reject) => { - let _session: any; - - // TODO: Populate session if it ID - - _session = deepcopy(session); - - // Me - if (me && !mongo.ObjectID.prototype.isPrototypeOf(me)) { - if (typeof me === 'string') { - me = new mongo.ObjectID(me); - } else { - me = me._id; - } - } - - delete _session._id; - - // Populate app - _session.app = await serializeApp(_session.app_id, me); - - resolve(_session); -}); diff --git a/src/api/serializers/channel.ts b/src/api/serializers/channel.ts deleted file mode 100644 index 3cba39aa1..000000000 --- a/src/api/serializers/channel.ts +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import deepcopy = require('deepcopy'); -import { IUser } from '../models/user'; -import { default as Channel, IChannel } from '../models/channel'; -import Watching from '../models/channel-watching'; - -/** - * Serialize a channel - * - * @param channel target - * @param me? serializee - * @return response - */ -export default ( - channel: string | mongo.ObjectID | IChannel, - me?: string | mongo.ObjectID | IUser -) => new Promise(async (resolve, reject) => { - - let _channel: any; - - // Populate the channel if 'channel' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(channel)) { - _channel = await Channel.findOne({ - _id: channel - }); - } else if (typeof channel === 'string') { - _channel = await Channel.findOne({ - _id: new mongo.ObjectID(channel) - }); - } else { - _channel = deepcopy(channel); - } - - // Rename _id to id - _channel.id = _channel._id; - delete _channel._id; - - // Remove needless properties - delete _channel.user_id; - - // Me - const meId: mongo.ObjectID = me - ? mongo.ObjectID.prototype.isPrototypeOf(me) - ? me as mongo.ObjectID - : typeof me === 'string' - ? new mongo.ObjectID(me) - : (me as IUser)._id - : null; - - if (me) { - //#region Watchしているかどうか - const watch = await Watching.findOne({ - user_id: meId, - channel_id: _channel.id, - deleted_at: { $exists: false } - }); - - _channel.is_watching = watch !== null; - //#endregion - } - - resolve(_channel); -}); diff --git a/src/api/serializers/drive-file.ts b/src/api/serializers/drive-file.ts deleted file mode 100644 index 003e09ee7..000000000 --- a/src/api/serializers/drive-file.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import DriveFile from '../models/drive-file'; -import serializeDriveFolder from './drive-folder'; -import serializeDriveTag from './drive-tag'; -import deepcopy = require('deepcopy'); -import config from '../../conf'; - -/** - * Serialize a drive file - * - * @param {any} file - * @param {any} options? - * @return {Promise} - */ -export default ( - file: any, - options?: { - detail: boolean - } -) => new Promise(async (resolve, reject) => { - const opts = Object.assign({ - detail: false - }, options); - - let _file: any; - - // Populate the file if 'file' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(file)) { - _file = await DriveFile.findOne({ - _id: file - }); - } else if (typeof file === 'string') { - _file = await DriveFile.findOne({ - _id: new mongo.ObjectID(file) - }); - } else { - _file = deepcopy(file); - } - - if (!_file) return reject('invalid file arg.'); - - // rendered target - let _target: any = {}; - - _target.id = _file._id; - _target.created_at = _file.uploadDate; - _target.name = _file.filename; - _target.type = _file.contentType; - _target.datasize = _file.length; - _target.md5 = _file.md5; - - _target = Object.assign(_target, _file.metadata); - - _target.url = `${config.drive_url}/${_target.id}/${encodeURIComponent(_target.name)}`; - - if (_target.properties == null) _target.properties = {}; - - if (opts.detail) { - if (_target.folder_id) { - // Populate folder - _target.folder = await serializeDriveFolder(_target.folder_id, { - detail: true - }); - } - - if (_target.tags) { - // Populate tags - _target.tags = await _target.tags.map(async (tag: any) => - await serializeDriveTag(tag) - ); - } - } - - resolve(_target); -}); diff --git a/src/api/serializers/drive-folder.ts b/src/api/serializers/drive-folder.ts deleted file mode 100644 index 6ebf454a2..000000000 --- a/src/api/serializers/drive-folder.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import DriveFolder from '../models/drive-folder'; -import DriveFile from '../models/drive-file'; -import deepcopy = require('deepcopy'); - -/** - * Serialize a drive folder - * - * @param {any} folder - * @param {any} options? - * @return {Promise} - */ -const self = ( - folder: any, - options?: { - detail: boolean - } -) => new Promise(async (resolve, reject) => { - const opts = Object.assign({ - detail: false - }, options); - - let _folder: any; - - // Populate the folder if 'folder' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(folder)) { - _folder = await DriveFolder.findOne({ _id: folder }); - } else if (typeof folder === 'string') { - _folder = await DriveFolder.findOne({ _id: new mongo.ObjectID(folder) }); - } else { - _folder = deepcopy(folder); - } - - // Rename _id to id - _folder.id = _folder._id; - delete _folder._id; - - if (opts.detail) { - const childFoldersCount = await DriveFolder.count({ - parent_id: _folder.id - }); - - const childFilesCount = await DriveFile.count({ - 'metadata.folder_id': _folder.id - }); - - _folder.folders_count = childFoldersCount; - _folder.files_count = childFilesCount; - } - - if (opts.detail && _folder.parent_id) { - // Populate parent folder - _folder.parent = await self(_folder.parent_id, { - detail: true - }); - } - - resolve(_folder); -}); - -export default self; diff --git a/src/api/serializers/drive-tag.ts b/src/api/serializers/drive-tag.ts deleted file mode 100644 index 2f152381b..000000000 --- a/src/api/serializers/drive-tag.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import DriveTag from '../models/drive-tag'; -import deepcopy = require('deepcopy'); - -/** - * Serialize a drive tag - * - * @param {any} tag - * @return {Promise} - */ -const self = ( - tag: any -) => new Promise(async (resolve, reject) => { - let _tag: any; - - // Populate the tag if 'tag' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(tag)) { - _tag = await DriveTag.findOne({ _id: tag }); - } else if (typeof tag === 'string') { - _tag = await DriveTag.findOne({ _id: new mongo.ObjectID(tag) }); - } else { - _tag = deepcopy(tag); - } - - // Rename _id to id - _tag.id = _tag._id; - delete _tag._id; - - resolve(_tag); -}); - -export default self; diff --git a/src/api/serializers/messaging-message.ts b/src/api/serializers/messaging-message.ts deleted file mode 100644 index 4ab95e42a..000000000 --- a/src/api/serializers/messaging-message.ts +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import deepcopy = require('deepcopy'); -import Message from '../models/messaging-message'; -import serializeUser from './user'; -import serializeDriveFile from './drive-file'; -import parse from '../common/text'; - -/** - * Serialize a message - * - * @param {any} message - * @param {any} me? - * @param {any} options? - * @return {Promise} - */ -export default ( - message: any, - me?: any, - options?: { - populateRecipient: boolean - } -) => new Promise(async (resolve, reject) => { - const opts = options || { - populateRecipient: true - }; - - let _message: any; - - // Populate the message if 'message' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(message)) { - _message = await Message.findOne({ - _id: message - }); - } else if (typeof message === 'string') { - _message = await Message.findOne({ - _id: new mongo.ObjectID(message) - }); - } else { - _message = deepcopy(message); - } - - // Rename _id to id - _message.id = _message._id; - delete _message._id; - - // Parse text - if (_message.text) { - _message.ast = parse(_message.text); - } - - // Populate user - _message.user = await serializeUser(_message.user_id, me); - - if (_message.file) { - // Populate file - _message.file = await serializeDriveFile(_message.file_id); - } - - if (opts.populateRecipient) { - // Populate recipient - _message.recipient = await serializeUser(_message.recipient_id, me); - } - - resolve(_message); -}); diff --git a/src/api/serializers/notification.ts b/src/api/serializers/notification.ts deleted file mode 100644 index ac919dc8b..000000000 --- a/src/api/serializers/notification.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import Notification from '../models/notification'; -import serializeUser from './user'; -import serializePost from './post'; -import deepcopy = require('deepcopy'); - -/** - * Serialize a notification - * - * @param {any} notification - * @return {Promise} - */ -export default (notification: any) => new Promise(async (resolve, reject) => { - let _notification: any; - - // Populate the notification if 'notification' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(notification)) { - _notification = await Notification.findOne({ - _id: notification - }); - } else if (typeof notification === 'string') { - _notification = await Notification.findOne({ - _id: new mongo.ObjectID(notification) - }); - } else { - _notification = deepcopy(notification); - } - - // Rename _id to id - _notification.id = _notification._id; - delete _notification._id; - - // Rename notifier_id to user_id - _notification.user_id = _notification.notifier_id; - delete _notification.notifier_id; - - const me = _notification.notifiee_id; - delete _notification.notifiee_id; - - // Populate notifier - _notification.user = await serializeUser(_notification.user_id, me); - - switch (_notification.type) { - case 'follow': - // nope - break; - case 'mention': - case 'reply': - case 'repost': - case 'quote': - case 'reaction': - case 'poll_vote': - // Populate post - _notification.post = await serializePost(_notification.post_id, me); - break; - default: - console.error(`Unknown type: ${_notification.type}`); - break; - } - - resolve(_notification); -}); diff --git a/src/api/serializers/post-reaction.ts b/src/api/serializers/post-reaction.ts deleted file mode 100644 index b8807a741..000000000 --- a/src/api/serializers/post-reaction.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import deepcopy = require('deepcopy'); -import Reaction from '../models/post-reaction'; -import serializeUser from './user'; - -/** - * Serialize a reaction - * - * @param {any} reaction - * @param {any} me? - * @return {Promise} - */ -export default ( - reaction: any, - me?: any -) => new Promise(async (resolve, reject) => { - let _reaction: any; - - // Populate the reaction if 'reaction' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(reaction)) { - _reaction = await Reaction.findOne({ - _id: reaction - }); - } else if (typeof reaction === 'string') { - _reaction = await Reaction.findOne({ - _id: new mongo.ObjectID(reaction) - }); - } else { - _reaction = deepcopy(reaction); - } - - // Rename _id to id - _reaction.id = _reaction._id; - delete _reaction._id; - - // Populate user - _reaction.user = await serializeUser(_reaction.user_id, me); - - resolve(_reaction); -}); diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts deleted file mode 100644 index 03fd12077..000000000 --- a/src/api/serializers/post.ts +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import deepcopy = require('deepcopy'); -import { default as Post, IPost } from '../models/post'; -import Reaction from '../models/post-reaction'; -import { IUser } from '../models/user'; -import Vote from '../models/poll-vote'; -import serializeApp from './app'; -import serializeChannel from './channel'; -import serializeUser from './user'; -import serializeDriveFile from './drive-file'; -import parse from '../common/text'; -import rap from '@prezzemolo/rap'; - -/** - * Serialize a post - * - * @param post target - * @param me? serializee - * @param options? serialize options - * @return response - */ -const self = async ( - post: string | mongo.ObjectID | IPost, - me?: string | mongo.ObjectID | IUser, - options?: { - detail: boolean - } -) => { - const opts = options || { - detail: true, - }; - - // Me - const meId: mongo.ObjectID = me - ? mongo.ObjectID.prototype.isPrototypeOf(me) - ? me as mongo.ObjectID - : typeof me === 'string' - ? new mongo.ObjectID(me) - : (me as IUser)._id - : null; - - let _post: any; - - // Populate the post if 'post' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(post)) { - _post = await Post.findOne({ - _id: post - }); - } else if (typeof post === 'string') { - _post = await Post.findOne({ - _id: new mongo.ObjectID(post) - }); - } else { - _post = deepcopy(post); - } - - if (!_post) throw 'invalid post arg.'; - - const id = _post._id; - - // Rename _id to id - _post.id = _post._id; - delete _post._id; - - delete _post.mentions; - - // Parse text - if (_post.text) { - _post.ast = parse(_post.text); - } - - // Populate user - _post.user = serializeUser(_post.user_id, meId); - - // Populate app - if (_post.app_id) { - _post.app = serializeApp(_post.app_id); - } - - // Populate channel - if (_post.channel_id) { - _post.channel = serializeChannel(_post.channel_id); - } - - // Populate media - if (_post.media_ids) { - _post.media = Promise.all(_post.media_ids.map(fileId => - serializeDriveFile(fileId) - )); - } - - // When requested a detailed post data - if (opts.detail) { - // Get previous post info - _post.prev = (async () => { - const prev = await Post.findOne({ - user_id: _post.user_id, - _id: { - $lt: id - } - }, { - fields: { - _id: true - }, - sort: { - _id: -1 - } - }); - return prev ? prev._id : null; - })(); - - // Get next post info - _post.next = (async () => { - const next = await Post.findOne({ - user_id: _post.user_id, - _id: { - $gt: id - } - }, { - fields: { - _id: true - }, - sort: { - _id: 1 - } - }); - return next ? next._id : null; - })(); - - if (_post.reply_id) { - // Populate reply to post - _post.reply = self(_post.reply_id, meId, { - detail: false - }); - } - - if (_post.repost_id) { - // Populate repost - _post.repost = self(_post.repost_id, meId, { - detail: _post.text == null - }); - } - - // Poll - if (meId && _post.poll) { - _post.poll = (async (poll) => { - const vote = await Vote - .findOne({ - user_id: meId, - post_id: id - }); - - if (vote != null) { - const myChoice = poll.choices - .filter(c => c.id == vote.choice)[0]; - - myChoice.is_voted = true; - } - - return poll; - })(_post.poll); - } - - // Fetch my reaction - if (meId) { - _post.my_reaction = (async () => { - const reaction = await Reaction - .findOne({ - user_id: meId, - post_id: id, - deleted_at: { $exists: false } - }); - - if (reaction) { - return reaction.reaction; - } - - return null; - })(); - } - } - - // resolve promises in _post object - _post = await rap(_post); - - return _post; -}; - -export default self; diff --git a/src/api/serializers/signin.ts b/src/api/serializers/signin.ts deleted file mode 100644 index 406806767..000000000 --- a/src/api/serializers/signin.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Module dependencies - */ -import deepcopy = require('deepcopy'); - -/** - * Serialize a signin record - * - * @param {any} record - * @return {Promise} - */ -export default ( - record: any -) => new Promise(async (resolve, reject) => { - - const _record = deepcopy(record); - - // Rename _id to id - _record.id = _record._id; - delete _record._id; - - resolve(_record); -}); diff --git a/src/api/serializers/user.ts b/src/api/serializers/user.ts deleted file mode 100644 index ac157097a..000000000 --- a/src/api/serializers/user.ts +++ /dev/null @@ -1,190 +0,0 @@ -/** - * Module dependencies - */ -import * as mongo from 'mongodb'; -import deepcopy = require('deepcopy'); -import { default as User, IUser } from '../models/user'; -import serializePost from './post'; -import Following from '../models/following'; -import Mute from '../models/mute'; -import getFriends from '../common/get-friends'; -import config from '../../conf'; -import rap from '@prezzemolo/rap'; - -/** - * Serialize a user - * - * @param user target - * @param me? serializee - * @param options? serialize options - * @return response - */ -export default ( - user: string | mongo.ObjectID | IUser, - me?: string | mongo.ObjectID | IUser, - options?: { - detail?: boolean, - includeSecrets?: boolean - } -) => new Promise(async (resolve, reject) => { - - const opts = Object.assign({ - detail: false, - includeSecrets: false - }, options); - - let _user: any; - - const fields = opts.detail ? { - settings: false - } : { - settings: false, - client_settings: false, - profile: false, - keywords: false, - domains: false - }; - - // Populate the user if 'user' is ID - if (mongo.ObjectID.prototype.isPrototypeOf(user)) { - _user = await User.findOne({ - _id: user - }, { fields }); - } else if (typeof user === 'string') { - _user = await User.findOne({ - _id: new mongo.ObjectID(user) - }, { fields }); - } else { - _user = deepcopy(user); - } - - if (!_user) return reject('invalid user arg.'); - - // Me - const meId: mongo.ObjectID = me - ? mongo.ObjectID.prototype.isPrototypeOf(me) - ? me as mongo.ObjectID - : typeof me === 'string' - ? new mongo.ObjectID(me) - : (me as IUser)._id - : null; - - // Rename _id to id - _user.id = _user._id; - delete _user._id; - - // Remove needless properties - delete _user.latest_post; - - // Remove private properties - delete _user.password; - delete _user.token; - delete _user.two_factor_temp_secret; - delete _user.two_factor_secret; - delete _user.username_lower; - if (_user.twitter) { - delete _user.twitter.access_token; - delete _user.twitter.access_token_secret; - } - delete _user.line; - - // Visible via only the official client - if (!opts.includeSecrets) { - delete _user.email; - delete _user.client_settings; - } - - if (!opts.detail) { - delete _user.two_factor_enabled; - } - - _user.avatar_url = _user.avatar_id != null - ? `${config.drive_url}/${_user.avatar_id}` - : `${config.drive_url}/default-avatar.jpg`; - - _user.banner_url = _user.banner_id != null - ? `${config.drive_url}/${_user.banner_id}` - : null; - - if (!meId || !meId.equals(_user.id) || !opts.detail) { - delete _user.avatar_id; - delete _user.banner_id; - - delete _user.drive_capacity; - } - - if (meId && !meId.equals(_user.id)) { - // Whether the user is following - _user.is_following = (async () => { - const follow = await Following.findOne({ - follower_id: meId, - followee_id: _user.id, - deleted_at: { $exists: false } - }); - return follow !== null; - })(); - - // Whether the user is followed - _user.is_followed = (async () => { - const follow2 = await Following.findOne({ - follower_id: _user.id, - followee_id: meId, - deleted_at: { $exists: false } - }); - return follow2 !== null; - })(); - - // Whether the user is muted - _user.is_muted = (async () => { - const mute = await Mute.findOne({ - muter_id: meId, - mutee_id: _user.id, - deleted_at: { $exists: false } - }); - return mute !== null; - })(); - } - - if (opts.detail) { - if (_user.pinned_post_id) { - // Populate pinned post - _user.pinned_post = serializePost(_user.pinned_post_id, meId, { - detail: true - }); - } - - if (meId && !meId.equals(_user.id)) { - const myFollowingIds = await getFriends(meId); - - // Get following you know count - _user.following_you_know_count = Following.count({ - followee_id: { $in: myFollowingIds }, - follower_id: _user.id, - deleted_at: { $exists: false } - }); - - // Get followers you know count - _user.followers_you_know_count = Following.count({ - followee_id: _user.id, - follower_id: { $in: myFollowingIds }, - deleted_at: { $exists: false } - }); - } - } - - // resolve promises in _user object - _user = await rap(_user); - - resolve(_user); -}); -/* -function img(url) { - return { - thumbnail: { - large: `${url}`, - medium: '', - small: '' - } - }; -} -*/ diff --git a/src/api/service/twitter.ts b/src/api/service/twitter.ts index 0e75ee0bd..adcd5ac49 100644 --- a/src/api/service/twitter.ts +++ b/src/api/service/twitter.ts @@ -5,8 +5,7 @@ import * as uuid from 'uuid'; // const Twitter = require('twitter'); import autwh from 'autwh'; import redis from '../../db/redis'; -import User from '../models/user'; -import serialize from '../serializers/user'; +import User, { pack } from '../models/user'; import event from '../event'; import config from '../../conf'; import signin from '../common/signin'; @@ -50,7 +49,7 @@ module.exports = (app: express.Application) => { res.send(`Twitterの連携を解除しました :v:`); // Publish i updated event - event(user._id, 'i_updated', await serialize(user, user, { + event(user._id, 'i_updated', await pack(user, user, { detail: true, includeSecrets: true })); @@ -164,7 +163,7 @@ module.exports = (app: express.Application) => { res.send(`Twitter: @${result.screenName} を、Misskey: @${user.username} に接続しました!`); // Publish i updated event - event(user._id, 'i_updated', await serialize(user, user, { + event(user._id, 'i_updated', await pack(user, user, { detail: true, includeSecrets: true })); diff --git a/src/api/stream/home.ts b/src/api/stream/home.ts index 7dcdb5ed7..10078337c 100644 --- a/src/api/stream/home.ts +++ b/src/api/stream/home.ts @@ -4,7 +4,7 @@ import * as debug from 'debug'; import User from '../models/user'; import Mute from '../models/mute'; -import serializePost from '../serializers/post'; +import { pack as packPost } from '../models/post'; import readNotification from '../common/read-notification'; const log = debug('misskey'); @@ -49,7 +49,7 @@ export default async function(request: websocket.request, connection: websocket. case 'post-stream': const postId = channel.split(':')[2]; log(`RECEIVED: ${postId} ${data} by @${user.username}`); - const post = await serializePost(postId, user, { + const post = await packPost(postId, user, { detail: true }); connection.send(JSON.stringify({