summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorrinsuki <428rinsuki+git@gmail.com>2018-05-17 07:52:24 +0900
committerrinsuki <428rinsuki+git@gmail.com>2018-05-17 07:52:24 +0900
commit829b4012e6dc14eb64a3d8f60826fe9b6a41b40d (patch)
tree42ac37f323db349dca9316e6fdb39fc33b860686 /src/server
parentadd yarn.lock to gitignore (diff)
parentUpdate deliver.ts (diff)
downloadmisskey-829b4012e6dc14eb64a3d8f60826fe9b6a41b40d.tar.gz
misskey-829b4012e6dc14eb64a3d8f60826fe9b6a41b40d.tar.bz2
misskey-829b4012e6dc14eb64a3d8f60826fe9b6a41b40d.zip
Merge branch 'master' into fix/yarn-lock-ignore
Diffstat (limited to 'src/server')
-rw-r--r--src/server/activitypub.ts19
-rw-r--r--src/server/api/common/get-friends.ts29
-rw-r--r--src/server/api/common/read-messaging-message.ts2
-rw-r--r--src/server/api/common/read-notification.ts2
-rw-r--r--src/server/api/endpoints.ts53
-rw-r--r--src/server/api/endpoints/aggregation/posts.ts5
-rw-r--r--src/server/api/endpoints/aggregation/users.ts5
-rw-r--r--src/server/api/endpoints/aggregation/users/activity.ts9
-rw-r--r--src/server/api/endpoints/aggregation/users/followers.ts7
-rw-r--r--src/server/api/endpoints/aggregation/users/following.ts7
-rw-r--r--src/server/api/endpoints/aggregation/users/post.ts7
-rw-r--r--src/server/api/endpoints/aggregation/users/reaction.ts4
-rw-r--r--src/server/api/endpoints/app/create.ts10
-rw-r--r--src/server/api/endpoints/app/name_id/available.ts2
-rw-r--r--src/server/api/endpoints/app/show.ts6
-rw-r--r--src/server/api/endpoints/auth/accept.ts2
-rw-r--r--src/server/api/endpoints/auth/session/generate.ts2
-rw-r--r--src/server/api/endpoints/auth/session/show.ts2
-rw-r--r--src/server/api/endpoints/auth/session/userkey.ts4
-rw-r--r--src/server/api/endpoints/channels.ts8
-rw-r--r--src/server/api/endpoints/channels/create.ts6
-rw-r--r--src/server/api/endpoints/channels/notes.ts14
-rw-r--r--src/server/api/endpoints/channels/show.ts8
-rw-r--r--src/server/api/endpoints/channels/unwatch.ts8
-rw-r--r--src/server/api/endpoints/channels/watch.ts8
-rw-r--r--src/server/api/endpoints/drive/files.ts17
-rw-r--r--src/server/api/endpoints/drive/files/create.ts9
-rw-r--r--src/server/api/endpoints/drive/files/find.ts10
-rw-r--r--src/server/api/endpoints/drive/files/show.ts8
-rw-r--r--src/server/api/endpoints/drive/files/update.ts12
-rw-r--r--src/server/api/endpoints/drive/files/upload_from_url.ts6
-rw-r--r--src/server/api/endpoints/drive/folders.ts15
-rw-r--r--src/server/api/endpoints/drive/folders/create.ts10
-rw-r--r--src/server/api/endpoints/drive/folders/find.ts10
-rw-r--r--src/server/api/endpoints/drive/folders/show.ts8
-rw-r--r--src/server/api/endpoints/drive/folders/update.ts12
-rw-r--r--src/server/api/endpoints/drive/stream.ts14
-rw-r--r--src/server/api/endpoints/following/create.ts4
-rw-r--r--src/server/api/endpoints/following/delete.ts4
-rw-r--r--src/server/api/endpoints/following/stalk.ts35
-rw-r--r--src/server/api/endpoints/following/unstalk.ts35
-rw-r--r--src/server/api/endpoints/i/2fa/done.ts2
-rw-r--r--src/server/api/endpoints/i/2fa/register.ts2
-rw-r--r--src/server/api/endpoints/i/2fa/unregister.ts2
-rw-r--r--src/server/api/endpoints/i/authorized_apps.ts10
-rw-r--r--src/server/api/endpoints/i/change_password.ts8
-rw-r--r--src/server/api/endpoints/i/favorites.ts63
-rw-r--r--src/server/api/endpoints/i/notifications.ts18
-rw-r--r--src/server/api/endpoints/i/pin.ts8
-rw-r--r--src/server/api/endpoints/i/regenerate_token.ts6
-rw-r--r--src/server/api/endpoints/i/signin_history.ts12
-rw-r--r--src/server/api/endpoints/i/update.ts41
-rw-r--r--src/server/api/endpoints/i/update_client_setting.ts27
-rw-r--r--src/server/api/endpoints/i/update_home.ts18
-rw-r--r--src/server/api/endpoints/i/update_mobile_home.ts15
-rw-r--r--src/server/api/endpoints/messaging/history.ts6
-rw-r--r--src/server/api/endpoints/messaging/messages.ts12
-rw-r--r--src/server/api/endpoints/messaging/messages/create.ts15
-rw-r--r--src/server/api/endpoints/messaging/unread.ts4
-rw-r--r--src/server/api/endpoints/meta.ts9
-rw-r--r--src/server/api/endpoints/mute/create.ts8
-rw-r--r--src/server/api/endpoints/mute/delete.ts4
-rw-r--r--src/server/api/endpoints/mute/list.ts16
-rw-r--r--src/server/api/endpoints/my/apps.ts8
-rw-r--r--src/server/api/endpoints/notes.ts18
-rw-r--r--src/server/api/endpoints/notes/context.ts8
-rw-r--r--src/server/api/endpoints/notes/create.ts120
-rw-r--r--src/server/api/endpoints/notes/favorites/create.ts8
-rw-r--r--src/server/api/endpoints/notes/favorites/delete.ts8
-rw-r--r--src/server/api/endpoints/notes/global-timeline.ts12
-rw-r--r--src/server/api/endpoints/notes/local-timeline.ts12
-rw-r--r--src/server/api/endpoints/notes/mentions.ts14
-rw-r--r--src/server/api/endpoints/notes/polls/recommendation.ts8
-rw-r--r--src/server/api/endpoints/notes/polls/vote.ts12
-rw-r--r--src/server/api/endpoints/notes/reactions.ts10
-rw-r--r--src/server/api/endpoints/notes/reactions/create.ts17
-rw-r--r--src/server/api/endpoints/notes/reactions/delete.ts9
-rw-r--r--src/server/api/endpoints/notes/replies.ts10
-rw-r--r--src/server/api/endpoints/notes/reposts.ts10
-rw-r--r--src/server/api/endpoints/notes/search.ts36
-rw-r--r--src/server/api/endpoints/notes/show.ts4
-rw-r--r--src/server/api/endpoints/notes/timeline.ts148
-rw-r--r--src/server/api/endpoints/notes/trend.ts21
-rw-r--r--src/server/api/endpoints/notes/user-list-timeline.ts179
-rw-r--r--src/server/api/endpoints/notifications/get_unread_count.ts4
-rw-r--r--src/server/api/endpoints/notifications/mark_as_read_all.ts4
-rw-r--r--src/server/api/endpoints/othello/games.ts10
-rw-r--r--src/server/api/endpoints/othello/games/show.ts4
-rw-r--r--src/server/api/endpoints/othello/match.ts4
-rw-r--r--src/server/api/endpoints/stats.ts52
-rw-r--r--src/server/api/endpoints/sw/register.ts6
-rw-r--r--src/server/api/endpoints/username/available.ts2
-rw-r--r--src/server/api/endpoints/users.ts10
-rw-r--r--src/server/api/endpoints/users/followers.ts18
-rw-r--r--src/server/api/endpoints/users/following.ts14
-rw-r--r--src/server/api/endpoints/users/get_frequently_replied_users.ts6
-rw-r--r--src/server/api/endpoints/users/lists/create.ts25
-rw-r--r--src/server/api/endpoints/users/lists/list.ts13
-rw-r--r--src/server/api/endpoints/users/lists/push.ts61
-rw-r--r--src/server/api/endpoints/users/lists/show.ts23
-rw-r--r--src/server/api/endpoints/users/notes.ts22
-rw-r--r--src/server/api/endpoints/users/recommendation.ts18
-rw-r--r--src/server/api/endpoints/users/search.ts6
-rw-r--r--src/server/api/endpoints/users/search_by_username.ts10
-rw-r--r--src/server/api/endpoints/users/show.ts66
-rw-r--r--src/server/api/stream/home.ts14
-rw-r--r--src/server/api/stream/user-list.ts14
-rw-r--r--src/server/api/streaming.ts2
-rw-r--r--src/server/file/assets/cache-expired.pngbin0 -> 15025 bytes
-rw-r--r--src/server/file/assets/tombstone.pngbin0 -> 6387 bytes
-rw-r--r--src/server/file/index.ts7
-rw-r--r--src/server/file/pour.ts88
-rw-r--r--src/server/file/send-drive-file.ts60
-rw-r--r--src/server/index.ts19
-rw-r--r--src/server/web/index.ts67
-rw-r--r--src/server/web/url-preview.ts4
-rw-r--r--src/server/web/views/note.pug25
-rw-r--r--src/server/web/views/user.pug20
-rw-r--r--src/server/webfinger.ts38
119 files changed, 1296 insertions, 856 deletions
diff --git a/src/server/activitypub.ts b/src/server/activitypub.ts
index e27e2552f3..3c07a3e2f2 100644
--- a/src/server/activitypub.ts
+++ b/src/server/activitypub.ts
@@ -1,3 +1,5 @@
+import * as mongo from 'mongodb';
+import * as Koa from 'koa';
import * as Router from 'koa-router';
const json = require('koa-json-body');
const httpSignature = require('http-signature');
@@ -18,8 +20,7 @@ const router = new Router();
//#region Routing
-// inbox
-router.post('/users/:user/inbox', json(), ctx => {
+function inbox(ctx: Koa.Context) {
let signature;
ctx.req.headers.authorization = 'Signature ' + ctx.req.headers.signature;
@@ -38,7 +39,11 @@ router.post('/users/:user/inbox', json(), ctx => {
}).save();
ctx.status = 202;
-});
+}
+
+// inbox
+router.post('/inbox', json(), inbox);
+router.post('/users/:user/inbox', json(), inbox);
// note
router.get('/notes/:note', async (ctx, next) => {
@@ -49,7 +54,7 @@ router.get('/notes/:note', async (ctx, next) => {
}
const note = await Note.findOne({
- _id: ctx.params.note
+ _id: new mongo.ObjectID(ctx.params.note)
});
if (note === null) {
@@ -62,7 +67,7 @@ router.get('/notes/:note', async (ctx, next) => {
// outbot
router.get('/users/:user/outbox', async ctx => {
- const userId = ctx.params.user;
+ const userId = new mongo.ObjectID(ctx.params.user);
const user = await User.findOne({ _id: userId });
@@ -84,7 +89,7 @@ router.get('/users/:user/outbox', async ctx => {
// publickey
router.get('/users/:user/publickey', async ctx => {
- const userId = ctx.params.user;
+ const userId = new mongo.ObjectID(ctx.params.user);
const user = await User.findOne({ _id: userId });
@@ -102,7 +107,7 @@ router.get('/users/:user/publickey', async ctx => {
// user
router.get('/users/:user', async ctx => {
- const userId = ctx.params.user;
+ const userId = new mongo.ObjectID(ctx.params.user);
const user = await User.findOne({ _id: userId });
diff --git a/src/server/api/common/get-friends.ts b/src/server/api/common/get-friends.ts
index c1cc3957d8..50ba71ea96 100644
--- a/src/server/api/common/get-friends.ts
+++ b/src/server/api/common/get-friends.ts
@@ -1,10 +1,10 @@
import * as mongodb from 'mongodb';
import Following from '../../../models/following';
-export default async (me: mongodb.ObjectID, includeMe: boolean = true) => {
+export const getFriendIds = async (me: mongodb.ObjectID, includeMe = true) => {
// Fetch relation to other users who the I follows
// SELECT followee
- const myfollowing = await Following
+ const followings = await Following
.find({
followerId: me
}, {
@@ -14,7 +14,7 @@ export default async (me: mongodb.ObjectID, includeMe: boolean = true) => {
});
// ID list of other users who the I follows
- const myfollowingIds = myfollowing.map(follow => follow.followeeId);
+ const myfollowingIds = followings.map(following => following.followeeId);
if (includeMe) {
myfollowingIds.push(me);
@@ -22,3 +22,26 @@ export default async (me: mongodb.ObjectID, includeMe: boolean = true) => {
return myfollowingIds;
};
+
+export const getFriends = async (me: mongodb.ObjectID, includeMe = true) => {
+ // Fetch relation to other users who the I follows
+ const followings = await Following
+ .find({
+ followerId: me
+ });
+
+ // ID list of other users who the I follows
+ const myfollowings = followings.map(following => ({
+ id: following.followeeId,
+ stalk: following.stalk
+ }));
+
+ if (includeMe) {
+ myfollowings.push({
+ id: me,
+ stalk: true
+ });
+ }
+
+ return myfollowings;
+};
diff --git a/src/server/api/common/read-messaging-message.ts b/src/server/api/common/read-messaging-message.ts
index c52f9363b5..28854e186e 100644
--- a/src/server/api/common/read-messaging-message.ts
+++ b/src/server/api/common/read-messaging-message.ts
@@ -57,6 +57,8 @@ export default (
.count({
recipientId: userId,
isRead: false
+ }, {
+ limit: 1
});
if (count == 0) {
diff --git a/src/server/api/common/read-notification.ts b/src/server/api/common/read-notification.ts
index 9bd41519fb..7b9faf4cf4 100644
--- a/src/server/api/common/read-notification.ts
+++ b/src/server/api/common/read-notification.ts
@@ -43,6 +43,8 @@ export default (
.count({
notifieeId: userId,
isRead: false
+ }, {
+ limit: 1
});
if (count == 0) {
diff --git a/src/server/api/endpoints.ts b/src/server/api/endpoints.ts
index e0223c23e0..734b8273f1 100644
--- a/src/server/api/endpoints.ts
+++ b/src/server/api/endpoints.ts
@@ -234,6 +234,12 @@ const endpoints: Endpoint[] = [
},
{
+ name: 'i/favorites',
+ withCredential: true,
+ kind: 'favorites-read'
+ },
+
+ {
name: 'othello/match',
withCredential: true
},
@@ -409,6 +415,27 @@ const endpoints: Endpoint[] = [
},
{
+ name: 'users/lists/show',
+ withCredential: true,
+ kind: 'account-read'
+ },
+ {
+ name: 'users/lists/create',
+ withCredential: true,
+ kind: 'account-write'
+ },
+ {
+ name: 'users/lists/push',
+ withCredential: true,
+ kind: 'account-write'
+ },
+ {
+ name: 'users/lists/list',
+ withCredential: true,
+ kind: 'account-read'
+ },
+
+ {
name: 'following/create',
withCredential: true,
limit: {
@@ -426,6 +453,24 @@ const endpoints: Endpoint[] = [
},
kind: 'following-write'
},
+ {
+ name: 'following/stalk',
+ withCredential: true,
+ limit: {
+ duration: ms('1hour'),
+ max: 100
+ },
+ kind: 'following-write'
+ },
+ {
+ name: 'following/unstalk',
+ withCredential: true,
+ limit: {
+ duration: ms('1hour'),
+ max: 100
+ },
+ kind: 'following-write'
+ },
{
name: 'notes'
@@ -480,6 +525,14 @@ const endpoints: Endpoint[] = [
}
},
{
+ name: 'notes/user-list-timeline',
+ withCredential: true,
+ limit: {
+ duration: ms('10minutes'),
+ max: 100
+ }
+ },
+ {
name: 'notes/mentions',
withCredential: true,
limit: {
diff --git a/src/server/api/endpoints/aggregation/posts.ts b/src/server/api/endpoints/aggregation/posts.ts
index cc2a48b53d..d348cadae9 100644
--- a/src/server/api/endpoints/aggregation/posts.ts
+++ b/src/server/api/endpoints/aggregation/posts.ts
@@ -6,13 +6,10 @@ import Note from '../../../../models/note';
/**
* Aggregate notes
- *
- * @param {any} params
- * @return {Promise<any>}
*/
module.exports = params => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 365, limitErr] = $(params.limit).optional.number().range(1, 365).$;
+ const [limit = 365, limitErr] = $.num.optional().range(1, 365).get(params.limit);
if (limitErr) return rej('invalid limit param');
const datas = await Note
diff --git a/src/server/api/endpoints/aggregation/users.ts b/src/server/api/endpoints/aggregation/users.ts
index 19776ed297..b116c1454b 100644
--- a/src/server/api/endpoints/aggregation/users.ts
+++ b/src/server/api/endpoints/aggregation/users.ts
@@ -6,13 +6,10 @@ import User from '../../../../models/user';
/**
* Aggregate users
- *
- * @param {any} params
- * @return {Promise<any>}
*/
module.exports = params => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 365, limitErr] = $(params.limit).optional.number().range(1, 365).$;
+ const [limit = 365, limitErr] = $.num.optional().range(1, 365).get(params.limit);
if (limitErr) return rej('invalid limit param');
const users = await User
diff --git a/src/server/api/endpoints/aggregation/users/activity.ts b/src/server/api/endpoints/aggregation/users/activity.ts
index 318cce77a5..9109487ac6 100644
--- a/src/server/api/endpoints/aggregation/users/activity.ts
+++ b/src/server/api/endpoints/aggregation/users/activity.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import User from '../../../../../models/user';
import Note from '../../../../../models/note';
@@ -9,17 +9,14 @@ import Note from '../../../../../models/note';
/**
* Aggregate activity of a user
- *
- * @param {any} params
- * @return {Promise<any>}
*/
module.exports = (params) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 365, limitErr] = $(params.limit).optional.number().range(1, 365).$;
+ const [limit = 365, limitErr] = $.num.optional().range(1, 365).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Lookup user
diff --git a/src/server/api/endpoints/aggregation/users/followers.ts b/src/server/api/endpoints/aggregation/users/followers.ts
index 7ccb2a3066..dfcaf8462f 100644
--- a/src/server/api/endpoints/aggregation/users/followers.ts
+++ b/src/server/api/endpoints/aggregation/users/followers.ts
@@ -1,19 +1,16 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import User from '../../../../../models/user';
import FollowedLog from '../../../../../models/followed-log';
/**
* Aggregate followers of a user
- *
- * @param {any} params
- * @return {Promise<any>}
*/
module.exports = (params) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Lookup user
diff --git a/src/server/api/endpoints/aggregation/users/following.ts b/src/server/api/endpoints/aggregation/users/following.ts
index 45e246495b..5f826fd71c 100644
--- a/src/server/api/endpoints/aggregation/users/following.ts
+++ b/src/server/api/endpoints/aggregation/users/following.ts
@@ -1,19 +1,16 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import User from '../../../../../models/user';
import FollowingLog from '../../../../../models/following-log';
/**
* Aggregate following of a user
- *
- * @param {any} params
- * @return {Promise<any>}
*/
module.exports = (params) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Lookup user
diff --git a/src/server/api/endpoints/aggregation/users/post.ts b/src/server/api/endpoints/aggregation/users/post.ts
index e6170d83e2..11f9ef14cd 100644
--- a/src/server/api/endpoints/aggregation/users/post.ts
+++ b/src/server/api/endpoints/aggregation/users/post.ts
@@ -1,19 +1,16 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import User from '../../../../../models/user';
import Note from '../../../../../models/note';
/**
* Aggregate note of a user
- *
- * @param {any} params
- * @return {Promise<any>}
*/
module.exports = (params) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Lookup user
diff --git a/src/server/api/endpoints/aggregation/users/reaction.ts b/src/server/api/endpoints/aggregation/users/reaction.ts
index 881c7ea693..2de2840258 100644
--- a/src/server/api/endpoints/aggregation/users/reaction.ts
+++ b/src/server/api/endpoints/aggregation/users/reaction.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import User from '../../../../../models/user';
import Reaction from '../../../../../models/note-reaction';
@@ -13,7 +13,7 @@ import Reaction from '../../../../../models/note-reaction';
*/
module.exports = (params) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Lookup user
diff --git a/src/server/api/endpoints/app/create.ts b/src/server/api/endpoints/app/create.ts
index 4a55d33f2d..553bd2381a 100644
--- a/src/server/api/endpoints/app/create.ts
+++ b/src/server/api/endpoints/app/create.ts
@@ -67,24 +67,24 @@ import App, { isValidNameId, pack } from '../../../../models/app';
*/
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'nameId' parameter
- const [nameId, nameIdErr] = $(params.nameId).string().pipe(isValidNameId).$;
+ const [nameId, nameIdErr] = $.str.pipe(isValidNameId).get(params.nameId);
if (nameIdErr) return rej('invalid nameId param');
// Get 'name' parameter
- const [name, nameErr] = $(params.name).string().$;
+ const [name, nameErr] = $.str.get(params.name);
if (nameErr) return rej('invalid name param');
// Get 'description' parameter
- const [description, descriptionErr] = $(params.description).string().$;
+ const [description, descriptionErr] = $.str.get(params.description);
if (descriptionErr) return rej('invalid description param');
// Get 'permission' parameter
- const [permission, permissionErr] = $(params.permission).array('string').unique().$;
+ const [permission, permissionErr] = $.arr($.str).unique().get(params.permission);
if (permissionErr) return rej('invalid permission param');
// Get 'callbackUrl' parameter
// TODO: Check it is valid url
- const [callbackUrl = null, callbackUrlErr] = $(params.callbackUrl).optional.nullable.string().$;
+ const [callbackUrl = null, callbackUrlErr] = $.str.optional().nullable().get(params.callbackUrl);
if (callbackUrlErr) return rej('invalid callbackUrl param');
// Generate secret
diff --git a/src/server/api/endpoints/app/name_id/available.ts b/src/server/api/endpoints/app/name_id/available.ts
index ec2d692412..135bb7d2b4 100644
--- a/src/server/api/endpoints/app/name_id/available.ts
+++ b/src/server/api/endpoints/app/name_id/available.ts
@@ -42,7 +42,7 @@ import { isValidNameId } from '../../../../../models/app';
*/
module.exports = async (params) => new Promise(async (res, rej) => {
// Get 'nameId' parameter
- const [nameId, nameIdErr] = $(params.nameId).string().pipe(isValidNameId).$;
+ const [nameId, nameIdErr] = $.str.pipe(isValidNameId).get(params.nameId);
if (nameIdErr) return rej('invalid nameId param');
// Get exist
diff --git a/src/server/api/endpoints/app/show.ts b/src/server/api/endpoints/app/show.ts
index 99a2093b68..8d742ab182 100644
--- a/src/server/api/endpoints/app/show.ts
+++ b/src/server/api/endpoints/app/show.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import App, { pack } from '../../../../models/app';
/**
@@ -41,11 +41,11 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => {
const isSecure = user != null && app == null;
// Get 'appId' parameter
- const [appId, appIdErr] = $(params.appId).optional.id().$;
+ const [appId, appIdErr] = $.type(ID).optional().get(params.appId);
if (appIdErr) return rej('invalid appId param');
// Get 'nameId' parameter
- const [nameId, nameIdErr] = $(params.nameId).optional.string().$;
+ const [nameId, nameIdErr] = $.str.optional().get(params.nameId);
if (nameIdErr) return rej('invalid nameId param');
if (appId === undefined && nameId === undefined) {
diff --git a/src/server/api/endpoints/auth/accept.ts b/src/server/api/endpoints/auth/accept.ts
index b6297d663d..695fbb0803 100644
--- a/src/server/api/endpoints/auth/accept.ts
+++ b/src/server/api/endpoints/auth/accept.ts
@@ -40,7 +40,7 @@ import AccessToken from '../../../../models/access-token';
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'token' parameter
- const [token, tokenErr] = $(params.token).string().$;
+ const [token, tokenErr] = $.str.get(params.token);
if (tokenErr) return rej('invalid token param');
// Fetch token
diff --git a/src/server/api/endpoints/auth/session/generate.ts b/src/server/api/endpoints/auth/session/generate.ts
index 7c475dbe26..d649a8d902 100644
--- a/src/server/api/endpoints/auth/session/generate.ts
+++ b/src/server/api/endpoints/auth/session/generate.ts
@@ -46,7 +46,7 @@ import config from '../../../../../config';
*/
module.exports = (params) => new Promise(async (res, rej) => {
// Get 'appSecret' parameter
- const [appSecret, appSecretErr] = $(params.appSecret).string().$;
+ const [appSecret, appSecretErr] = $.str.get(params.appSecret);
if (appSecretErr) return rej('invalid appSecret param');
// Lookup app
diff --git a/src/server/api/endpoints/auth/session/show.ts b/src/server/api/endpoints/auth/session/show.ts
index f7f0b087b7..434cc264a0 100644
--- a/src/server/api/endpoints/auth/session/show.ts
+++ b/src/server/api/endpoints/auth/session/show.ts
@@ -53,7 +53,7 @@ import AuthSess, { pack } from '../../../../../models/auth-session';
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'token' parameter
- const [token, tokenErr] = $(params.token).string().$;
+ const [token, tokenErr] = $.str.get(params.token);
if (tokenErr) return rej('invalid token param');
// Lookup session
diff --git a/src/server/api/endpoints/auth/session/userkey.ts b/src/server/api/endpoints/auth/session/userkey.ts
index ddb67cb451..3026b477f1 100644
--- a/src/server/api/endpoints/auth/session/userkey.ts
+++ b/src/server/api/endpoints/auth/session/userkey.ts
@@ -51,7 +51,7 @@ import { pack } from '../../../../../models/user';
*/
module.exports = (params) => new Promise(async (res, rej) => {
// Get 'appSecret' parameter
- const [appSecret, appSecretErr] = $(params.appSecret).string().$;
+ const [appSecret, appSecretErr] = $.str.get(params.appSecret);
if (appSecretErr) return rej('invalid appSecret param');
// Lookup app
@@ -64,7 +64,7 @@ module.exports = (params) => new Promise(async (res, rej) => {
}
// Get 'token' parameter
- const [token, tokenErr] = $(params.token).string().$;
+ const [token, tokenErr] = $.str.get(params.token);
if (tokenErr) return rej('invalid token param');
// Fetch token
diff --git a/src/server/api/endpoints/channels.ts b/src/server/api/endpoints/channels.ts
index 582e6ba43b..ceef4b9cb9 100644
--- a/src/server/api/endpoints/channels.ts
+++ b/src/server/api/endpoints/channels.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../cafy-id';
import Channel, { pack } from '../../../models/channel';
/**
@@ -13,15 +13,15 @@ import Channel, { pack } from '../../../models/channel';
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
diff --git a/src/server/api/endpoints/channels/create.ts b/src/server/api/endpoints/channels/create.ts
index 0f0f558c8a..0e3c9dc5ac 100644
--- a/src/server/api/endpoints/channels/create.ts
+++ b/src/server/api/endpoints/channels/create.ts
@@ -8,14 +8,10 @@ import { pack } from '../../../../models/channel';
/**
* Create a channel
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'title' parameter
- const [title, titleErr] = $(params.title).string().range(1, 100).$;
+ const [title, titleErr] = $.str.range(1, 100).get(params.title);
if (titleErr) return rej('invalid title param');
// Create a channel
diff --git a/src/server/api/endpoints/channels/notes.ts b/src/server/api/endpoints/channels/notes.ts
index d636aa0d10..463152e74a 100644
--- a/src/server/api/endpoints/channels/notes.ts
+++ b/src/server/api/endpoints/channels/notes.ts
@@ -1,28 +1,24 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import { default as Channel, IChannel } from '../../../../models/channel';
import Note, { pack } from '../../../../models/note';
/**
* Show a notes of a channel
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 1000, limitErr] = $(params.limit).optional.number().range(1, 1000).$;
+ const [limit = 1000, limitErr] = $.num.optional().range(1, 1000).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
@@ -31,7 +27,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
}
// Get 'channelId' parameter
- const [channelId, channelIdErr] = $(params.channelId).id().$;
+ const [channelId, channelIdErr] = $.type(ID).get(params.channelId);
if (channelIdErr) return rej('invalid channelId param');
// Fetch channel
diff --git a/src/server/api/endpoints/channels/show.ts b/src/server/api/endpoints/channels/show.ts
index 3ce9ce4745..1bba63d490 100644
--- a/src/server/api/endpoints/channels/show.ts
+++ b/src/server/api/endpoints/channels/show.ts
@@ -1,19 +1,15 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Channel, { IChannel, pack } from '../../../../models/channel';
/**
* Show a channel
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'channelId' parameter
- const [channelId, channelIdErr] = $(params.channelId).id().$;
+ const [channelId, channelIdErr] = $.type(ID).get(params.channelId);
if (channelIdErr) return rej('invalid channelId param');
// Fetch channel
diff --git a/src/server/api/endpoints/channels/unwatch.ts b/src/server/api/endpoints/channels/unwatch.ts
index 8220b90b68..f7dddff461 100644
--- a/src/server/api/endpoints/channels/unwatch.ts
+++ b/src/server/api/endpoints/channels/unwatch.ts
@@ -1,20 +1,16 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Channel from '../../../../models/channel';
import Watching from '../../../../models/channel-watching';
/**
* Unwatch a channel
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'channelId' parameter
- const [channelId, channelIdErr] = $(params.channelId).id().$;
+ const [channelId, channelIdErr] = $.type(ID).get(params.channelId);
if (channelIdErr) return rej('invalid channelId param');
//#region Fetch channel
diff --git a/src/server/api/endpoints/channels/watch.ts b/src/server/api/endpoints/channels/watch.ts
index 6906282a54..34243ff68b 100644
--- a/src/server/api/endpoints/channels/watch.ts
+++ b/src/server/api/endpoints/channels/watch.ts
@@ -1,20 +1,16 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Channel from '../../../../models/channel';
import Watching from '../../../../models/channel-watching';
/**
* Watch a channel
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'channelId' parameter
- const [channelId, channelIdErr] = $(params.channelId).id().$;
+ const [channelId, channelIdErr] = $.type(ID).get(params.channelId);
if (channelIdErr) return rej('invalid channelId param');
//#region Fetch channel
diff --git a/src/server/api/endpoints/drive/files.ts b/src/server/api/endpoints/drive/files.ts
index 63d69d145a..ab4b18cef4 100644
--- a/src/server/api/endpoints/drive/files.ts
+++ b/src/server/api/endpoints/drive/files.ts
@@ -1,28 +1,23 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import DriveFile, { pack } from '../../../../models/drive-file';
/**
* Get drive files
- *
- * @param {any} params
- * @param {any} user
- * @param {any} app
- * @return {Promise<any>}
*/
module.exports = async (params, user, app) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) throw 'invalid limit param';
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) throw 'invalid sinceId param';
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) throw 'invalid untilId param';
// Check if both of sinceId and untilId is specified
@@ -31,11 +26,11 @@ module.exports = async (params, user, app) => {
}
// Get 'folderId' parameter
- const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
+ const [folderId = null, folderIdErr] = $.type(ID).optional().nullable().get(params.folderId);
if (folderIdErr) throw 'invalid folderId param';
// Get 'type' parameter
- const [type, typeErr] = $(params.type).optional.string().match(/^[a-zA-Z\/\-\*]+$/).$;
+ const [type, typeErr] = $.str.optional().match(/^[a-zA-Z\/\-\*]+$/).get(params.type);
if (typeErr) throw 'invalid type param';
// Construct query
diff --git a/src/server/api/endpoints/drive/files/create.ts b/src/server/api/endpoints/drive/files/create.ts
index df0bd0a0d3..e9348e4e2f 100644
--- a/src/server/api/endpoints/drive/files/create.ts
+++ b/src/server/api/endpoints/drive/files/create.ts
@@ -1,17 +1,12 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import { validateFileName, pack } from '../../../../../models/drive-file';
import create from '../../../../../services/drive/add-file';
/**
* Create a file
- *
- * @param {any} file
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = async (file, params, user): Promise<any> => {
if (file == null) {
@@ -34,7 +29,7 @@ module.exports = async (file, params, user): Promise<any> => {
}
// Get 'folderId' parameter
- const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
+ const [folderId = null, folderIdErr] = $.type(ID).optional().nullable().get(params.folderId);
if (folderIdErr) throw 'invalid folderId param';
try {
diff --git a/src/server/api/endpoints/drive/files/find.ts b/src/server/api/endpoints/drive/files/find.ts
index 0ab6e5d3e3..98165990fe 100644
--- a/src/server/api/endpoints/drive/files/find.ts
+++ b/src/server/api/endpoints/drive/files/find.ts
@@ -1,23 +1,19 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import DriveFile, { pack } from '../../../../../models/drive-file';
/**
* Find a file(s)
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'name' parameter
- const [name, nameErr] = $(params.name).string().$;
+ const [name, nameErr] = $.str.get(params.name);
if (nameErr) return rej('invalid name param');
// Get 'folderId' parameter
- const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
+ const [folderId = null, folderIdErr] = $.type(ID).optional().nullable().get(params.folderId);
if (folderIdErr) return rej('invalid folderId param');
// Issue query
diff --git a/src/server/api/endpoints/drive/files/show.ts b/src/server/api/endpoints/drive/files/show.ts
index 3398f24541..c7efda7ab0 100644
--- a/src/server/api/endpoints/drive/files/show.ts
+++ b/src/server/api/endpoints/drive/files/show.ts
@@ -1,19 +1,15 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import DriveFile, { pack } from '../../../../../models/drive-file';
/**
* Show a file
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = async (params, user) => {
// Get 'fileId' parameter
- const [fileId, fileIdErr] = $(params.fileId).id().$;
+ const [fileId, fileIdErr] = $.type(ID).get(params.fileId);
if (fileIdErr) throw 'invalid fileId param';
// Fetch file
diff --git a/src/server/api/endpoints/drive/files/update.ts b/src/server/api/endpoints/drive/files/update.ts
index c783ad8b3b..12fa8e025d 100644
--- a/src/server/api/endpoints/drive/files/update.ts
+++ b/src/server/api/endpoints/drive/files/update.ts
@@ -1,21 +1,17 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import DriveFolder from '../../../../../models/drive-folder';
import DriveFile, { validateFileName, pack } from '../../../../../models/drive-file';
import { publishDriveStream } from '../../../../../publishers/stream';
/**
* Update a file
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'fileId' parameter
- const [fileId, fileIdErr] = $(params.fileId).id().$;
+ const [fileId, fileIdErr] = $.type(ID).get(params.fileId);
if (fileIdErr) return rej('invalid fileId param');
// Fetch file
@@ -30,12 +26,12 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
}
// Get 'name' parameter
- const [name, nameErr] = $(params.name).optional.string().pipe(validateFileName).$;
+ const [name, nameErr] = $.str.optional().pipe(validateFileName).get(params.name);
if (nameErr) return rej('invalid name param');
if (name) file.filename = name;
// Get 'folderId' parameter
- const [folderId, folderIdErr] = $(params.folderId).optional.nullable.id().$;
+ const [folderId, folderIdErr] = $.type(ID).optional().nullable().get(params.folderId);
if (folderIdErr) return rej('invalid folderId param');
if (folderId !== undefined) {
diff --git a/src/server/api/endpoints/drive/files/upload_from_url.ts b/src/server/api/endpoints/drive/files/upload_from_url.ts
index 8a426c0efc..c012f0d3c9 100644
--- a/src/server/api/endpoints/drive/files/upload_from_url.ts
+++ b/src/server/api/endpoints/drive/files/upload_from_url.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import { pack } from '../../../../../models/drive-file';
import uploadFromUrl from '../../../../../services/drive/upload-from-url';
@@ -11,11 +11,11 @@ import uploadFromUrl from '../../../../../services/drive/upload-from-url';
module.exports = async (params, user): Promise<any> => {
// Get 'url' parameter
// TODO: Validate this url
- const [url, urlErr] = $(params.url).string().$;
+ const [url, urlErr] = $.str.get(params.url);
if (urlErr) throw 'invalid url param';
// Get 'folderId' parameter
- const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
+ const [folderId = null, folderIdErr] = $.type(ID).optional().nullable().get(params.folderId);
if (folderIdErr) throw 'invalid folderId param';
return pack(await uploadFromUrl(url, user, folderId));
diff --git a/src/server/api/endpoints/drive/folders.ts b/src/server/api/endpoints/drive/folders.ts
index 489e47912e..bc6c50eb99 100644
--- a/src/server/api/endpoints/drive/folders.ts
+++ b/src/server/api/endpoints/drive/folders.ts
@@ -1,28 +1,23 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import DriveFolder, { pack } from '../../../../models/drive-folder';
/**
* Get drive folders
- *
- * @param {any} params
- * @param {any} user
- * @param {any} app
- * @return {Promise<any>}
*/
module.exports = (params, user, app) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
@@ -31,7 +26,7 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => {
}
// Get 'folderId' parameter
- const [folderId = null, folderIdErr] = $(params.folderId).optional.nullable.id().$;
+ const [folderId = null, folderIdErr] = $.type(ID).optional().nullable().get(params.folderId);
if (folderIdErr) return rej('invalid folderId param');
// Construct query
diff --git a/src/server/api/endpoints/drive/folders/create.ts b/src/server/api/endpoints/drive/folders/create.ts
index f34d0019d7..62e3b6f6e8 100644
--- a/src/server/api/endpoints/drive/folders/create.ts
+++ b/src/server/api/endpoints/drive/folders/create.ts
@@ -1,24 +1,20 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import DriveFolder, { isValidFolderName, pack } from '../../../../../models/drive-folder';
import { publishDriveStream } from '../../../../../publishers/stream';
/**
* Create drive folder
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'name' parameter
- const [name = '無題のフォルダー', nameErr] = $(params.name).optional.string().pipe(isValidFolderName).$;
+ const [name = '無題のフォルダー', nameErr] = $.str.optional().pipe(isValidFolderName).get(params.name);
if (nameErr) return rej('invalid name param');
// Get 'parentId' parameter
- const [parentId = null, parentIdErr] = $(params.parentId).optional.nullable.id().$;
+ const [parentId = null, parentIdErr] = $.type(ID).optional().nullable().get(params.parentId);
if (parentIdErr) return rej('invalid parentId param');
// If the parent folder is specified
diff --git a/src/server/api/endpoints/drive/folders/find.ts b/src/server/api/endpoints/drive/folders/find.ts
index 04dc38f87f..9703d9e99d 100644
--- a/src/server/api/endpoints/drive/folders/find.ts
+++ b/src/server/api/endpoints/drive/folders/find.ts
@@ -1,23 +1,19 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import DriveFolder, { pack } from '../../../../../models/drive-folder';
/**
* Find a folder(s)
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'name' parameter
- const [name, nameErr] = $(params.name).string().$;
+ const [name, nameErr] = $.str.get(params.name);
if (nameErr) return rej('invalid name param');
// Get 'parentId' parameter
- const [parentId = null, parentIdErr] = $(params.parentId).optional.nullable.id().$;
+ const [parentId = null, parentIdErr] = $.type(ID).optional().nullable().get(params.parentId);
if (parentIdErr) return rej('invalid parentId param');
// Issue query
diff --git a/src/server/api/endpoints/drive/folders/show.ts b/src/server/api/endpoints/drive/folders/show.ts
index b432f5a50a..44f1889001 100644
--- a/src/server/api/endpoints/drive/folders/show.ts
+++ b/src/server/api/endpoints/drive/folders/show.ts
@@ -1,19 +1,15 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import DriveFolder, { pack } from '../../../../../models/drive-folder';
/**
* Show a folder
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'folderId' parameter
- const [folderId, folderIdErr] = $(params.folderId).id().$;
+ const [folderId, folderIdErr] = $.type(ID).get(params.folderId);
if (folderIdErr) return rej('invalid folderId param');
// Get folder
diff --git a/src/server/api/endpoints/drive/folders/update.ts b/src/server/api/endpoints/drive/folders/update.ts
index dd7e8f5c86..e24d8a14cd 100644
--- a/src/server/api/endpoints/drive/folders/update.ts
+++ b/src/server/api/endpoints/drive/folders/update.ts
@@ -1,20 +1,16 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import DriveFolder, { isValidFolderName, pack } from '../../../../../models/drive-folder';
import { publishDriveStream } from '../../../../../publishers/stream';
/**
* Update a folder
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'folderId' parameter
- const [folderId, folderIdErr] = $(params.folderId).id().$;
+ const [folderId, folderIdErr] = $.type(ID).get(params.folderId);
if (folderIdErr) return rej('invalid folderId param');
// Fetch folder
@@ -29,12 +25,12 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
}
// Get 'name' parameter
- const [name, nameErr] = $(params.name).optional.string().pipe(isValidFolderName).$;
+ const [name, nameErr] = $.str.optional().pipe(isValidFolderName).get(params.name);
if (nameErr) return rej('invalid name param');
if (name) folder.name = name;
// Get 'parentId' parameter
- const [parentId, parentIdErr] = $(params.parentId).optional.nullable.id().$;
+ const [parentId, parentIdErr] = $.type(ID).optional().nullable().get(params.parentId);
if (parentIdErr) return rej('invalid parentId param');
if (parentId !== undefined) {
if (parentId === null) {
diff --git a/src/server/api/endpoints/drive/stream.ts b/src/server/api/endpoints/drive/stream.ts
index 02313aa37b..8cb3a99b42 100644
--- a/src/server/api/endpoints/drive/stream.ts
+++ b/src/server/api/endpoints/drive/stream.ts
@@ -1,27 +1,23 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import DriveFile, { pack } from '../../../../models/drive-file';
/**
* Get drive stream
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
@@ -30,7 +26,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
}
// Get 'type' parameter
- const [type, typeErr] = $(params.type).optional.string().match(/^[a-zA-Z\/\-\*]+$/).$;
+ const [type, typeErr] = $.str.optional().match(/^[a-zA-Z\/\-\*]+$/).get(params.type);
if (typeErr) return rej('invalid type param');
// Construct query
diff --git a/src/server/api/endpoints/following/create.ts b/src/server/api/endpoints/following/create.ts
index 27e5eb31db..766a8c03d0 100644
--- a/src/server/api/endpoints/following/create.ts
+++ b/src/server/api/endpoints/following/create.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import User from '../../../../models/user';
import Following from '../../../../models/following';
import create from '../../../../services/following/create';
@@ -13,7 +13,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
const follower = user;
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// 自分自身
diff --git a/src/server/api/endpoints/following/delete.ts b/src/server/api/endpoints/following/delete.ts
index ca0703ca22..396b19a6f6 100644
--- a/src/server/api/endpoints/following/delete.ts
+++ b/src/server/api/endpoints/following/delete.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import User from '../../../../models/user';
import Following from '../../../../models/following';
import deleteFollowing from '../../../../services/following/delete';
@@ -13,7 +13,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
const follower = user;
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Check if the followee is yourself
diff --git a/src/server/api/endpoints/following/stalk.ts b/src/server/api/endpoints/following/stalk.ts
new file mode 100644
index 0000000000..f0bc8cbdfc
--- /dev/null
+++ b/src/server/api/endpoints/following/stalk.ts
@@ -0,0 +1,35 @@
+import $ from 'cafy'; import ID from '../../../../cafy-id';
+import Following from '../../../../models/following';
+
+/**
+ * Stalk a user
+ */
+module.exports = (params, user) => new Promise(async (res, rej) => {
+ const follower = user;
+
+ // Get 'userId' parameter
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
+ if (userIdErr) return rej('invalid userId param');
+
+ // Fetch following
+ const following = await Following.findOne({
+ followerId: follower._id,
+ followeeId: userId
+ });
+
+ if (following === null) {
+ return rej('following not found');
+ }
+
+ // Stalk
+ await Following.update({ _id: following._id }, {
+ $set: {
+ stalk: true
+ }
+ });
+
+ // Send response
+ res();
+
+ // TODO: イベント
+});
diff --git a/src/server/api/endpoints/following/unstalk.ts b/src/server/api/endpoints/following/unstalk.ts
new file mode 100644
index 0000000000..0d0a018c34
--- /dev/null
+++ b/src/server/api/endpoints/following/unstalk.ts
@@ -0,0 +1,35 @@
+import $ from 'cafy'; import ID from '../../../../cafy-id';
+import Following from '../../../../models/following';
+
+/**
+ * Unstalk a user
+ */
+module.exports = (params, user) => new Promise(async (res, rej) => {
+ const follower = user;
+
+ // Get 'userId' parameter
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
+ if (userIdErr) return rej('invalid userId param');
+
+ // Fetch following
+ const following = await Following.findOne({
+ followerId: follower._id,
+ followeeId: userId
+ });
+
+ if (following === null) {
+ return rej('following not found');
+ }
+
+ // Stalk
+ await Following.update({ _id: following._id }, {
+ $set: {
+ stalk: false
+ }
+ });
+
+ // Send response
+ res();
+
+ // TODO: イベント
+});
diff --git a/src/server/api/endpoints/i/2fa/done.ts b/src/server/api/endpoints/i/2fa/done.ts
index 3e824feffd..1a2706aa84 100644
--- a/src/server/api/endpoints/i/2fa/done.ts
+++ b/src/server/api/endpoints/i/2fa/done.ts
@@ -7,7 +7,7 @@ import User from '../../../../../models/user';
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'token' parameter
- const [token, tokenErr] = $(params.token).string().$;
+ const [token, tokenErr] = $.str.get(params.token);
if (tokenErr) return rej('invalid token param');
const _token = token.replace(/\s/g, '');
diff --git a/src/server/api/endpoints/i/2fa/register.ts b/src/server/api/endpoints/i/2fa/register.ts
index bed64a2545..d314e1a280 100644
--- a/src/server/api/endpoints/i/2fa/register.ts
+++ b/src/server/api/endpoints/i/2fa/register.ts
@@ -10,7 +10,7 @@ import config from '../../../../../config';
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'password' parameter
- const [password, passwordErr] = $(params.password).string().$;
+ const [password, passwordErr] = $.str.get(params.password);
if (passwordErr) return rej('invalid password param');
// Compare password
diff --git a/src/server/api/endpoints/i/2fa/unregister.ts b/src/server/api/endpoints/i/2fa/unregister.ts
index f9d7a25f53..336a3564ab 100644
--- a/src/server/api/endpoints/i/2fa/unregister.ts
+++ b/src/server/api/endpoints/i/2fa/unregister.ts
@@ -7,7 +7,7 @@ import User from '../../../../../models/user';
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'password' parameter
- const [password, passwordErr] = $(params.password).string().$;
+ const [password, passwordErr] = $.str.get(params.password);
if (passwordErr) return rej('invalid password param');
// Compare password
diff --git a/src/server/api/endpoints/i/authorized_apps.ts b/src/server/api/endpoints/i/authorized_apps.ts
index 82fd2d2516..d15bd67bf2 100644
--- a/src/server/api/endpoints/i/authorized_apps.ts
+++ b/src/server/api/endpoints/i/authorized_apps.ts
@@ -7,22 +7,18 @@ import { pack } from '../../../../models/app';
/**
* Get authorized apps of my account
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Get 'sort' parameter
- const [sort = 'desc', sortError] = $(params.sort).optional.string().or('desc asc').$;
+ const [sort = 'desc', sortError] = $.str.optional().or('desc asc').get(params.sort);
if (sortError) return rej('invalid sort param');
// Get tokens
diff --git a/src/server/api/endpoints/i/change_password.ts b/src/server/api/endpoints/i/change_password.ts
index 57415083f1..a1a1a43406 100644
--- a/src/server/api/endpoints/i/change_password.ts
+++ b/src/server/api/endpoints/i/change_password.ts
@@ -7,18 +7,14 @@ import User from '../../../../models/user';
/**
* Change password
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'currentPasword' parameter
- const [currentPassword, currentPasswordErr] = $(params.currentPasword).string().$;
+ const [currentPassword, currentPasswordErr] = $.str.get(params.currentPasword);
if (currentPasswordErr) return rej('invalid currentPasword param');
// Get 'newPassword' parameter
- const [newPassword, newPasswordErr] = $(params.newPassword).string().$;
+ const [newPassword, newPasswordErr] = $.str.get(params.newPassword);
if (newPasswordErr) return rej('invalid newPassword param');
// Compare password
diff --git a/src/server/api/endpoints/i/favorites.ts b/src/server/api/endpoints/i/favorites.ts
index b40f2b3887..23517baaff 100644
--- a/src/server/api/endpoints/i/favorites.ts
+++ b/src/server/api/endpoints/i/favorites.ts
@@ -1,44 +1,53 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
-import Favorite from '../../../../models/favorite';
-import { pack } from '../../../../models/note';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
+import Favorite, { pack } from '../../../../models/favorite';
/**
- * Get followers of a user
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
+ * Get favorited notes
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
- // Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
- if (offsetErr) return rej('invalid offset param');
+ // Get 'sinceId' parameter
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
+ if (sinceIdErr) return rej('invalid sinceId param');
- // Get 'sort' parameter
- const [sort = 'desc', sortError] = $(params.sort).optional.string().or('desc asc').$;
- if (sortError) return rej('invalid sort param');
+ // Get 'untilId' parameter
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
+ if (untilIdErr) return rej('invalid untilId param');
+
+ // Check if both of sinceId and untilId is specified
+ if (sinceId && untilId) {
+ return rej('cannot set sinceId and untilId');
+ }
+
+ const query = {
+ userId: user._id
+ } as any;
+
+ const sort = {
+ _id: -1
+ };
+
+ if (sinceId) {
+ sort._id = 1;
+ query._id = {
+ $gt: sinceId
+ };
+ } else if (untilId) {
+ query._id = {
+ $lt: untilId
+ };
+ }
// Get favorites
const favorites = await Favorite
- .find({
- userId: user._id
- }, {
- limit: limit,
- skip: offset,
- sort: {
- _id: sort == 'asc' ? 1 : -1
- }
- });
+ .find(query, { limit, sort });
// Serialize
- res(await Promise.all(favorites.map(async favorite =>
- await pack(favorite.noteId)
- )));
+ res(await Promise.all(favorites.map(favorite => pack(favorite, user))));
});
diff --git a/src/server/api/endpoints/i/notifications.ts b/src/server/api/endpoints/i/notifications.ts
index 3b4899682d..50ed9b27e8 100644
--- a/src/server/api/endpoints/i/notifications.ts
+++ b/src/server/api/endpoints/i/notifications.ts
@@ -1,11 +1,11 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Notification from '../../../../models/notification';
import Mute from '../../../../models/mute';
import { pack } from '../../../../models/notification';
-import getFriends from '../../common/get-friends';
+import { getFriendIds } from '../../common/get-friends';
import read from '../../common/read-notification';
/**
@@ -14,27 +14,27 @@ import read from '../../common/read-notification';
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'following' parameter
const [following = false, followingError] =
- $(params.following).optional.boolean().$;
+ $.bool.optional().get(params.following);
if (followingError) return rej('invalid following param');
// Get 'markAsRead' parameter
- const [markAsRead = true, markAsReadErr] = $(params.markAsRead).optional.boolean().$;
+ const [markAsRead = true, markAsReadErr] = $.bool.optional().get(params.markAsRead);
if (markAsReadErr) return rej('invalid markAsRead param');
// Get 'type' parameter
- const [type, typeErr] = $(params.type).optional.array('string').unique().$;
+ const [type, typeErr] = $.arr($.str).optional().unique().get(params.type);
if (typeErr) return rej('invalid type param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
@@ -62,7 +62,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
if (following) {
// ID list of the user itself and other users who the user follows
- const followingIds = await getFriends(user._id);
+ const followingIds = await getFriendIds(user._id);
query.$and.push({
notifierId: {
diff --git a/src/server/api/endpoints/i/pin.ts b/src/server/api/endpoints/i/pin.ts
index 909a6fdbde..423f0ac4ae 100644
--- a/src/server/api/endpoints/i/pin.ts
+++ b/src/server/api/endpoints/i/pin.ts
@@ -1,21 +1,17 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import User from '../../../../models/user';
import Note from '../../../../models/note';
import { pack } from '../../../../models/user';
/**
* Pin note
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Fetch pinee
diff --git a/src/server/api/endpoints/i/regenerate_token.ts b/src/server/api/endpoints/i/regenerate_token.ts
index f9e92c1797..6e1e571297 100644
--- a/src/server/api/endpoints/i/regenerate_token.ts
+++ b/src/server/api/endpoints/i/regenerate_token.ts
@@ -9,14 +9,10 @@ import generateUserToken from '../../common/generate-native-user-token';
/**
* Regenerate native token
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'password' parameter
- const [password, passwordErr] = $(params.password).string().$;
+ const [password, passwordErr] = $.str.get(params.password);
if (passwordErr) return rej('invalid password param');
// Compare password
diff --git a/src/server/api/endpoints/i/signin_history.ts b/src/server/api/endpoints/i/signin_history.ts
index 931b9e2252..63a74b41b1 100644
--- a/src/server/api/endpoints/i/signin_history.ts
+++ b/src/server/api/endpoints/i/signin_history.ts
@@ -1,27 +1,23 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Signin, { pack } from '../../../../models/signin';
/**
* Get signin history of my account
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts
index f3c9d777b5..b7b25d0f65 100644
--- a/src/server/api/endpoints/i/update.ts
+++ b/src/server/api/endpoints/i/update.ts
@@ -1,9 +1,10 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import User, { isValidName, isValidDescription, isValidLocation, isValidBirthday, pack } from '../../../../models/user';
import event from '../../../../publishers/stream';
+import DriveFile from '../../../../models/drive-file';
/**
* Update myself
@@ -12,51 +13,73 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
const isSecure = user != null && app == null;
// Get 'name' parameter
- const [name, nameErr] = $(params.name).optional.nullable.string().pipe(isValidName).$;
+ const [name, nameErr] = $.str.optional().nullable().pipe(isValidName).get(params.name);
if (nameErr) return rej('invalid name param');
if (name) user.name = name;
// Get 'description' parameter
- const [description, descriptionErr] = $(params.description).optional.nullable.string().pipe(isValidDescription).$;
+ const [description, descriptionErr] = $.str.optional().nullable().pipe(isValidDescription).get(params.description);
if (descriptionErr) return rej('invalid description param');
if (description !== undefined) user.description = description;
// Get 'location' parameter
- const [location, locationErr] = $(params.location).optional.nullable.string().pipe(isValidLocation).$;
+ const [location, locationErr] = $.str.optional().nullable().pipe(isValidLocation).get(params.location);
if (locationErr) return rej('invalid location param');
if (location !== undefined) user.profile.location = location;
// Get 'birthday' parameter
- const [birthday, birthdayErr] = $(params.birthday).optional.nullable.string().pipe(isValidBirthday).$;
+ const [birthday, birthdayErr] = $.str.optional().nullable().pipe(isValidBirthday).get(params.birthday);
if (birthdayErr) return rej('invalid birthday param');
if (birthday !== undefined) user.profile.birthday = birthday;
// Get 'avatarId' parameter
- const [avatarId, avatarIdErr] = $(params.avatarId).optional.id().$;
+ const [avatarId, avatarIdErr] = $.type(ID).optional().get(params.avatarId);
if (avatarIdErr) return rej('invalid avatarId param');
if (avatarId) user.avatarId = avatarId;
// Get 'bannerId' parameter
- const [bannerId, bannerIdErr] = $(params.bannerId).optional.id().$;
+ const [bannerId, bannerIdErr] = $.type(ID).optional().get(params.bannerId);
if (bannerIdErr) return rej('invalid bannerId param');
if (bannerId) user.bannerId = bannerId;
// Get 'isBot' parameter
- const [isBot, isBotErr] = $(params.isBot).optional.boolean().$;
+ const [isBot, isBotErr] = $.bool.optional().get(params.isBot);
if (isBotErr) return rej('invalid isBot param');
if (isBot != null) user.isBot = isBot;
// Get 'autoWatch' parameter
- const [autoWatch, autoWatchErr] = $(params.autoWatch).optional.boolean().$;
+ const [autoWatch, autoWatchErr] = $.bool.optional().get(params.autoWatch);
if (autoWatchErr) return rej('invalid autoWatch param');
if (autoWatch != null) user.settings.autoWatch = autoWatch;
+ if (avatarId) {
+ const avatar = await DriveFile.findOne({
+ _id: avatarId
+ });
+
+ if (avatar != null && avatar.metadata.properties.avgColor) {
+ user.avatarColor = avatar.metadata.properties.avgColor;
+ }
+ }
+
+ if (bannerId) {
+ const banner = await DriveFile.findOne({
+ _id: bannerId
+ });
+
+ if (banner != null && banner.metadata.properties.avgColor) {
+ user.bannerColor = banner.metadata.properties.avgColor;
+ }
+ }
+
await User.update(user._id, {
$set: {
name: user.name,
description: user.description,
avatarId: user.avatarId,
+ avatarColor: user.avatarColor,
bannerId: user.bannerId,
+ bannerColor: user.bannerColor,
profile: user.profile,
isBot: user.isBot,
settings: user.settings
diff --git a/src/server/api/endpoints/i/update_client_setting.ts b/src/server/api/endpoints/i/update_client_setting.ts
index b0d5db5ec2..e91d7565fd 100644
--- a/src/server/api/endpoints/i/update_client_setting.ts
+++ b/src/server/api/endpoints/i/update_client_setting.ts
@@ -2,23 +2,19 @@
* Module dependencies
*/
import $ from 'cafy';
-import User, { pack } from '../../../../models/user';
+import User from '../../../../models/user';
import event from '../../../../publishers/stream';
/**
* Update myself
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'name' parameter
- const [name, nameErr] = $(params.name).string().$;
+ const [name, nameErr] = $.str.get(params.name);
if (nameErr) return rej('invalid name param');
// Get 'value' parameter
- const [value, valueErr] = $(params.value).nullable.any().$;
+ const [value, valueErr] = $.any.nullable().get(params.value);
if (valueErr) return rej('invalid value param');
const x = {};
@@ -28,16 +24,11 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
$set: x
});
- // Serialize
- user.clientSettings[name] = value;
- const iObj = await pack(user, user, {
- detail: true,
- includeSecrets: true
- });
-
- // Send response
- res(iObj);
+ res();
- // Publish i updated event
- event(user._id, 'i_updated', iObj);
+ // Publish event
+ event(user._id, 'clientSettingUpdated', {
+ key: name,
+ value
+ });
});
diff --git a/src/server/api/endpoints/i/update_home.ts b/src/server/api/endpoints/i/update_home.ts
index ce7661ede0..8ce551957e 100644
--- a/src/server/api/endpoints/i/update_home.ts
+++ b/src/server/api/endpoints/i/update_home.ts
@@ -7,20 +7,22 @@ import event from '../../../../publishers/stream';
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'home' parameter
- const [home, homeErr] = $(params.home).optional.array().each(
- $().strict.object()
- .have('name', $().string())
- .have('id', $().string())
- .have('place', $().string())
- .have('data', $().object())).$;
+ const [home, homeErr] = $.arr(
+ $.obj.strict()
+ .have('name', $.str)
+ .have('id', $.str)
+ .have('place', $.str)
+ .have('data', $.obj))
+ .optional()
+ .get(params.home);
if (homeErr) return rej('invalid home param');
// Get 'id' parameter
- const [id, idErr] = $(params.id).optional.string().$;
+ const [id, idErr] = $.str.optional().get(params.id);
if (idErr) return rej('invalid id param');
// Get 'data' parameter
- const [data, dataErr] = $(params.data).optional.object().$;
+ const [data, dataErr] = $.obj.optional().get(params.data);
if (dataErr) return rej('invalid data param');
if (home) {
diff --git a/src/server/api/endpoints/i/update_mobile_home.ts b/src/server/api/endpoints/i/update_mobile_home.ts
index b710e2f330..d79a77072b 100644
--- a/src/server/api/endpoints/i/update_mobile_home.ts
+++ b/src/server/api/endpoints/i/update_mobile_home.ts
@@ -7,19 +7,20 @@ import event from '../../../../publishers/stream';
module.exports = async (params, user) => new Promise(async (res, rej) => {
// Get 'home' parameter
- const [home, homeErr] = $(params.home).optional.array().each(
- $().strict.object()
- .have('name', $().string())
- .have('id', $().string())
- .have('data', $().object())).$;
+ const [home, homeErr] = $.arr(
+ $.obj.strict()
+ .have('name', $.str)
+ .have('id', $.str)
+ .have('data', $.obj))
+ .optional().get(params.home);
if (homeErr) return rej('invalid home param');
// Get 'id' parameter
- const [id, idErr] = $(params.id).optional.string().$;
+ const [id, idErr] = $.str.optional().get(params.id);
if (idErr) return rej('invalid id param');
// Get 'data' parameter
- const [data, dataErr] = $(params.data).optional.object().$;
+ const [data, dataErr] = $.obj.optional().get(params.data);
if (dataErr) return rej('invalid data param');
if (home) {
diff --git a/src/server/api/endpoints/messaging/history.ts b/src/server/api/endpoints/messaging/history.ts
index e42d34f21a..ec97642f17 100644
--- a/src/server/api/endpoints/messaging/history.ts
+++ b/src/server/api/endpoints/messaging/history.ts
@@ -8,14 +8,10 @@ import { pack } from '../../../../models/messaging-message';
/**
* Show messaging history
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
const mute = await Mute.find({
diff --git a/src/server/api/endpoints/messaging/messages.ts b/src/server/api/endpoints/messaging/messages.ts
index 092eab0562..0338aba68a 100644
--- a/src/server/api/endpoints/messaging/messages.ts
+++ b/src/server/api/endpoints/messaging/messages.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Message from '../../../../models/messaging-message';
import User from '../../../../models/user';
import { pack } from '../../../../models/messaging-message';
@@ -16,7 +16,7 @@ import read from '../../common/read-messaging-message';
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [recipientId, recipientIdErr] = $(params.userId).id().$;
+ const [recipientId, recipientIdErr] = $.type(ID).get(params.userId);
if (recipientIdErr) return rej('invalid userId param');
// Fetch recipient
@@ -33,19 +33,19 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
}
// Get 'markAsRead' parameter
- const [markAsRead = true, markAsReadErr] = $(params.markAsRead).optional.boolean().$;
+ const [markAsRead = true, markAsReadErr] = $.bool.optional().get(params.markAsRead);
if (markAsReadErr) return rej('invalid markAsRead param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
diff --git a/src/server/api/endpoints/messaging/messages/create.ts b/src/server/api/endpoints/messaging/messages/create.ts
index 085e75e6cf..db471839e7 100644
--- a/src/server/api/endpoints/messaging/messages/create.ts
+++ b/src/server/api/endpoints/messaging/messages/create.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import Message from '../../../../../models/messaging-message';
import { isValidText } from '../../../../../models/messaging-message';
import History from '../../../../../models/messaging-history';
@@ -12,20 +12,14 @@ import { pack } from '../../../../../models/messaging-message';
import publishUserStream from '../../../../../publishers/stream';
import { publishMessagingStream, publishMessagingIndexStream } from '../../../../../publishers/stream';
import pushSw from '../../../../../publishers/push-sw';
-import html from '../../../../../text/html';
-import parse from '../../../../../text/parse';
import config from '../../../../../config';
/**
* Create a message
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [recipientId, recipientIdErr] = $(params.userId).id().$;
+ const [recipientId, recipientIdErr] = $.type(ID).get(params.userId);
if (recipientIdErr) return rej('invalid userId param');
// Myself
@@ -47,11 +41,11 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
}
// Get 'text' parameter
- const [text, textErr] = $(params.text).optional.string().pipe(isValidText).$;
+ const [text, textErr] = $.str.optional().pipe(isValidText).get(params.text);
if (textErr) return rej('invalid text');
// Get 'fileId' parameter
- const [fileId, fileIdErr] = $(params.fileId).optional.id().$;
+ const [fileId, fileIdErr] = $.type(ID).optional().get(params.fileId);
if (fileIdErr) return rej('invalid fileId param');
let file = null;
@@ -77,7 +71,6 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
fileId: file ? file._id : undefined,
recipientId: recipient._id,
text: text ? text : undefined,
- textHtml: text ? html(parse(text)) : undefined,
userId: user._id,
isRead: false
});
diff --git a/src/server/api/endpoints/messaging/unread.ts b/src/server/api/endpoints/messaging/unread.ts
index 30d59dd8bd..1d83af501d 100644
--- a/src/server/api/endpoints/messaging/unread.ts
+++ b/src/server/api/endpoints/messaging/unread.ts
@@ -6,10 +6,6 @@ import Mute from '../../../../models/mute';
/**
* Get count of unread messages
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
const mute = await Mute.find({
diff --git a/src/server/api/endpoints/meta.ts b/src/server/api/endpoints/meta.ts
index f6a276a2b7..0e9ecf47df 100644
--- a/src/server/api/endpoints/meta.ts
+++ b/src/server/api/endpoints/meta.ts
@@ -2,10 +2,12 @@
* Module dependencies
*/
import * as os from 'os';
-import version from '../../../version';
import config from '../../../config';
import Meta from '../../../models/meta';
+const pkg = require('../../../../package.json');
+const client = require('../../../../built/client/meta.json');
+
/**
* @swagger
* /meta:
@@ -41,7 +43,10 @@ module.exports = (params) => new Promise(async (res, rej) => {
res({
maintainer: config.maintainer,
- version: version,
+
+ version: pkg.version,
+ clientVersion: client.version,
+
secure: config.https != null,
machine: os.hostname(),
os: os.platform(),
diff --git a/src/server/api/endpoints/mute/create.ts b/src/server/api/endpoints/mute/create.ts
index 26ae612cab..534020c671 100644
--- a/src/server/api/endpoints/mute/create.ts
+++ b/src/server/api/endpoints/mute/create.ts
@@ -1,22 +1,18 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import User from '../../../../models/user';
import Mute from '../../../../models/mute';
/**
* Mute a user
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
const muter = user;
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// 自分自身
diff --git a/src/server/api/endpoints/mute/delete.ts b/src/server/api/endpoints/mute/delete.ts
index 6f617416c8..949aff64ba 100644
--- a/src/server/api/endpoints/mute/delete.ts
+++ b/src/server/api/endpoints/mute/delete.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import User from '../../../../models/user';
import Mute from '../../../../models/mute';
@@ -12,7 +12,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
const muter = user;
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Check if the mutee is yourself
diff --git a/src/server/api/endpoints/mute/list.ts b/src/server/api/endpoints/mute/list.ts
index bd80401445..cf89f7e959 100644
--- a/src/server/api/endpoints/mute/list.ts
+++ b/src/server/api/endpoints/mute/list.ts
@@ -1,29 +1,25 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Mute from '../../../../models/mute';
import { pack } from '../../../../models/user';
-import getFriends from '../../common/get-friends';
+import { getFriendIds } from '../../common/get-friends';
/**
* Get muted users of a user
- *
- * @param {any} params
- * @param {any} me
- * @return {Promise<any>}
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'iknow' parameter
- const [iknow = false, iknowErr] = $(params.iknow).optional.boolean().$;
+ const [iknow = false, iknowErr] = $.bool.optional().get(params.iknow);
if (iknowErr) return rej('invalid iknow param');
// Get 'limit' parameter
- const [limit = 30, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 30, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'cursor' parameter
- const [cursor = null, cursorErr] = $(params.cursor).optional.id().$;
+ const [cursor = null, cursorErr] = $.type(ID).optional().get(params.cursor);
if (cursorErr) return rej('invalid cursor param');
// Construct query
@@ -34,7 +30,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
if (iknow) {
// Get my friends
- const myFriends = await getFriends(me._id);
+ const myFriends = await getFriendIds(me._id);
query.muteeId = {
$in: myFriends
diff --git a/src/server/api/endpoints/my/apps.ts b/src/server/api/endpoints/my/apps.ts
index 2a3f8bcd7a..086e0b8965 100644
--- a/src/server/api/endpoints/my/apps.ts
+++ b/src/server/api/endpoints/my/apps.ts
@@ -6,18 +6,14 @@ import App, { pack } from '../../../../models/app';
/**
* Get my apps
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
const query = {
diff --git a/src/server/api/endpoints/notes.ts b/src/server/api/endpoints/notes.ts
index a70ac0588f..4ce7613d70 100644
--- a/src/server/api/endpoints/notes.ts
+++ b/src/server/api/endpoints/notes.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../cafy-id';
import Note, { pack } from '../../../models/note';
/**
@@ -9,35 +9,35 @@ import Note, { pack } from '../../../models/note';
*/
module.exports = (params) => new Promise(async (res, rej) => {
// Get 'reply' parameter
- const [reply, replyErr] = $(params.reply).optional.boolean().$;
+ const [reply, replyErr] = $.bool.optional().get(params.reply);
if (replyErr) return rej('invalid reply param');
// Get 'renote' parameter
- const [renote, renoteErr] = $(params.renote).optional.boolean().$;
+ const [renote, renoteErr] = $.bool.optional().get(params.renote);
if (renoteErr) return rej('invalid renote param');
// Get 'media' parameter
- const [media, mediaErr] = $(params.media).optional.boolean().$;
+ const [media, mediaErr] = $.bool.optional().get(params.media);
if (mediaErr) return rej('invalid media param');
// Get 'poll' parameter
- const [poll, pollErr] = $(params.poll).optional.boolean().$;
+ const [poll, pollErr] = $.bool.optional().get(params.poll);
if (pollErr) return rej('invalid poll param');
// Get 'bot' parameter
- //const [bot, botErr] = $(params.bot).optional.boolean().$;
+ //const [bot, botErr] = $.bool.optional().get(params.bot);
//if (botErr) return rej('invalid bot param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
diff --git a/src/server/api/endpoints/notes/context.ts b/src/server/api/endpoints/notes/context.ts
index 2caf742d26..1cd27250e2 100644
--- a/src/server/api/endpoints/notes/context.ts
+++ b/src/server/api/endpoints/notes/context.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note, { pack } from '../../../../models/note';
/**
@@ -13,15 +13,15 @@ import Note, { pack } from '../../../../models/note';
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Lookup note
diff --git a/src/server/api/endpoints/notes/create.ts b/src/server/api/endpoints/notes/create.ts
index 7e79912b1b..429b6d370a 100644
--- a/src/server/api/endpoints/notes/create.ts
+++ b/src/server/api/endpoints/notes/create.ts
@@ -1,10 +1,9 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
-import deepEqual = require('deep-equal');
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note, { INote, isValidText, isValidCw, pack } from '../../../../models/note';
-import { ILocalUser } from '../../../../models/user';
+import User, { ILocalUser } from '../../../../models/user';
import Channel, { IChannel } from '../../../../models/channel';
import DriveFile from '../../../../models/drive-file';
import create from '../../../../services/note/create';
@@ -12,48 +11,54 @@ import { IApp } from '../../../../models/app';
/**
* Create a note
- *
- * @param {any} params
- * @param {any} user
- * @param {any} app
- * @return {Promise<any>}
*/
module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res, rej) => {
// Get 'visibility' parameter
- const [visibility = 'public', visibilityErr] = $(params.visibility).optional.string().or(['public', 'unlisted', 'private', 'direct']).$;
+ const [visibility = 'public', visibilityErr] = $.str.optional().or(['public', 'home', 'followers', 'specified', 'private']).get(params.visibility);
if (visibilityErr) return rej('invalid visibility');
+ // Get 'visibleUserIds' parameter
+ const [visibleUserIds, visibleUserIdsErr] = $.arr($.type(ID)).optional().unique().min(1).get(params.visibleUserIds);
+ if (visibleUserIdsErr) return rej('invalid visibleUserIds');
+
+ let visibleUsers = [];
+ if (visibleUserIds !== undefined) {
+ visibleUsers = await Promise.all(visibleUserIds.map(id => User.findOne({
+ _id: id
+ })));
+ }
+
// Get 'text' parameter
- const [text, textErr] = $(params.text).optional.string().pipe(isValidText).$;
+ const [text = null, textErr] = $.str.optional().nullable().pipe(isValidText).get(params.text);
if (textErr) return rej('invalid text');
// Get 'cw' parameter
- const [cw, cwErr] = $(params.cw).optional.string().pipe(isValidCw).$;
+ const [cw, cwErr] = $.str.optional().nullable().pipe(isValidCw).get(params.cw);
if (cwErr) return rej('invalid cw');
// Get 'viaMobile' parameter
- const [viaMobile = false, viaMobileErr] = $(params.viaMobile).optional.boolean().$;
+ const [viaMobile = false, viaMobileErr] = $.bool.optional().get(params.viaMobile);
if (viaMobileErr) return rej('invalid viaMobile');
// Get 'tags' parameter
- const [tags = [], tagsErr] = $(params.tags).optional.array('string').unique().eachQ(t => t.range(1, 32)).$;
+ const [tags = [], tagsErr] = $.arr($.str.range(1, 32)).optional().unique().get(params.tags);
if (tagsErr) return rej('invalid tags');
// Get 'geo' parameter
- const [geo, geoErr] = $(params.geo).optional.nullable.strict.object()
- .have('coordinates', $().array().length(2)
- .item(0, $().number().range(-180, 180))
- .item(1, $().number().range(-90, 90)))
- .have('altitude', $().nullable.number())
- .have('accuracy', $().nullable.number())
- .have('altitudeAccuracy', $().nullable.number())
- .have('heading', $().nullable.number().range(0, 360))
- .have('speed', $().nullable.number())
- .$;
+ const [geo, geoErr] = $.obj.optional().nullable().strict()
+ .have('coordinates', $.arr().length(2)
+ .item(0, $.num.range(-180, 180))
+ .item(1, $.num.range(-90, 90)))
+ .have('altitude', $.num.nullable())
+ .have('accuracy', $.num.nullable())
+ .have('altitudeAccuracy', $.num.nullable())
+ .have('heading', $.num.nullable().range(0, 360))
+ .have('speed', $.num.nullable())
+ .get(params.geo);
if (geoErr) return rej('invalid geo');
// Get 'mediaIds' parameter
- const [mediaIds, mediaIdsErr] = $(params.mediaIds).optional.array('id').unique().range(1, 4).$;
+ const [mediaIds, mediaIdsErr] = $.arr($.type(ID)).optional().unique().range(1, 4).get(params.mediaIds);
if (mediaIdsErr) return rej('invalid mediaIds');
let files = [];
@@ -80,7 +85,7 @@ module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res
}
// Get 'renoteId' parameter
- const [renoteId, renoteIdErr] = $(params.renoteId).optional.id().$;
+ const [renoteId, renoteIdErr] = $.type(ID).optional().get(params.renoteId);
if (renoteIdErr) return rej('invalid renoteId');
let renote: INote = null;
@@ -97,35 +102,11 @@ module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res
return rej('cannot renote to renote');
}
- // Fetch recently note
- const latestNote = await Note.findOne({
- userId: user._id
- }, {
- sort: {
- _id: -1
- }
- });
-
isQuote = text != null || files != null;
-
- // 直近と同じRenote対象かつ引用じゃなかったらエラー
- if (latestNote &&
- latestNote.renoteId &&
- latestNote.renoteId.equals(renote._id) &&
- !isQuote) {
- return rej('cannot renote same note that already reposted in your latest note');
- }
-
- // 直近がRenote対象かつ引用じゃなかったらエラー
- if (latestNote &&
- latestNote._id.equals(renote._id) &&
- !isQuote) {
- return rej('cannot renote your latest note');
- }
}
// Get 'replyId' parameter
- const [replyId, replyIdErr] = $(params.replyId).optional.id().$;
+ const [replyId, replyIdErr] = $.type(ID).optional().get(params.replyId);
if (replyIdErr) return rej('invalid replyId');
let reply: INote = null;
@@ -146,7 +127,7 @@ module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res
}
// Get 'channelId' parameter
- const [channelId, channelIdErr] = $(params.channelId).optional.id().$;
+ const [channelId, channelIdErr] = $.type(ID).optional().get(params.channelId);
if (channelIdErr) return rej('invalid channelId');
let channel: IChannel = null;
@@ -187,12 +168,12 @@ module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res
}
// Get 'poll' parameter
- const [poll, pollErr] = $(params.poll).optional.strict.object()
- .have('choices', $().array('string')
+ const [poll, pollErr] = $.obj.optional().strict()
+ .have('choices', $.arr($.str)
.unique()
.range(2, 10)
.each(c => c.length > 0 && c.length < 50))
- .$;
+ .get(params.poll);
if (pollErr) return rej('invalid poll');
if (poll) {
@@ -208,37 +189,20 @@ module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res
return rej('text, mediaIds, renoteId or poll is required');
}
- // 直近の投稿と重複してたらエラー
- // TODO: 直近の投稿が一日前くらいなら重複とは見なさない
- if (user.latestNote) {
- if (deepEqual({
- text: user.latestNote.text,
- reply: user.latestNote.replyId ? user.latestNote.replyId.toString() : null,
- renote: user.latestNote.renoteId ? user.latestNote.renoteId.toString() : null,
- mediaIds: (user.latestNote.mediaIds || []).map(id => id.toString())
- }, {
- text: text,
- reply: reply ? reply._id.toString() : null,
- renote: renote ? renote._id.toString() : null,
- mediaIds: (files || []).map(file => file._id.toString())
- })) {
- return rej('duplicate');
- }
- }
-
// 投稿を作成
const note = await create(user, {
createdAt: new Date(),
media: files,
- poll: poll,
- text: text,
+ poll,
+ text,
reply,
renote,
- cw: cw,
- tags: tags,
- app: app,
- viaMobile: viaMobile,
+ cw,
+ tags,
+ app,
+ viaMobile,
visibility,
+ visibleUsers,
geo
});
diff --git a/src/server/api/endpoints/notes/favorites/create.ts b/src/server/api/endpoints/notes/favorites/create.ts
index c8e7f52426..6832b52f75 100644
--- a/src/server/api/endpoints/notes/favorites/create.ts
+++ b/src/server/api/endpoints/notes/favorites/create.ts
@@ -1,20 +1,16 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import Favorite from '../../../../../models/favorite';
import Note from '../../../../../models/note';
/**
* Favorite a note
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Get favoritee
diff --git a/src/server/api/endpoints/notes/favorites/delete.ts b/src/server/api/endpoints/notes/favorites/delete.ts
index 92aceb343b..07112dae15 100644
--- a/src/server/api/endpoints/notes/favorites/delete.ts
+++ b/src/server/api/endpoints/notes/favorites/delete.ts
@@ -1,20 +1,16 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import Favorite from '../../../../../models/favorite';
import Note from '../../../../../models/note';
/**
* Unfavorite a note
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Get favoritee
diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts
index 07e138ec54..d22a1763de 100644
--- a/src/server/api/endpoints/notes/global-timeline.ts
+++ b/src/server/api/endpoints/notes/global-timeline.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note from '../../../../models/note';
import Mute from '../../../../models/mute';
import { pack } from '../../../../models/note';
@@ -11,23 +11,23 @@ import { pack } from '../../../../models/note';
*/
module.exports = async (params, user, app) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) throw 'invalid limit param';
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) throw 'invalid sinceId param';
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) throw 'invalid untilId param';
// Get 'sinceDate' parameter
- const [sinceDate, sinceDateErr] = $(params.sinceDate).optional.number().$;
+ const [sinceDate, sinceDateErr] = $.num.optional().get(params.sinceDate);
if (sinceDateErr) throw 'invalid sinceDate param';
// Get 'untilDate' parameter
- const [untilDate, untilDateErr] = $(params.untilDate).optional.number().$;
+ const [untilDate, untilDateErr] = $.num.optional().get(params.untilDate);
if (untilDateErr) throw 'invalid untilDate param';
// Check if only one of sinceId, untilId, sinceDate, untilDate specified
diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts
index d63528c3cd..e7ebe5d960 100644
--- a/src/server/api/endpoints/notes/local-timeline.ts
+++ b/src/server/api/endpoints/notes/local-timeline.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note from '../../../../models/note';
import Mute from '../../../../models/mute';
import { pack } from '../../../../models/note';
@@ -11,23 +11,23 @@ import { pack } from '../../../../models/note';
*/
module.exports = async (params, user, app) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) throw 'invalid limit param';
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) throw 'invalid sinceId param';
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) throw 'invalid untilId param';
// Get 'sinceDate' parameter
- const [sinceDate, sinceDateErr] = $(params.sinceDate).optional.number().$;
+ const [sinceDate, sinceDateErr] = $.num.optional().get(params.sinceDate);
if (sinceDateErr) throw 'invalid sinceDate param';
// Get 'untilDate' parameter
- const [untilDate, untilDateErr] = $(params.untilDate).optional.number().$;
+ const [untilDate, untilDateErr] = $.num.optional().get(params.untilDate);
if (untilDateErr) throw 'invalid untilDate param';
// Check if only one of sinceId, untilId, sinceDate, untilDate specified
diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts
index c507acbaec..163a6b4866 100644
--- a/src/server/api/endpoints/notes/mentions.ts
+++ b/src/server/api/endpoints/notes/mentions.ts
@@ -1,9 +1,9 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note from '../../../../models/note';
-import getFriends from '../../common/get-friends';
+import { getFriendIds } from '../../common/get-friends';
import { pack } from '../../../../models/note';
/**
@@ -16,19 +16,19 @@ import { pack } from '../../../../models/note';
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'following' parameter
const [following = false, followingError] =
- $(params.following).optional.boolean().$;
+ $.bool.optional().get(params.following);
if (followingError) return rej('invalid following param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
@@ -46,7 +46,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
};
if (following) {
- const followingIds = await getFriends(user._id);
+ const followingIds = await getFriendIds(user._id);
query.userId = {
$in: followingIds
diff --git a/src/server/api/endpoints/notes/polls/recommendation.ts b/src/server/api/endpoints/notes/polls/recommendation.ts
index cb530ea2cf..a272378d19 100644
--- a/src/server/api/endpoints/notes/polls/recommendation.ts
+++ b/src/server/api/endpoints/notes/polls/recommendation.ts
@@ -7,18 +7,14 @@ import Note, { pack } from '../../../../../models/note';
/**
* Get recommended polls
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Get votes
diff --git a/src/server/api/endpoints/notes/polls/vote.ts b/src/server/api/endpoints/notes/polls/vote.ts
index 03d94da60d..f8f4515308 100644
--- a/src/server/api/endpoints/notes/polls/vote.ts
+++ b/src/server/api/endpoints/notes/polls/vote.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import Vote from '../../../../../models/poll-vote';
import Note from '../../../../../models/note';
import Watching from '../../../../../models/note-watching';
@@ -11,14 +11,10 @@ import notify from '../../../../../publishers/notify';
/**
* Vote poll of a note
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Get votee
@@ -36,9 +32,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'choice' parameter
const [choice, choiceError] =
- $(params.choice).number()
+ $.num
.pipe(c => note.poll.choices.some(x => x.id == c))
- .$;
+ .get(params.choice);
if (choiceError) return rej('invalid choice param');
// if already voted
diff --git a/src/server/api/endpoints/notes/reactions.ts b/src/server/api/endpoints/notes/reactions.ts
index bbff97bb0a..4ad952a7a1 100644
--- a/src/server/api/endpoints/notes/reactions.ts
+++ b/src/server/api/endpoints/notes/reactions.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note from '../../../../models/note';
import Reaction, { pack } from '../../../../models/note-reaction';
@@ -14,19 +14,19 @@ import Reaction, { pack } from '../../../../models/note-reaction';
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Get 'sort' parameter
- const [sort = 'desc', sortError] = $(params.sort).optional.string().or('desc asc').$;
+ const [sort = 'desc', sortError] = $.str.optional().or('desc asc').get(params.sort);
if (sortError) return rej('invalid sort param');
// Lookup note
diff --git a/src/server/api/endpoints/notes/reactions/create.ts b/src/server/api/endpoints/notes/reactions/create.ts
index c80c5416b1..21757cb427 100644
--- a/src/server/api/endpoints/notes/reactions/create.ts
+++ b/src/server/api/endpoints/notes/reactions/create.ts
@@ -1,30 +1,21 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import Note from '../../../../../models/note';
import create from '../../../../../services/note/reaction/create';
+import { validateReaction } from '../../../../../models/note-reaction';
/**
* React to a note
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Get 'reaction' parameter
- const [reaction, reactionErr] = $(params.reaction).string().or([
- 'like',
- 'love',
- 'laugh',
- 'hmm',
- 'surprise',
- 'congrats',
- 'angry',
- 'confused',
- 'pudding'
- ]).$;
+ const [reaction, reactionErr] = $.str.pipe(validateReaction.ok).get(params.reaction);
if (reactionErr) return rej('invalid reaction param');
// Fetch reactee
diff --git a/src/server/api/endpoints/notes/reactions/delete.ts b/src/server/api/endpoints/notes/reactions/delete.ts
index b5d738b8ff..afb8629112 100644
--- a/src/server/api/endpoints/notes/reactions/delete.ts
+++ b/src/server/api/endpoints/notes/reactions/delete.ts
@@ -1,21 +1,16 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import Reaction from '../../../../../models/note-reaction';
import Note from '../../../../../models/note';
-// import event from '../../../publishers/stream';
/**
* Unreact to a note
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Fetch unreactee
diff --git a/src/server/api/endpoints/notes/replies.ts b/src/server/api/endpoints/notes/replies.ts
index 88d9ff329a..11d221d8f7 100644
--- a/src/server/api/endpoints/notes/replies.ts
+++ b/src/server/api/endpoints/notes/replies.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note, { pack } from '../../../../models/note';
/**
@@ -13,19 +13,19 @@ import Note, { pack } from '../../../../models/note';
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Get 'sort' parameter
- const [sort = 'desc', sortError] = $(params.sort).optional.string().or('desc asc').$;
+ const [sort = 'desc', sortError] = $.str.optional().or('desc asc').get(params.sort);
if (sortError) return rej('invalid sort param');
// Lookup note
diff --git a/src/server/api/endpoints/notes/reposts.ts b/src/server/api/endpoints/notes/reposts.ts
index 9dfc2c3cb5..3098211b61 100644
--- a/src/server/api/endpoints/notes/reposts.ts
+++ b/src/server/api/endpoints/notes/reposts.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note, { pack } from '../../../../models/note';
/**
@@ -13,19 +13,19 @@ import Note, { pack } from '../../../../models/note';
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
diff --git a/src/server/api/endpoints/notes/search.ts b/src/server/api/endpoints/notes/search.ts
index bfa17b000e..9705dcfd6e 100644
--- a/src/server/api/endpoints/notes/search.ts
+++ b/src/server/api/endpoints/notes/search.ts
@@ -1,12 +1,12 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
const escapeRegexp = require('escape-regexp');
import Note from '../../../../models/note';
import User from '../../../../models/user';
import Mute from '../../../../models/mute';
-import getFriends from '../../common/get-friends';
+import { getFriendIds } from '../../common/get-friends';
import { pack } from '../../../../models/note';
/**
@@ -18,63 +18,63 @@ import { pack } from '../../../../models/note';
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'text' parameter
- const [text, textError] = $(params.text).optional.string().$;
+ const [text, textError] = $.str.optional().get(params.text);
if (textError) return rej('invalid text param');
// Get 'includeUserIds' parameter
- const [includeUserIds = [], includeUserIdsErr] = $(params.includeUserIds).optional.array('id').$;
+ const [includeUserIds = [], includeUserIdsErr] = $.arr($.type(ID)).optional().get(params.includeUserIds);
if (includeUserIdsErr) return rej('invalid includeUserIds param');
// Get 'excludeUserIds' parameter
- const [excludeUserIds = [], excludeUserIdsErr] = $(params.excludeUserIds).optional.array('id').$;
+ const [excludeUserIds = [], excludeUserIdsErr] = $.arr($.type(ID)).optional().get(params.excludeUserIds);
if (excludeUserIdsErr) return rej('invalid excludeUserIds param');
// Get 'includeUserUsernames' parameter
- const [includeUserUsernames = [], includeUserUsernamesErr] = $(params.includeUserUsernames).optional.array('string').$;
+ const [includeUserUsernames = [], includeUserUsernamesErr] = $.arr($.str).optional().get(params.includeUserUsernames);
if (includeUserUsernamesErr) return rej('invalid includeUserUsernames param');
// Get 'excludeUserUsernames' parameter
- const [excludeUserUsernames = [], excludeUserUsernamesErr] = $(params.excludeUserUsernames).optional.array('string').$;
+ const [excludeUserUsernames = [], excludeUserUsernamesErr] = $.arr($.str).optional().get(params.excludeUserUsernames);
if (excludeUserUsernamesErr) return rej('invalid excludeUserUsernames param');
// Get 'following' parameter
- const [following = null, followingErr] = $(params.following).optional.nullable.boolean().$;
+ const [following = null, followingErr] = $.bool.optional().nullable().get(params.following);
if (followingErr) return rej('invalid following param');
// Get 'mute' parameter
- const [mute = 'mute_all', muteErr] = $(params.mute).optional.string().$;
+ const [mute = 'mute_all', muteErr] = $.str.optional().get(params.mute);
if (muteErr) return rej('invalid mute param');
// Get 'reply' parameter
- const [reply = null, replyErr] = $(params.reply).optional.nullable.boolean().$;
+ const [reply = null, replyErr] = $.bool.optional().nullable().get(params.reply);
if (replyErr) return rej('invalid reply param');
// Get 'renote' parameter
- const [renote = null, renoteErr] = $(params.renote).optional.nullable.boolean().$;
+ const [renote = null, renoteErr] = $.bool.optional().nullable().get(params.renote);
if (renoteErr) return rej('invalid renote param');
// Get 'media' parameter
- const [media = null, mediaErr] = $(params.media).optional.nullable.boolean().$;
+ const [media = null, mediaErr] = $.bool.optional().nullable().get(params.media);
if (mediaErr) return rej('invalid media param');
// Get 'poll' parameter
- const [poll = null, pollErr] = $(params.poll).optional.nullable.boolean().$;
+ const [poll = null, pollErr] = $.bool.optional().nullable().get(params.poll);
if (pollErr) return rej('invalid poll param');
// Get 'sinceDate' parameter
- const [sinceDate, sinceDateErr] = $(params.sinceDate).optional.number().$;
+ const [sinceDate, sinceDateErr] = $.num.optional().get(params.sinceDate);
if (sinceDateErr) throw 'invalid sinceDate param';
// Get 'untilDate' parameter
- const [untilDate, untilDateErr] = $(params.untilDate).optional.number().$;
+ const [untilDate, untilDateErr] = $.num.optional().get(params.untilDate);
if (untilDateErr) throw 'invalid untilDate param';
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 30).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 30).get(params.limit);
if (limitErr) return rej('invalid limit param');
let includeUsers = includeUserIds;
@@ -156,7 +156,7 @@ async function search(
}
if (following != null && me != null) {
- const ids = await getFriends(me._id, false);
+ const ids = await getFriendIds(me._id, false);
push({
userId: following ? {
$in: ids
diff --git a/src/server/api/endpoints/notes/show.ts b/src/server/api/endpoints/notes/show.ts
index 67cdc3038b..78dc55a703 100644
--- a/src/server/api/endpoints/notes/show.ts
+++ b/src/server/api/endpoints/notes/show.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note, { pack } from '../../../../models/note';
/**
@@ -13,7 +13,7 @@ import Note, { pack } from '../../../../models/note';
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'noteId' parameter
- const [noteId, noteIdErr] = $(params.noteId).id().$;
+ const [noteId, noteIdErr] = $.type(ID).get(params.noteId);
if (noteIdErr) return rej('invalid noteId param');
// Get note
diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts
index b5feaac817..78786d4a16 100644
--- a/src/server/api/endpoints/notes/timeline.ts
+++ b/src/server/api/endpoints/notes/timeline.ts
@@ -1,12 +1,11 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
-import rap from '@prezzemolo/rap';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note from '../../../../models/note';
import Mute from '../../../../models/mute';
import ChannelWatching from '../../../../models/channel-watching';
-import getFriends from '../../common/get-friends';
+import { getFriends } from '../../common/get-friends';
import { pack } from '../../../../models/note';
/**
@@ -14,23 +13,23 @@ import { pack } from '../../../../models/note';
*/
module.exports = async (params, user, app) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) throw 'invalid limit param';
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) throw 'invalid sinceId param';
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) throw 'invalid untilId param';
// Get 'sinceDate' parameter
- const [sinceDate, sinceDateErr] = $(params.sinceDate).optional.number().$;
+ const [sinceDate, sinceDateErr] = $.num.optional().get(params.sinceDate);
if (sinceDateErr) throw 'invalid sinceDate param';
// Get 'untilDate' parameter
- const [untilDate, untilDateErr] = $(params.untilDate).optional.number().$;
+ const [untilDate, untilDateErr] = $.num.optional().get(params.untilDate);
if (untilDateErr) throw 'invalid untilDate param';
// Check if only one of sinceId, untilId, sinceDate, untilDate specified
@@ -38,59 +37,130 @@ module.exports = async (params, user, app) => {
throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
}
- const { followingIds, watchingChannelIds, mutedUserIds } = await rap({
- // ID list of the user itself and other users who the user follows
- followingIds: getFriends(user._id),
+ // Get 'includeMyRenotes' parameter
+ const [includeMyRenotes = true, includeMyRenotesErr] = $.bool.optional().get(params.includeMyRenotes);
+ if (includeMyRenotesErr) throw 'invalid includeMyRenotes param';
+
+ // Get 'includeRenotedMyNotes' parameter
+ const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
+ if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
+
+ const [followings, watchingChannelIds, mutedUserIds] = await Promise.all([
+ // フォローを取得
+ // Fetch following
+ getFriends(user._id),
// Watchしているチャンネルを取得
- watchingChannelIds: ChannelWatching.find({
+ ChannelWatching.find({
userId: user._id,
// 削除されたドキュメントは除く
deletedAt: { $exists: false }
}).then(watches => watches.map(w => w.channelId)),
// ミュートしているユーザーを取得
- mutedUserIds: Mute.find({
+ Mute.find({
muterId: user._id
}).then(ms => ms.map(m => m.muteeId))
- });
+ ]);
//#region Construct query
const sort = {
_id: -1
};
- const query = {
+ const followQuery = followings.map(f => f.stalk ? {
+ userId: f.id
+ } : {
+ userId: f.id,
+
+ // ストーキングしてないならリプライは含めない(ただし投稿者自身の投稿へのリプライ、自分の投稿へのリプライ、自分のリプライは含める)
$or: [{
- // フォローしている人のタイムラインへの投稿
- userId: {
- $in: followingIds
- },
- // 「タイムラインへの」投稿に限定するためにチャンネルが指定されていないもののみに限る
+ // リプライでない
+ replyId: null
+ }, { // または
+ // リプライだが返信先が投稿者自身の投稿
+ $expr: {
+ $eq: ['$_reply.userId', '$userId']
+ }
+ }, { // または
+ // リプライだが返信先が自分(フォロワー)の投稿
+ '_reply.userId': user._id
+ }, { // または
+ // 自分(フォロワー)が送信したリプライ
+ userId: user._id
+ }]
+ });
+
+ const query = {
+ $and: [{
$or: [{
+ $and: [{
+ // フォローしている人のタイムラインへの投稿
+ $or: followQuery
+ }, {
+ // 「タイムラインへの」投稿に限定するためにチャンネルが指定されていないもののみに限る
+ $or: [{
+ channelId: {
+ $exists: false
+ }
+ }, {
+ channelId: null
+ }]
+ }]
+ }, {
+ // Watchしているチャンネルへの投稿
channelId: {
- $exists: false
+ $in: watchingChannelIds
}
+ }],
+ // mute
+ userId: {
+ $nin: mutedUserIds
+ },
+ '_reply.userId': {
+ $nin: mutedUserIds
+ },
+ '_renote.userId': {
+ $nin: mutedUserIds
+ },
+ }]
+ } as any;
+
+ // MongoDBではトップレベルで否定ができないため、De Morganの法則を利用してクエリします。
+ // つまり、「『自分の投稿かつRenote』ではない」を「『自分の投稿ではない』または『Renoteではない』」と表現します。
+ // for details: https://en.wikipedia.org/wiki/De_Morgan%27s_laws
+
+ if (includeMyRenotes === false) {
+ query.$and.push({
+ $or: [{
+ userId: { $ne: user._id }
+ }, {
+ renoteId: null
+ }, {
+ text: { $ne: null }
+ }, {
+ mediaIds: { $ne: [] }
}, {
- channelId: null
+ poll: { $ne: null }
}]
- }, {
- // Watchしているチャンネルへの投稿
- channelId: {
- $in: watchingChannelIds
- }
- }],
- // mute
- userId: {
- $nin: mutedUserIds
- },
- '_reply.userId': {
- $nin: mutedUserIds
- },
- '_renote.userId': {
- $nin: mutedUserIds
- },
- } as any;
+ });
+ }
+
+ if (includeRenotedMyNotes === false) {
+ query.$and.push({
+ $or: [{
+ '_renote.userId': { $ne: user._id }
+ }, {
+ renoteId: null
+ }, {
+ text: { $ne: null }
+ }, {
+ mediaIds: { $ne: [] }
+ }, {
+ poll: { $ne: null }
+ }]
+ });
+ }
if (sinceId) {
sort._id = 1;
diff --git a/src/server/api/endpoints/notes/trend.ts b/src/server/api/endpoints/notes/trend.ts
index 48ecd5b843..4735bec51e 100644
--- a/src/server/api/endpoints/notes/trend.ts
+++ b/src/server/api/endpoints/notes/trend.ts
@@ -14,36 +14,33 @@ import Note, { pack } from '../../../../models/note';
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Get 'reply' parameter
- const [reply, replyErr] = $(params.reply).optional.boolean().$;
+ const [reply, replyErr] = $.bool.optional().get(params.reply);
if (replyErr) return rej('invalid reply param');
// Get 'renote' parameter
- const [renote, renoteErr] = $(params.renote).optional.boolean().$;
+ const [renote, renoteErr] = $.bool.optional().get(params.renote);
if (renoteErr) return rej('invalid renote param');
// Get 'media' parameter
- const [media, mediaErr] = $(params.media).optional.boolean().$;
+ const [media, mediaErr] = $.bool.optional().get(params.media);
if (mediaErr) return rej('invalid media param');
// Get 'poll' parameter
- const [poll, pollErr] = $(params.poll).optional.boolean().$;
+ const [poll, pollErr] = $.bool.optional().get(params.poll);
if (pollErr) return rej('invalid poll param');
const query = {
- createdAt: {
- $gte: new Date(Date.now() - ms('1days'))
- },
- renoteCount: {
- $gt: 0
- }
+ _id: { $gte: new Date(Date.now() - ms('1days')) },
+ renoteCount: { $gt: 0 },
+ '_user.host': null
} as any;
if (reply != undefined) {
diff --git a/src/server/api/endpoints/notes/user-list-timeline.ts b/src/server/api/endpoints/notes/user-list-timeline.ts
new file mode 100644
index 0000000000..9f8397d679
--- /dev/null
+++ b/src/server/api/endpoints/notes/user-list-timeline.ts
@@ -0,0 +1,179 @@
+/**
+ * Module dependencies
+ */
+import $ from 'cafy'; import ID from '../../../../cafy-id';
+import Note from '../../../../models/note';
+import Mute from '../../../../models/mute';
+import { pack } from '../../../../models/note';
+import UserList from '../../../../models/user-list';
+
+/**
+ * Get timeline of a user list
+ */
+module.exports = async (params, user, app) => {
+ // Get 'limit' parameter
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
+ if (limitErr) throw 'invalid limit param';
+
+ // Get 'sinceId' parameter
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
+ if (sinceIdErr) throw 'invalid sinceId param';
+
+ // Get 'untilId' parameter
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
+ if (untilIdErr) throw 'invalid untilId param';
+
+ // Get 'sinceDate' parameter
+ const [sinceDate, sinceDateErr] = $.num.optional().get(params.sinceDate);
+ if (sinceDateErr) throw 'invalid sinceDate param';
+
+ // Get 'untilDate' parameter
+ const [untilDate, untilDateErr] = $.num.optional().get(params.untilDate);
+ if (untilDateErr) throw 'invalid untilDate param';
+
+ // Check if only one of sinceId, untilId, sinceDate, untilDate specified
+ if ([sinceId, untilId, sinceDate, untilDate].filter(x => x != null).length > 1) {
+ throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
+ }
+
+ // Get 'includeMyRenotes' parameter
+ const [includeMyRenotes = true, includeMyRenotesErr] = $.bool.optional().get(params.includeMyRenotes);
+ if (includeMyRenotesErr) throw 'invalid includeMyRenotes param';
+
+ // Get 'includeRenotedMyNotes' parameter
+ const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
+ if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
+
+ // Get 'listId' parameter
+ const [listId, listIdErr] = $.type(ID).get(params.listId);
+ if (listIdErr) throw 'invalid listId param';
+
+ const [list, mutedUserIds] = await Promise.all([
+ // リストを取得
+ // Fetch the list
+ UserList.findOne({
+ _id: listId,
+ userId: user._id
+ }),
+
+ // ミュートしているユーザーを取得
+ Mute.find({
+ muterId: user._id
+ }).then(ms => ms.map(m => m.muteeId))
+ ]);
+
+ if (list.userIds.length == 0) {
+ return [];
+ }
+
+ //#region Construct query
+ const sort = {
+ _id: -1
+ };
+
+ const listQuery = list.userIds.map(u => ({
+ userId: u,
+
+ // リプライは含めない(ただし投稿者自身の投稿へのリプライ、自分の投稿へのリプライ、自分のリプライは含める)
+ $or: [{
+ // リプライでない
+ replyId: null
+ }, { // または
+ // リプライだが返信先が投稿者自身の投稿
+ $expr: {
+ $eq: ['$_reply.userId', '$userId']
+ }
+ }, { // または
+ // リプライだが返信先が自分(フォロワー)の投稿
+ '_reply.userId': user._id
+ }, { // または
+ // 自分(フォロワー)が送信したリプライ
+ userId: user._id
+ }]
+ }));
+
+ const query = {
+ $and: [{
+ // リストに入っている人のタイムラインへの投稿
+ $or: listQuery,
+
+ // mute
+ userId: {
+ $nin: mutedUserIds
+ },
+ '_reply.userId': {
+ $nin: mutedUserIds
+ },
+ '_renote.userId': {
+ $nin: mutedUserIds
+ },
+ }]
+ } as any;
+
+ // MongoDBではトップレベルで否定ができないため、De Morganの法則を利用してクエリします。
+ // つまり、「『自分の投稿かつRenote』ではない」を「『自分の投稿ではない』または『Renoteではない』」と表現します。
+ // for details: https://en.wikipedia.org/wiki/De_Morgan%27s_laws
+
+ if (includeMyRenotes === false) {
+ query.$and.push({
+ $or: [{
+ userId: { $ne: user._id }
+ }, {
+ renoteId: null
+ }, {
+ text: { $ne: null }
+ }, {
+ mediaIds: { $ne: [] }
+ }, {
+ poll: { $ne: null }
+ }]
+ });
+ }
+
+ if (includeRenotedMyNotes === false) {
+ query.$and.push({
+ $or: [{
+ '_renote.userId': { $ne: user._id }
+ }, {
+ renoteId: null
+ }, {
+ text: { $ne: null }
+ }, {
+ mediaIds: { $ne: [] }
+ }, {
+ poll: { $ne: null }
+ }]
+ });
+ }
+
+ if (sinceId) {
+ sort._id = 1;
+ query._id = {
+ $gt: sinceId
+ };
+ } else if (untilId) {
+ query._id = {
+ $lt: untilId
+ };
+ } else if (sinceDate) {
+ sort._id = 1;
+ query.createdAt = {
+ $gt: new Date(sinceDate)
+ };
+ } else if (untilDate) {
+ query.createdAt = {
+ $lt: new Date(untilDate)
+ };
+ }
+ //#endregion
+
+ // Issue query
+ const timeline = await Note
+ .find(query, {
+ limit: limit,
+ sort: sort
+ });
+
+ // Serialize
+ return await Promise.all(timeline.map(note => pack(note, user)));
+};
diff --git a/src/server/api/endpoints/notifications/get_unread_count.ts b/src/server/api/endpoints/notifications/get_unread_count.ts
index 283ecd63b1..600a80d194 100644
--- a/src/server/api/endpoints/notifications/get_unread_count.ts
+++ b/src/server/api/endpoints/notifications/get_unread_count.ts
@@ -6,10 +6,6 @@ import Mute from '../../../../models/mute';
/**
* Get count of unread notifications
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
const mute = await Mute.find({
diff --git a/src/server/api/endpoints/notifications/mark_as_read_all.ts b/src/server/api/endpoints/notifications/mark_as_read_all.ts
index 01c9145837..dce3cb4663 100644
--- a/src/server/api/endpoints/notifications/mark_as_read_all.ts
+++ b/src/server/api/endpoints/notifications/mark_as_read_all.ts
@@ -6,10 +6,6 @@ import event from '../../../../publishers/stream';
/**
* Mark as read all notifications
- *
- * @param {any} params
- * @param {any} user
- * @return {Promise<any>}
*/
module.exports = (params, user) => new Promise(async (res, rej) => {
// Update documents
diff --git a/src/server/api/endpoints/othello/games.ts b/src/server/api/endpoints/othello/games.ts
index d05c1c2585..2320a34b04 100644
--- a/src/server/api/endpoints/othello/games.ts
+++ b/src/server/api/endpoints/othello/games.ts
@@ -1,21 +1,21 @@
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import OthelloGame, { pack } from '../../../../models/othello-game';
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'my' parameter
- const [my = false, myErr] = $(params.my).optional.boolean().$;
+ const [my = false, myErr] = $.bool.optional().get(params.my);
if (myErr) return rej('invalid my param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Check if both of sinceId and untilId is specified
diff --git a/src/server/api/endpoints/othello/games/show.ts b/src/server/api/endpoints/othello/games/show.ts
index dd886936d4..6b2f5ce137 100644
--- a/src/server/api/endpoints/othello/games/show.ts
+++ b/src/server/api/endpoints/othello/games/show.ts
@@ -1,10 +1,10 @@
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
import OthelloGame, { pack } from '../../../../../models/othello-game';
import Othello from '../../../../../othello/core';
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'gameId' parameter
- const [gameId, gameIdErr] = $(params.gameId).id().$;
+ const [gameId, gameIdErr] = $.type(ID).get(params.gameId);
if (gameIdErr) return rej('invalid gameId param');
const game = await OthelloGame.findOne({ _id: gameId });
diff --git a/src/server/api/endpoints/othello/match.ts b/src/server/api/endpoints/othello/match.ts
index d9274f8f9c..e70e579755 100644
--- a/src/server/api/endpoints/othello/match.ts
+++ b/src/server/api/endpoints/othello/match.ts
@@ -1,4 +1,4 @@
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Matching, { pack as packMatching } from '../../../../models/othello-matching';
import OthelloGame, { pack as packGame } from '../../../../models/othello-game';
import User from '../../../../models/user';
@@ -7,7 +7,7 @@ import { eighteight } from '../../../../othello/maps';
module.exports = (params, user) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [childId, childIdErr] = $(params.userId).id().$;
+ const [childId, childIdErr] = $.type(ID).get(params.userId);
if (childIdErr) return rej('invalid userId param');
// Myself
diff --git a/src/server/api/endpoints/stats.ts b/src/server/api/endpoints/stats.ts
index 52e5195484..d1e17651f2 100644
--- a/src/server/api/endpoints/stats.ts
+++ b/src/server/api/endpoints/stats.ts
@@ -1,48 +1,26 @@
-/**
- * Module dependencies
- */
import Note from '../../../models/note';
import User from '../../../models/user';
/**
- * @swagger
- * /stats:
- * note:
- * summary: Show the misskey's statistics
- * responses:
- * 200:
- * description: Success
- * schema:
- * type: object
- * properties:
- * notesCount:
- * description: count of all notes of misskey
- * type: number
- * usersCount:
- * description: count of all users of misskey
- * type: number
- *
- * default:
- * description: Failed
- * schema:
- * $ref: "#/definitions/Error"
- */
-
-/**
- * Show the misskey's statistics
- *
- * @param {any} params
- * @return {Promise<any>}
+ * Get the misskey's statistics
*/
module.exports = params => new Promise(async (res, rej) => {
- const notesCount = await Note
- .count();
+ const notesCount = await Note.count();
- const usersCount = await User
- .count();
+ const usersCount = await User.count();
+
+ const originalNotesCount = await Note.count({
+ '_user.host': null
+ });
+
+ const originalUsersCount = await User.count({
+ host: null
+ });
res({
- notesCount: notesCount,
- usersCount: usersCount
+ notesCount,
+ usersCount,
+ originalNotesCount,
+ originalUsersCount
});
});
diff --git a/src/server/api/endpoints/sw/register.ts b/src/server/api/endpoints/sw/register.ts
index 3fe0bda4ee..b22a8b08ef 100644
--- a/src/server/api/endpoints/sw/register.ts
+++ b/src/server/api/endpoints/sw/register.ts
@@ -9,15 +9,15 @@ import Subscription from '../../../../models/sw-subscription';
*/
module.exports = async (params, user, app) => new Promise(async (res, rej) => {
// Get 'endpoint' parameter
- const [endpoint, endpointErr] = $(params.endpoint).string().$;
+ const [endpoint, endpointErr] = $.str.get(params.endpoint);
if (endpointErr) return rej('invalid endpoint param');
// Get 'auth' parameter
- const [auth, authErr] = $(params.auth).string().$;
+ const [auth, authErr] = $.str.get(params.auth);
if (authErr) return rej('invalid auth param');
// Get 'publickey' parameter
- const [publickey, publickeyErr] = $(params.publickey).string().$;
+ const [publickey, publickeyErr] = $.str.get(params.publickey);
if (publickeyErr) return rej('invalid publickey param');
// if already subscribed
diff --git a/src/server/api/endpoints/username/available.ts b/src/server/api/endpoints/username/available.ts
index bd27c37de0..b11bec4e58 100644
--- a/src/server/api/endpoints/username/available.ts
+++ b/src/server/api/endpoints/username/available.ts
@@ -13,7 +13,7 @@ import { validateUsername } from '../../../../models/user';
*/
module.exports = async (params) => new Promise(async (res, rej) => {
// Get 'username' parameter
- const [username, usernameError] = $(params.username).string().pipe(validateUsername).$;
+ const [username, usernameError] = $.str.pipe(validateUsername).get(params.username);
if (usernameError) return rej('invalid username param');
// Get exist
diff --git a/src/server/api/endpoints/users.ts b/src/server/api/endpoints/users.ts
index ae33e8af0c..eb581cb7e6 100644
--- a/src/server/api/endpoints/users.ts
+++ b/src/server/api/endpoints/users.ts
@@ -6,22 +6,18 @@ import User, { pack } from '../../../models/user';
/**
* Lists all users
- *
- * @param {any} params
- * @param {any} me
- * @return {Promise<any>}
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Get 'sort' parameter
- const [sort, sortError] = $(params.sort).optional.string().or('+follower|-follower').$;
+ const [sort, sortError] = $.str.optional().or('+follower|-follower').get(params.sort);
if (sortError) return rej('invalid sort param');
// Construct query
diff --git a/src/server/api/endpoints/users/followers.ts b/src/server/api/endpoints/users/followers.ts
index 0222313e81..810cd7341b 100644
--- a/src/server/api/endpoints/users/followers.ts
+++ b/src/server/api/endpoints/users/followers.ts
@@ -1,34 +1,30 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import User from '../../../../models/user';
import Following from '../../../../models/following';
import { pack } from '../../../../models/user';
-import getFriends from '../../common/get-friends';
+import { getFriendIds } from '../../common/get-friends';
/**
* Get followers of a user
- *
- * @param {any} params
- * @param {any} me
- * @return {Promise<any>}
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Get 'iknow' parameter
- const [iknow = false, iknowErr] = $(params.iknow).optional.boolean().$;
+ const [iknow = false, iknowErr] = $.bool.optional().get(params.iknow);
if (iknowErr) return rej('invalid iknow param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'cursor' parameter
- const [cursor = null, cursorErr] = $(params.cursor).optional.id().$;
+ const [cursor = null, cursorErr] = $.type(ID).optional().get(params.cursor);
if (cursorErr) return rej('invalid cursor param');
// Lookup user
@@ -52,7 +48,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
// ログインしていてかつ iknow フラグがあるとき
if (me && iknow) {
// Get my friends
- const myFriends = await getFriends(me._id);
+ const myFriends = await getFriendIds(me._id);
query.followerId = {
$in: myFriends
diff --git a/src/server/api/endpoints/users/following.ts b/src/server/api/endpoints/users/following.ts
index 2372f57fbe..3373b9d632 100644
--- a/src/server/api/endpoints/users/following.ts
+++ b/src/server/api/endpoints/users/following.ts
@@ -1,11 +1,11 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import User from '../../../../models/user';
import Following from '../../../../models/following';
import { pack } from '../../../../models/user';
-import getFriends from '../../common/get-friends';
+import { getFriendIds } from '../../common/get-friends';
/**
* Get following users of a user
@@ -16,19 +16,19 @@ import getFriends from '../../common/get-friends';
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Get 'iknow' parameter
- const [iknow = false, iknowErr] = $(params.iknow).optional.boolean().$;
+ const [iknow = false, iknowErr] = $.bool.optional().get(params.iknow);
if (iknowErr) return rej('invalid iknow param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'cursor' parameter
- const [cursor = null, cursorErr] = $(params.cursor).optional.id().$;
+ const [cursor = null, cursorErr] = $.type(ID).optional().get(params.cursor);
if (cursorErr) return rej('invalid cursor param');
// Lookup user
@@ -52,7 +52,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
// ログインしていてかつ iknow フラグがあるとき
if (me && iknow) {
// Get my friends
- const myFriends = await getFriends(me._id);
+ const myFriends = await getFriendIds(me._id);
query.followeeId = {
$in: myFriends
diff --git a/src/server/api/endpoints/users/get_frequently_replied_users.ts b/src/server/api/endpoints/users/get_frequently_replied_users.ts
index 7a98f44e98..64d737a06b 100644
--- a/src/server/api/endpoints/users/get_frequently_replied_users.ts
+++ b/src/server/api/endpoints/users/get_frequently_replied_users.ts
@@ -1,17 +1,17 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import Note from '../../../../models/note';
import User, { pack } from '../../../../models/user';
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).id().$;
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Lookup user
diff --git a/src/server/api/endpoints/users/lists/create.ts b/src/server/api/endpoints/users/lists/create.ts
new file mode 100644
index 0000000000..100a78b872
--- /dev/null
+++ b/src/server/api/endpoints/users/lists/create.ts
@@ -0,0 +1,25 @@
+/**
+ * Module dependencies
+ */
+import $ from 'cafy';
+import UserList, { pack } from '../../../../../models/user-list';
+
+/**
+ * Create a user list
+ */
+module.exports = async (params, user) => new Promise(async (res, rej) => {
+ // Get 'title' parameter
+ const [title, titleErr] = $.str.range(1, 100).get(params.title);
+ if (titleErr) return rej('invalid title param');
+
+ // insert
+ const userList = await UserList.insert({
+ createdAt: new Date(),
+ userId: user._id,
+ title: title,
+ userIds: []
+ });
+
+ // Response
+ res(await pack(userList));
+});
diff --git a/src/server/api/endpoints/users/lists/list.ts b/src/server/api/endpoints/users/lists/list.ts
new file mode 100644
index 0000000000..d19339a1f5
--- /dev/null
+++ b/src/server/api/endpoints/users/lists/list.ts
@@ -0,0 +1,13 @@
+import UserList, { pack } from '../../../../../models/user-list';
+
+/**
+ * Add a user to a user list
+ */
+module.exports = async (params, me) => new Promise(async (res, rej) => {
+ // Fetch lists
+ const userLists = await UserList.find({
+ userId: me._id,
+ });
+
+ res(await Promise.all(userLists.map(x => pack(x))));
+});
diff --git a/src/server/api/endpoints/users/lists/push.ts b/src/server/api/endpoints/users/lists/push.ts
new file mode 100644
index 0000000000..da5a9a134c
--- /dev/null
+++ b/src/server/api/endpoints/users/lists/push.ts
@@ -0,0 +1,61 @@
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
+import UserList from '../../../../../models/user-list';
+import User, { pack as packUser, isRemoteUser, getGhost } from '../../../../../models/user';
+import { publishUserListStream } from '../../../../../publishers/stream';
+import ap from '../../../../../remote/activitypub/renderer';
+import renderFollow from '../../../../../remote/activitypub/renderer/follow';
+import { deliver } from '../../../../../queue';
+
+/**
+ * Add a user to a user list
+ */
+module.exports = async (params, me) => new Promise(async (res, rej) => {
+ // Get 'listId' parameter
+ const [listId, listIdErr] = $.type(ID).get(params.listId);
+ if (listIdErr) return rej('invalid listId param');
+
+ // Fetch the list
+ const userList = await UserList.findOne({
+ _id: listId,
+ userId: me._id,
+ });
+
+ if (userList == null) {
+ return rej('list not found');
+ }
+
+ // Get 'userId' parameter
+ const [userId, userIdErr] = $.type(ID).get(params.userId);
+ if (userIdErr) return rej('invalid userId param');
+
+ // Fetch the user
+ const user = await User.findOne({
+ _id: userId
+ });
+
+ if (user == null) {
+ return rej('user not found');
+ }
+
+ if (userList.userIds.map(id => id.toHexString()).includes(user._id.toHexString())) {
+ return rej('the user already added');
+ }
+
+ // Push the user
+ await UserList.update({ _id: userList._id }, {
+ $push: {
+ userIds: user._id
+ }
+ });
+
+ res();
+
+ publishUserListStream(userList._id, 'userAdded', await packUser(user));
+
+ // このインスタンス内にこのリモートユーザーをフォローしているユーザーがいなくても投稿を受け取るためにダミーのユーザーがフォローしたということにする
+ if (isRemoteUser(user)) {
+ const ghost = await getGhost();
+ const content = ap(renderFollow(ghost, user));
+ deliver(ghost, content, user.inbox);
+ }
+});
diff --git a/src/server/api/endpoints/users/lists/show.ts b/src/server/api/endpoints/users/lists/show.ts
new file mode 100644
index 0000000000..16cb3382fd
--- /dev/null
+++ b/src/server/api/endpoints/users/lists/show.ts
@@ -0,0 +1,23 @@
+import $ from 'cafy'; import ID from '../../../../../cafy-id';
+import UserList, { pack } from '../../../../../models/user-list';
+
+/**
+ * Show a user list
+ */
+module.exports = async (params, me) => new Promise(async (res, rej) => {
+ // Get 'listId' parameter
+ const [listId, listIdErr] = $.type(ID).get(params.listId);
+ if (listIdErr) return rej('invalid listId param');
+
+ // Fetch the list
+ const userList = await UserList.findOne({
+ _id: listId,
+ userId: me._id,
+ });
+
+ if (userList == null) {
+ return rej('list not found');
+ }
+
+ res(await pack(userList));
+});
diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts
index bd4247c79c..061c363d0f 100644
--- a/src/server/api/endpoints/users/notes.ts
+++ b/src/server/api/endpoints/users/notes.ts
@@ -1,7 +1,7 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import getHostLower from '../../common/get-host-lower';
import Note, { pack } from '../../../../models/note';
import User from '../../../../models/user';
@@ -11,11 +11,11 @@ import User from '../../../../models/user';
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).optional.id().$;
+ const [userId, userIdErr] = $.type(ID).optional().get(params.userId);
if (userIdErr) return rej('invalid userId param');
// Get 'username' parameter
- const [username, usernameErr] = $(params.username).optional.string().$;
+ const [username, usernameErr] = $.str.optional().get(params.username);
if (usernameErr) return rej('invalid username param');
if (userId === undefined && username === undefined) {
@@ -23,7 +23,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
}
// Get 'host' parameter
- const [host, hostErr] = $(params.host).optional.string().$;
+ const [host, hostErr] = $.str.optional().get(params.host);
if (hostErr) return rej('invalid host param');
if (userId === undefined && host === undefined) {
@@ -31,31 +31,31 @@ module.exports = (params, me) => new Promise(async (res, rej) => {
}
// Get 'includeReplies' parameter
- const [includeReplies = true, includeRepliesErr] = $(params.includeReplies).optional.boolean().$;
+ const [includeReplies = true, includeRepliesErr] = $.bool.optional().get(params.includeReplies);
if (includeRepliesErr) return rej('invalid includeReplies param');
// Get 'withMedia' parameter
- const [withMedia = false, withMediaErr] = $(params.withMedia).optional.boolean().$;
+ const [withMedia = false, withMediaErr] = $.bool.optional().get(params.withMedia);
if (withMediaErr) return rej('invalid withMedia param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'sinceId' parameter
- const [sinceId, sinceIdErr] = $(params.sinceId).optional.id().$;
+ const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
if (sinceIdErr) return rej('invalid sinceId param');
// Get 'untilId' parameter
- const [untilId, untilIdErr] = $(params.untilId).optional.id().$;
+ const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
if (untilIdErr) return rej('invalid untilId param');
// Get 'sinceDate' parameter
- const [sinceDate, sinceDateErr] = $(params.sinceDate).optional.number().$;
+ const [sinceDate, sinceDateErr] = $.num.optional().get(params.sinceDate);
if (sinceDateErr) throw 'invalid sinceDate param';
// Get 'untilDate' parameter
- const [untilDate, untilDateErr] = $(params.untilDate).optional.number().$;
+ const [untilDate, untilDateErr] = $.num.optional().get(params.untilDate);
if (untilDateErr) throw 'invalid untilDate param';
// Check if only one of sinceId, untilId, sinceDate, untilDate specified
diff --git a/src/server/api/endpoints/users/recommendation.ts b/src/server/api/endpoints/users/recommendation.ts
index e367e65a6c..620ae17ca2 100644
--- a/src/server/api/endpoints/users/recommendation.ts
+++ b/src/server/api/endpoints/users/recommendation.ts
@@ -4,7 +4,8 @@
const ms = require('ms');
import $ from 'cafy';
import User, { pack } from '../../../../models/user';
-import getFriends from '../../common/get-friends';
+import { getFriendIds } from '../../common/get-friends';
+import Mute from '../../../../models/mute';
/**
* Get recommended users
@@ -15,23 +16,28 @@ import getFriends from '../../common/get-friends';
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// ID list of the user itself and other users who the user follows
- const followingIds = await getFriends(me._id);
+ const followingIds = await getFriendIds(me._id);
+
+ // ミュートしているユーザーを取得
+ const mutedUserIds = (await Mute.find({
+ muterId: me._id
+ })).map(m => m.muteeId);
const users = await User
.find({
_id: {
- $nin: followingIds
+ $nin: followingIds.concat(mutedUserIds)
},
$or: [{
- 'lastUsedAt': {
+ lastUsedAt: {
$gte: new Date(Date.now() - ms('7days'))
}
}, {
diff --git a/src/server/api/endpoints/users/search.ts b/src/server/api/endpoints/users/search.ts
index da30f47c2a..cfbdc337bf 100644
--- a/src/server/api/endpoints/users/search.ts
+++ b/src/server/api/endpoints/users/search.ts
@@ -16,15 +16,15 @@ const escapeRegexp = require('escape-regexp');
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'query' parameter
- const [query, queryError] = $(params.query).string().pipe(x => x != '').$;
+ const [query, queryError] = $.str.pipe(x => x != '').get(params.query);
if (queryError) return rej('invalid query param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Get 'max' parameter
- const [max = 10, maxErr] = $(params.max).optional.number().range(1, 30).$;
+ const [max = 10, maxErr] = $.num.optional().range(1, 30).get(params.max);
if (maxErr) return rej('invalid max param');
// If Elasticsearch is available, search by $
diff --git a/src/server/api/endpoints/users/search_by_username.ts b/src/server/api/endpoints/users/search_by_username.ts
index 5f6ececff9..5927d00faf 100644
--- a/src/server/api/endpoints/users/search_by_username.ts
+++ b/src/server/api/endpoints/users/search_by_username.ts
@@ -6,22 +6,18 @@ import User, { pack } from '../../../../models/user';
/**
* Search a user by username
- *
- * @param {any} params
- * @param {any} me
- * @return {Promise<any>}
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
// Get 'query' parameter
- const [query, queryError] = $(params.query).string().$;
+ const [query, queryError] = $.str.get(params.query);
if (queryError) return rej('invalid query param');
// Get 'offset' parameter
- const [offset = 0, offsetErr] = $(params.offset).optional.number().min(0).$;
+ const [offset = 0, offsetErr] = $.num.optional().min(0).get(params.offset);
if (offsetErr) return rej('invalid offset param');
// Get 'limit' parameter
- const [limit = 10, limitErr] = $(params.limit).optional.number().range(1, 100).$;
+ const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
if (limitErr) return rej('invalid limit param');
const users = await User
diff --git a/src/server/api/endpoints/users/show.ts b/src/server/api/endpoints/users/show.ts
index 7e7f5dc488..b8c6ff25c4 100644
--- a/src/server/api/endpoints/users/show.ts
+++ b/src/server/api/endpoints/users/show.ts
@@ -1,56 +1,68 @@
/**
* Module dependencies
*/
-import $ from 'cafy';
+import $ from 'cafy'; import ID from '../../../../cafy-id';
import User, { pack } from '../../../../models/user';
import resolveRemoteUser from '../../../../remote/resolve-user';
const cursorOption = { fields: { data: false } };
/**
- * Show a user
+ * Show user(s)
*/
module.exports = (params, me) => new Promise(async (res, rej) => {
let user;
// Get 'userId' parameter
- const [userId, userIdErr] = $(params.userId).optional.id().$;
+ const [userId, userIdErr] = $.type(ID).optional().get(params.userId);
if (userIdErr) return rej('invalid userId param');
+ // Get 'userIds' parameter
+ const [userIds, userIdsErr] = $.arr($.type(ID)).optional().get(params.userIds);
+ if (userIdsErr) return rej('invalid userIds param');
+
// Get 'username' parameter
- const [username, usernameErr] = $(params.username).optional.string().$;
+ const [username, usernameErr] = $.str.optional().get(params.username);
if (usernameErr) return rej('invalid username param');
// Get 'host' parameter
- const [host, hostErr] = $(params.host).nullable.optional.string().$;
+ const [host, hostErr] = $.str.optional().nullable().get(params.host);
if (hostErr) return rej('invalid host param');
- if (userId === undefined && typeof username !== 'string') {
- return rej('userId or pair of username and host is required');
- }
+ if (userIds) {
+ const users = await User.find({
+ _id: {
+ $in: userIds
+ }
+ });
- // Lookup user
- if (typeof host === 'string') {
- try {
- user = await resolveRemoteUser(username, host, cursorOption);
- } catch (e) {
- console.warn(`failed to resolve remote user: ${e}`);
- return rej('failed to resolve remote user');
- }
+ res(await Promise.all(users.map(u => pack(u, me, {
+ detail: true
+ }))));
} else {
- const q = userId !== undefined
- ? { _id: userId }
- : { usernameLower: username.toLowerCase(), host: null };
+ // Lookup user
+ if (typeof host === 'string') {
+ try {
+ user = await resolveRemoteUser(username, host, cursorOption);
+ } catch (e) {
+ console.warn(`failed to resolve remote user: ${e}`);
+ return rej('failed to resolve remote user');
+ }
+ } else {
+ const q = userId !== undefined
+ ? { _id: userId }
+ : { usernameLower: username.toLowerCase(), host: null };
- user = await User.findOne(q, cursorOption);
+ user = await User.findOne(q, cursorOption);
- if (user === null) {
- return rej('user not found');
+ if (user === null) {
+ return rej('user not found');
+ }
}
- }
- // Send response
- res(await pack(user, me, {
- detail: true
- }));
+ // Send response
+ res(await pack(user, me, {
+ detail: true
+ }));
+ }
});
diff --git a/src/server/api/stream/home.ts b/src/server/api/stream/home.ts
index a9d6ff241e..54fde2d776 100644
--- a/src/server/api/stream/home.ts
+++ b/src/server/api/stream/home.ts
@@ -32,17 +32,17 @@ export default async function(
//#region 流れてきたメッセージがミュートしているユーザーが関わるものだったら無視する
if (x.type == 'note') {
- if (mutedUserIds.indexOf(x.body.userId) != -1) {
+ if (mutedUserIds.includes(x.body.userId)) {
return;
}
- if (x.body.reply != null && mutedUserIds.indexOf(x.body.reply.userId) != -1) {
+ if (x.body.reply != null && mutedUserIds.includes(x.body.reply.userId)) {
return;
}
- if (x.body.renote != null && mutedUserIds.indexOf(x.body.renote.userId) != -1) {
+ if (x.body.renote != null && mutedUserIds.includes(x.body.renote.userId)) {
return;
}
} else if (x.type == 'notification') {
- if (mutedUserIds.indexOf(x.body.userId) != -1) {
+ if (mutedUserIds.includes(x.body.userId)) {
return;
}
}
@@ -53,6 +53,7 @@ export default async function(
connection.send(data);
}
break;
+
case 'note-stream':
const noteId = channel.split(':')[2];
log(`RECEIVED: ${noteId} ${data} by @${user.username}`);
@@ -69,12 +70,13 @@ export default async function(
}
});
- connection.on('message', data => {
+ connection.on('message', async data => {
const msg = JSON.parse(data.utf8Data);
switch (msg.type) {
case 'api':
- call(msg.endpoint, user, app, msg.data).then(res => {
+ // 新鮮なデータを利用するためにユーザーをフェッチ
+ call(msg.endpoint, await User.findOne({ _id: user._id }), app, msg.data).then(res => {
connection.send(JSON.stringify({
type: `api-res:${msg.id}`,
body: { res }
diff --git a/src/server/api/stream/user-list.ts b/src/server/api/stream/user-list.ts
new file mode 100644
index 0000000000..ba03b97860
--- /dev/null
+++ b/src/server/api/stream/user-list.ts
@@ -0,0 +1,14 @@
+import * as websocket from 'websocket';
+import * as redis from 'redis';
+import { ParsedUrlQuery } from 'querystring';
+
+export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void {
+ const q = request.resourceURL.query as ParsedUrlQuery;
+ const listId = q.listId as string;
+
+ // Subscribe stream
+ subscriber.subscribe(`misskey:user-list-stream:${listId}`);
+ subscriber.on('message', (_, data) => {
+ connection.send(data);
+ });
+}
diff --git a/src/server/api/streaming.ts b/src/server/api/streaming.ts
index ce13253649..e4884ed7c4 100644
--- a/src/server/api/streaming.ts
+++ b/src/server/api/streaming.ts
@@ -6,6 +6,7 @@ import config from '../../config';
import homeStream from './stream/home';
import localTimelineStream from './stream/local-timeline';
import globalTimelineStream from './stream/global-timeline';
+import userListStream from './stream/user-list';
import driveStream from './stream/drive';
import messagingStream from './stream/messaging';
import messagingIndexStream from './stream/messaging-index';
@@ -70,6 +71,7 @@ module.exports = (server: http.Server) => {
request.resourceURL.pathname === '/' ? homeStream :
request.resourceURL.pathname === '/local-timeline' ? localTimelineStream :
request.resourceURL.pathname === '/global-timeline' ? globalTimelineStream :
+ request.resourceURL.pathname === '/user-list' ? userListStream :
request.resourceURL.pathname === '/drive' ? driveStream :
request.resourceURL.pathname === '/messaging' ? messagingStream :
request.resourceURL.pathname === '/messaging-index' ? messagingIndexStream :
diff --git a/src/server/file/assets/cache-expired.png b/src/server/file/assets/cache-expired.png
new file mode 100644
index 0000000000..ea681af0a0
--- /dev/null
+++ b/src/server/file/assets/cache-expired.png
Binary files differ
diff --git a/src/server/file/assets/tombstone.png b/src/server/file/assets/tombstone.png
new file mode 100644
index 0000000000..86224e3182
--- /dev/null
+++ b/src/server/file/assets/tombstone.png
Binary files differ
diff --git a/src/server/file/index.ts b/src/server/file/index.ts
index 29056c63e7..973528da33 100644
--- a/src/server/file/index.ts
+++ b/src/server/file/index.ts
@@ -6,7 +6,6 @@ import * as fs from 'fs';
import * as Koa from 'koa';
import * as cors from '@koa/cors';
import * as Router from 'koa-router';
-import pour from './pour';
import sendDriveFile from './send-drive-file';
// Init app
@@ -24,12 +23,14 @@ const router = new Router();
router.get('/default-avatar.jpg', ctx => {
const file = fs.createReadStream(`${__dirname}/assets/avatar.jpg`);
- pour(file, 'image/jpeg', ctx);
+ ctx.set('Content-Type', 'image/jpeg');
+ ctx.body = file;
});
router.get('/app-default.jpg', ctx => {
const file = fs.createReadStream(`${__dirname}/assets/dummy.png`);
- pour(file, 'image/png', ctx);
+ ctx.set('Content-Type', 'image/jpeg');
+ ctx.body = file;
});
router.get('/:id', sendDriveFile);
diff --git a/src/server/file/pour.ts b/src/server/file/pour.ts
deleted file mode 100644
index 0fd0ad0e60..0000000000
--- a/src/server/file/pour.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import * as fs from 'fs';
-import * as stream from 'stream';
-import * as Koa from 'koa';
-import * as Gm from 'gm';
-
-const gm = Gm.subClass({
- imageMagick: true
-});
-
-interface ISend {
- contentType: string;
- stream: stream.Readable;
-}
-
-function thumbnail(data: stream.Readable, type: string, resize: number): ISend {
- const readable: stream.Readable = (() => {
- // 動画であれば
- if (/^video\/.*$/.test(type)) {
- // TODO
- // 使わないことになったストリームはしっかり取り壊す
- data.destroy();
- return fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`);
- // 画像であれば
- // Note: SVGはapplication/xml
- } else if (/^image\/.*$/.test(type) || type == 'application/xml') {
- // 0フレーム目を送る
- try {
- return gm(data).selectFrame(0).stream();
- // だめだったら
- } catch (e) {
- // 使わないことになったストリームはしっかり取り壊す
- data.destroy();
- return fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`);
- }
- // 動画か画像以外
- } else {
- data.destroy();
- return fs.createReadStream(`${__dirname}/assets/not-an-image.png`);
- }
- })();
-
- let g = gm(readable);
-
- if (resize) {
- g = g.resize(resize, resize);
- }
-
- const stream = g
- .compress('jpeg')
- .quality(80)
- .interlace('line')
- .stream();
-
- return {
- contentType: 'image/jpeg',
- stream
- };
-}
-
-const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void => {
- console.error(e);
- ctx.status = 500;
-};
-
-export default function(readable: stream.Readable, type: string, ctx: Koa.Context): void {
- readable.on('error', commonReadableHandlerGenerator(ctx));
-
- const data = ((): ISend => {
- if (ctx.query.thumbnail !== undefined) {
- return thumbnail(readable, type, ctx.query.size);
- }
- return {
- contentType: type,
- stream: readable
- };
- })();
-
- if (readable !== data.stream) {
- data.stream.on('error', commonReadableHandlerGenerator(ctx));
- }
-
- if (ctx.query.download !== undefined) {
- ctx.set('Content-Disposition', 'attachment');
- }
-
- ctx.set('Content-Type', data.contentType);
- ctx.body = data.stream;
-}
diff --git a/src/server/file/send-drive-file.ts b/src/server/file/send-drive-file.ts
index e6ee19ff1d..d613a3aa5f 100644
--- a/src/server/file/send-drive-file.ts
+++ b/src/server/file/send-drive-file.ts
@@ -1,8 +1,17 @@
+import * as fs from 'fs';
+
import * as Koa from 'koa';
import * as send from 'koa-send';
import * as mongodb from 'mongodb';
-import DriveFile, { getGridFSBucket } from '../../models/drive-file';
-import pour from './pour';
+import DriveFile, { getDriveFileBucket } from '../../models/drive-file';
+import DriveFileThumbnail, { getDriveFileThumbnailBucket } from '../../models/drive-file-thumbnail';
+
+const assets = `${__dirname}/../../server/file/assets/`;
+
+const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void => {
+ console.error(e);
+ ctx.status = 500;
+};
export default async function(ctx: Koa.Context) {
// Validate id
@@ -18,13 +27,52 @@ export default async function(ctx: Koa.Context) {
if (file == null) {
ctx.status = 404;
- await send(ctx, `${__dirname}/assets/dummy.png`);
+ await send(ctx, '/dummy.png', { root: assets });
return;
}
- const bucket = await getGridFSBucket();
+ if (file.metadata.deletedAt) {
+ ctx.status = 410;
+ if (file.metadata.isExpired) {
+ await send(ctx, '/cache-expired.png', { root: assets });
+ } else {
+ await send(ctx, '/tombstone.png', { root: assets });
+ }
+ return;
+ }
+
+ const sendRaw = async () => {
+ const bucket = await getDriveFileBucket();
+ const readable = bucket.openDownloadStream(fileId);
+ readable.on('error', commonReadableHandlerGenerator(ctx));
+ ctx.set('Content-Type', file.contentType);
+ ctx.body = readable;
+ };
- const readable = bucket.openDownloadStream(fileId);
+ if ('thumbnail' in ctx.query) {
+ // 画像以外
+ if (!file.contentType.startsWith('image/')) {
+ const readable = fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`);
+ ctx.set('Content-Type', 'image/png');
+ ctx.body = readable;
+ } else if (file.contentType == 'image/gif') {
+ // GIF
+ await sendRaw();
+ } else {
+ const thumb = await DriveFileThumbnail.findOne({ 'metadata.originalId': fileId });
+ if (thumb != null) {
+ ctx.set('Content-Type', 'image/jpeg');
+ const bucket = await getDriveFileThumbnailBucket();
+ ctx.body = bucket.openDownloadStream(thumb._id);
+ } else {
+ await sendRaw();
+ }
+ }
+ } else {
+ if ('download' in ctx.query) {
+ ctx.set('Content-Disposition', 'attachment');
+ }
- pour(readable, file.contentType, ctx);
+ await sendRaw();
+ }
}
diff --git a/src/server/index.ts b/src/server/index.ts
index 5db3da2b93..ded8f7706e 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -4,12 +4,15 @@
import * as fs from 'fs';
import * as http from 'http';
-import * as http2 from 'http2';
+import * as https from 'https';
+//import * as http2 from 'http2';
import * as zlib from 'zlib';
import * as Koa from 'koa';
import * as Router from 'koa-router';
import * as mount from 'koa-mount';
import * as compress from 'koa-compress';
+import * as logger from 'koa-logger';
+//const slow = require('koa-slow');
import activityPub from './activitypub';
import webFinger from './webfinger';
@@ -19,6 +22,17 @@ import config from '../config';
const app = new Koa();
app.proxy = true;
+if (process.env.NODE_ENV != 'production') {
+ // Logger
+ app.use(logger());
+
+ // Delay
+ //app.use(slow({
+ // delay: 1000
+ //}));
+}
+
+// Compress response
app.use(compress({
flush: zlib.constants.Z_SYNC_FLUSH
}));
@@ -54,7 +68,8 @@ function createServer() {
certs[k] = fs.readFileSync(config.https[k]);
});
certs['allowHTTP1'] = true;
- return http2.createSecureServer(certs, app.callback());
+ //return http2.createSecureServer(certs, app.callback());
+ return https.createServer(certs, app.callback());
} else {
return http.createServer(app.callback());
}
diff --git a/src/server/web/index.ts b/src/server/web/index.ts
index eba0c372b0..6ceef17c1c 100644
--- a/src/server/web/index.ts
+++ b/src/server/web/index.ts
@@ -7,14 +7,32 @@ import * as Koa from 'koa';
import * as Router from 'koa-router';
import * as send from 'koa-send';
import * as favicon from 'koa-favicon';
+import * as views from 'koa-views';
import docs from './docs';
+import User from '../../models/user';
+import parseAcct from '../../acct/parse';
+import { fa } from '../../build/fa';
+import config from '../../config';
+import Note, { pack as packNote } from '../../models/note';
+import getNoteSummary from '../../renderers/get-note-summary';
+const consts = require('../../const.json');
const client = `${__dirname}/../../client/`;
// Init app
const app = new Koa();
+// Init renderer
+app.use(views(__dirname + '/views', {
+ extension: 'pug',
+ options: {
+ config,
+ themeColor: consts.themeColor,
+ facss: fa.dom.css()
+ }
+}));
+
// Serve favicon
app.use(favicon(`${client}/assets/favicon.ico`));
@@ -42,17 +60,21 @@ router.get('/assets/*', async ctx => {
// Apple touch icon
router.get('/apple-touch-icon.png', async ctx => {
- await send(ctx, `${client}/assets/apple-touch-icon.png`);
+ await send(ctx, '/assets/apple-touch-icon.png', {
+ root: client
+ });
});
// ServiceWroker
-router.get(/^\/sw\.(.+?)\.js$/, async ctx => {
- await send(ctx, `${client}/assets/sw.${ctx.params[0]}.js`);
-});
+//router.get(/^\/sw\.(.+?)\.js$/, async ctx => {
+// await send(ctx, `${client}/assets/sw.${ctx.params[0]}.js`);
+//});
// Manifest
router.get('/manifest.json', async ctx => {
- await send(ctx, `${client}/assets/manifest.json`);
+ await send(ctx, '/assets/manifest.json', {
+ root: client
+ });
});
//#endregion
@@ -61,7 +83,40 @@ router.get('/manifest.json', async ctx => {
router.use('/docs', docs.routes());
// URL preview endpoint
-router.get('url', require('./url-preview'));
+router.get('/url', require('./url-preview'));
+
+//#region for crawlers
+// User
+router.get('/@:user', async (ctx, next) => {
+ const { username, host } = parseAcct(ctx.params.user);
+ const user = await User.findOne({
+ usernameLower: username.toLowerCase(),
+ host
+ });
+
+ if (user != null) {
+ await ctx.render('user', { user });
+ } else {
+ // リモートユーザーなので
+ await next();
+ }
+});
+
+// Note
+router.get('/notes/:note', async ctx => {
+ const note = await Note.findOne({ _id: ctx.params.note });
+
+ if (note != null) {
+ const _note = await packNote(note);
+ await ctx.render('note', {
+ note: _note,
+ summary: getNoteSummary(_note)
+ });
+ } else {
+ ctx.status = 404;
+ }
+});
+//#endregion
// Render base html for all requests
router.get('*', async ctx => {
diff --git a/src/server/web/url-preview.ts b/src/server/web/url-preview.ts
index d5464d0cd4..cd53837a25 100644
--- a/src/server/web/url-preview.ts
+++ b/src/server/web/url-preview.ts
@@ -14,6 +14,8 @@ module.exports = async (ctx: Koa.Context) => {
function wrap(url: string): string {
return url != null
- ? `https://images.weserv.nl/?url=${url.replace(/^https?:\/\//, '')}`
+ ? url.startsWith('https://') || url.startsWith('data:')
+ ? url
+ : `https://images.weserv.nl/?url=${encodeURIComponent(url.replace(/^http:\/\//, ''))}`
: null;
}
diff --git a/src/server/web/views/note.pug b/src/server/web/views/note.pug
new file mode 100644
index 0000000000..22f1834059
--- /dev/null
+++ b/src/server/web/views/note.pug
@@ -0,0 +1,25 @@
+extends ../../../../src/client/app/base
+
+block vars
+ - const user = note.user;
+ - const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`;
+ - const url = `${config.url}/notes/${note.id}`;
+
+block title
+ = `${title} | Misskey`
+
+block desc
+ meta(name='description' content= summary)
+
+block meta
+ meta(name='twitter:card' content='summary')
+ meta(property='og:type' content='article')
+ meta(property='og:title' content= title)
+ meta(property='og:description' content= summary)
+ meta(property='og:url' content= url)
+ meta(property='og:image' content= user.avatarUrl)
+
+ if note.prev
+ link(rel='prev' href=`${config.url}/notes/${note.prev}`)
+ if note.next
+ link(rel='next' href=`${config.url}/notes/${note.next}`)
diff --git a/src/server/web/views/user.pug b/src/server/web/views/user.pug
new file mode 100644
index 0000000000..b5ea2f6eb4
--- /dev/null
+++ b/src/server/web/views/user.pug
@@ -0,0 +1,20 @@
+extends ../../../../src/client/app/base
+
+block vars
+ - const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`;
+ - const url = config.url + '/@' + (user.host ? `${user.username}@${user.host}` : user.username);
+ - const img = user.avatarId ? `${config.drive_url}/${user.avatarId}` : null;
+
+block title
+ = `${title} | Misskey`
+
+block desc
+ meta(name='description' content= user.description)
+
+block meta
+ meta(name='twitter:card' content='summary')
+ meta(property='og:type' content='blog')
+ meta(property='og:title' content= title)
+ meta(property='og:description' content= user.description)
+ meta(property='og:url' content= url)
+ meta(property='og:image' content= img)
diff --git a/src/server/webfinger.ts b/src/server/webfinger.ts
index e72592351b..ce0cb82fe2 100644
--- a/src/server/webfinger.ts
+++ b/src/server/webfinger.ts
@@ -1,8 +1,9 @@
+import * as mongo from 'mongodb';
import * as Router from 'koa-router';
import config from '../config';
import parseAcct from '../acct/parse';
-import User from '../models/user';
+import User, { IUser } from '../models/user';
// Init router
const router = new Router();
@@ -14,27 +15,38 @@ router.get('/.well-known/webfinger', async ctx => {
}
const resourceLower = ctx.query.resource.toLowerCase();
- const webPrefix = config.url.toLowerCase() + '/@';
let acctLower;
+ let id;
- if (resourceLower.startsWith(webPrefix)) {
- acctLower = resourceLower.slice(webPrefix.length);
+ if (resourceLower.startsWith(config.url.toLowerCase() + '/@')) {
+ acctLower = resourceLower.split('/').pop();
+ } else if (resourceLower.startsWith(config.url.toLowerCase() + '/users/')) {
+ id = new mongo.ObjectID(resourceLower.split('/').pop());
} else if (resourceLower.startsWith('acct:')) {
acctLower = resourceLower.slice('acct:'.length);
} else {
acctLower = resourceLower;
}
- const parsedAcctLower = parseAcct(acctLower);
- if (![null, config.host.toLowerCase()].includes(parsedAcctLower.host)) {
- ctx.status = 422;
- return;
- }
+ let user: IUser;
+
+ if (acctLower) {
+ const parsedAcctLower = parseAcct(acctLower);
+ if (![null, config.host.toLowerCase()].includes(parsedAcctLower.host)) {
+ ctx.status = 422;
+ return;
+ }
- const user = await User.findOne({
- usernameLower: parsedAcctLower.username,
- host: null
- });
+ user = await User.findOne({
+ usernameLower: parsedAcctLower.username,
+ host: null
+ });
+ } else {
+ user = await User.findOne({
+ _id: id,
+ host: null
+ });
+ }
if (user === null) {
ctx.status = 404;