summaryrefslogtreecommitdiff
path: root/src/server/api/endpoints/users
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/api/endpoints/users')
-rw-r--r--src/server/api/endpoints/users/followers.ts98
-rw-r--r--src/server/api/endpoints/users/following.ts98
-rw-r--r--src/server/api/endpoints/users/get-frequently-replied-users.ts52
-rw-r--r--src/server/api/endpoints/users/lists/create.ts18
-rw-r--r--src/server/api/endpoints/users/lists/delete.ts17
-rw-r--r--src/server/api/endpoints/users/lists/list.ts10
-rw-r--r--src/server/api/endpoints/users/lists/pull.ts23
-rw-r--r--src/server/api/endpoints/users/lists/push.ts21
-rw-r--r--src/server/api/endpoints/users/lists/show.ts15
-rw-r--r--src/server/api/endpoints/users/lists/update.ts23
-rw-r--r--src/server/api/endpoints/users/notes.ts130
-rw-r--r--src/server/api/endpoints/users/recommendation.ts99
-rw-r--r--src/server/api/endpoints/users/relation.ts7
-rw-r--r--src/server/api/endpoints/users/report-abuse.ts24
-rw-r--r--src/server/api/endpoints/users/search.ts40
-rw-r--r--src/server/api/endpoints/users/show.ts29
16 files changed, 224 insertions, 480 deletions
diff --git a/src/server/api/endpoints/users/followers.ts b/src/server/api/endpoints/users/followers.ts
index 3c8290a8b1..51b007ddaa 100644
--- a/src/server/api/endpoints/users/followers.ts
+++ b/src/server/api/endpoints/users/followers.ts
@@ -1,11 +1,9 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../misc/cafy-id';
-import User from '../../../../models/user';
-import Following from '../../../../models/following';
-import { pack } from '../../../../models/user';
-import { getFriendIds } from '../../common/get-friends';
+import { ID } from '../../../../misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
+import { Users, Followings } from '../../../../models';
+import { makePaginationQuery } from '../../common/make-pagination-query';
export const meta = {
desc: {
@@ -20,7 +18,6 @@ export const meta = {
params: {
userId: {
validator: $.optional.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象のユーザーのID',
'en-US': 'Target user ID'
@@ -35,38 +32,25 @@ export const meta = {
validator: $.optional.nullable.str
},
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
+ sinceId: {
+ validator: $.optional.type(ID),
},
- cursor: {
+ untilId: {
validator: $.optional.type(ID),
- default: null as any,
- transform: transform,
},
- iknow: {
- validator: $.optional.bool,
- default: false,
- }
+ limit: {
+ validator: $.optional.num.range(1, 100),
+ default: 10
+ },
},
res: {
- type: 'object',
- properties: {
- users: {
- type: 'array',
- items: {
- type: 'User',
- }
- },
- next: {
- type: 'string',
- format: 'id',
- nullable: true
- }
- }
+ type: 'array',
+ items: {
+ type: 'Following',
+ },
},
errors: {
@@ -79,54 +63,20 @@ export const meta = {
};
export default define(meta, async (ps, me) => {
- const q: any = ps.userId != null
- ? { _id: ps.userId }
- : { usernameLower: ps.username.toLowerCase(), host: ps.host };
-
- const user = await User.findOne(q);
+ const user = await Users.findOne(ps.userId != null
+ ? { id: ps.userId }
+ : { usernameLower: ps.username.toLowerCase(), host: ps.host });
- if (user === null) {
+ if (user == null) {
throw new ApiError(meta.errors.noSuchUser);
}
- const query = {
- followeeId: user._id
- } as any;
-
- // ログインしていてかつ iknow フラグがあるとき
- if (me && ps.iknow) {
- // Get my friends
- const myFriends = await getFriendIds(me._id);
-
- query.followerId = {
- $in: myFriends
- };
- }
-
- // カーソルが指定されている場合
- if (ps.cursor) {
- query._id = {
- $lt: ps.cursor
- };
- }
-
- // Get followers
- const following = await Following
- .find(query, {
- limit: ps.limit + 1,
- sort: { _id: -1 }
- });
-
- // 「次のページ」があるかどうか
- const inStock = following.length === ps.limit + 1;
- if (inStock) {
- following.pop();
- }
+ const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
+ .andWhere(`following.followeeId = :userId`, { userId: user.id });
- const users = await Promise.all(following.map(f => pack(f.followerId, me, { detail: true })));
+ const followings = await query
+ .take(ps.limit)
+ .getMany();
- return {
- users: users,
- next: inStock ? following[following.length - 1]._id : null,
- };
+ return await Followings.packMany(followings, me, { populateFollower: true });
});
diff --git a/src/server/api/endpoints/users/following.ts b/src/server/api/endpoints/users/following.ts
index 4bc740cad9..46550f0f77 100644
--- a/src/server/api/endpoints/users/following.ts
+++ b/src/server/api/endpoints/users/following.ts
@@ -1,11 +1,9 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../misc/cafy-id';
-import User from '../../../../models/user';
-import Following from '../../../../models/following';
-import { pack } from '../../../../models/user';
-import { getFriendIds } from '../../common/get-friends';
+import { ID } from '../../../../misc/cafy-id';
import define from '../../define';
import { ApiError } from '../../error';
+import { Users, Followings } from '../../../../models';
+import { makePaginationQuery } from '../../common/make-pagination-query';
export const meta = {
desc: {
@@ -20,7 +18,6 @@ export const meta = {
params: {
userId: {
validator: $.optional.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象のユーザーのID',
'en-US': 'Target user ID'
@@ -35,38 +32,25 @@ export const meta = {
validator: $.optional.nullable.str
},
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
+ sinceId: {
+ validator: $.optional.type(ID),
},
- cursor: {
+ untilId: {
validator: $.optional.type(ID),
- default: null as any,
- transform: transform,
},
- iknow: {
- validator: $.optional.bool,
- default: false,
- }
+ limit: {
+ validator: $.optional.num.range(1, 100),
+ default: 10
+ },
},
res: {
- type: 'object',
- properties: {
- users: {
- type: 'array',
- items: {
- type: 'User',
- }
- },
- next: {
- type: 'string',
- format: 'id',
- nullable: true
- }
- }
+ type: 'array',
+ items: {
+ type: 'Following',
+ },
},
errors: {
@@ -79,54 +63,20 @@ export const meta = {
};
export default define(meta, async (ps, me) => {
- const q: any = ps.userId != null
- ? { _id: ps.userId }
- : { usernameLower: ps.username.toLowerCase(), host: ps.host };
-
- const user = await User.findOne(q);
+ const user = await Users.findOne(ps.userId != null
+ ? { id: ps.userId }
+ : { usernameLower: ps.username.toLowerCase(), host: ps.host });
- if (user === null) {
+ if (user == null) {
throw new ApiError(meta.errors.noSuchUser);
}
- const query = {
- followerId: user._id
- } as any;
-
- // ログインしていてかつ iknow フラグがあるとき
- if (me && ps.iknow) {
- // Get my friends
- const myFriends = await getFriendIds(me._id);
-
- query.followeeId = {
- $in: myFriends
- };
- }
-
- // カーソルが指定されている場合
- if (ps.cursor) {
- query._id = {
- $lt: ps.cursor
- };
- }
-
- // Get followers
- const following = await Following
- .find(query, {
- limit: ps.limit + 1,
- sort: { _id: -1 }
- });
-
- // 「次のページ」があるかどうか
- const inStock = following.length === ps.limit + 1;
- if (inStock) {
- following.pop();
- }
+ const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId)
+ .andWhere(`following.followerId = :userId`, { userId: user.id });
- const users = await Promise.all(following.map(f => pack(f.followeeId, me, { detail: true })));
+ const followings = await query
+ .take(ps.limit)
+ .getMany();
- return {
- users: users,
- next: inStock ? following[following.length - 1]._id : null,
- };
+ return await Followings.packMany(followings, me, { populateFollowee: true });
});
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 46c7fba2f6..f82f437629 100644
--- a/src/server/api/endpoints/users/get-frequently-replied-users.ts
+++ b/src/server/api/endpoints/users/get-frequently-replied-users.ts
@@ -1,12 +1,11 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../misc/cafy-id';
-import Note from '../../../../models/note';
-import { pack } from '../../../../models/user';
+import { ID } from '../../../../misc/cafy-id';
import define from '../../define';
import { maximum } from '../../../../prelude/array';
-import { getHideUserIds } from '../../common/get-hide-users';
import { ApiError } from '../../error';
import { getUser } from '../../common/getters';
+import { Not, In } from 'typeorm';
+import { Notes, Users } from '../../../../models';
export const meta = {
tags: ['users'],
@@ -16,7 +15,6 @@ export const meta = {
params: {
userId: {
validator: $.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象のユーザーのID',
'en-US': 'Target user ID'
@@ -53,21 +51,16 @@ export default define(meta, async (ps, me) => {
});
// Fetch recent notes
- const recentNotes = await Note.find({
- userId: user._id,
- replyId: {
- $exists: true,
- $ne: null
- }
- }, {
- sort: {
- _id: -1
+ const recentNotes = await Notes.find({
+ where: {
+ userId: user.id,
+ replyId: Not(null)
},
- limit: 1000,
- fields: {
- _id: false,
- replyId: true
- }
+ order: {
+ id: -1
+ },
+ take: 1000,
+ select: ['replyId']
});
// 投稿が少なかったら中断
@@ -75,21 +68,12 @@ export default define(meta, async (ps, me) => {
return [];
}
- const hideUserIds = await getHideUserIds(me);
- hideUserIds.push(user._id);
-
- const replyTargetNotes = await Note.find({
- _id: {
- $in: recentNotes.map(p => p.replyId)
+ // TODO ミュートを考慮
+ const replyTargetNotes = await Notes.find({
+ where: {
+ id: In(recentNotes.map(p => p.replyId)),
},
- userId: {
- $nin: hideUserIds
- }
- }, {
- fields: {
- _id: false,
- userId: true
- }
+ select: ['userId']
});
const repliedUsers: any = {};
@@ -114,7 +98,7 @@ export default define(meta, async (ps, me) => {
// Make replies object (includes weights)
const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({
- user: await pack(user, me, { detail: true }),
+ user: await Users.pack(user, me, { detail: true }),
weight: repliedUsers[user] / peak
})));
diff --git a/src/server/api/endpoints/users/lists/create.ts b/src/server/api/endpoints/users/lists/create.ts
index 00d2538c9f..21dc6d331d 100644
--- a/src/server/api/endpoints/users/lists/create.ts
+++ b/src/server/api/endpoints/users/lists/create.ts
@@ -1,6 +1,8 @@
import $ from 'cafy';
-import UserList, { pack } from '../../../../../models/user-list';
import define from '../../../define';
+import { UserLists } from '../../../../../models';
+import { genId } from '../../../../../misc/gen-id';
+import { UserList } from '../../../../../models/entities/user-list';
export const meta = {
desc: {
@@ -12,7 +14,7 @@ export const meta = {
requireCredential: true,
- kind: 'account-write',
+ kind: 'write:account',
params: {
title: {
@@ -22,12 +24,12 @@ export const meta = {
};
export default define(meta, async (ps, user) => {
- const userList = await UserList.insert({
+ const userList = await UserLists.save({
+ id: genId(),
createdAt: new Date(),
- userId: user._id,
- title: ps.title,
- userIds: []
- });
+ userId: user.id,
+ name: ps.title,
+ } as UserList);
- return await pack(userList);
+ return await UserLists.pack(userList);
});
diff --git a/src/server/api/endpoints/users/lists/delete.ts b/src/server/api/endpoints/users/lists/delete.ts
index d8faaa928c..0634bca4e3 100644
--- a/src/server/api/endpoints/users/lists/delete.ts
+++ b/src/server/api/endpoints/users/lists/delete.ts
@@ -1,8 +1,8 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../../misc/cafy-id';
-import UserList from '../../../../../models/user-list';
+import { ID } from '../../../../../misc/cafy-id';
import define from '../../../define';
import { ApiError } from '../../../error';
+import { UserLists } from '../../../../../models';
export const meta = {
desc: {
@@ -14,12 +14,11 @@ export const meta = {
requireCredential: true,
- kind: 'account-write',
+ kind: 'write:account',
params: {
listId: {
validator: $.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象となるユーザーリストのID',
'en-US': 'ID of target user list'
@@ -37,16 +36,14 @@ export const meta = {
};
export default define(meta, async (ps, user) => {
- const userList = await UserList.findOne({
- _id: ps.listId,
- userId: user._id
+ const userList = await UserLists.findOne({
+ id: ps.listId,
+ userId: user.id
});
if (userList == null) {
throw new ApiError(meta.errors.noSuchList);
}
- await UserList.remove({
- _id: userList._id
- });
+ await UserLists.delete(userList.id);
});
diff --git a/src/server/api/endpoints/users/lists/list.ts b/src/server/api/endpoints/users/lists/list.ts
index ece2af5603..b05fc45527 100644
--- a/src/server/api/endpoints/users/lists/list.ts
+++ b/src/server/api/endpoints/users/lists/list.ts
@@ -1,5 +1,5 @@
-import UserList, { pack } from '../../../../../models/user-list';
import define from '../../../define';
+import { UserLists } from '../../../../../models';
export const meta = {
desc: {
@@ -10,7 +10,7 @@ export const meta = {
requireCredential: true,
- kind: 'account-read',
+ kind: 'read:account',
res: {
type: 'array',
@@ -21,9 +21,9 @@ export const meta = {
};
export default define(meta, async (ps, me) => {
- const userLists = await UserList.find({
- userId: me._id,
+ const userLists = await UserLists.find({
+ userId: me.id,
});
- return await Promise.all(userLists.map(x => pack(x)));
+ return await Promise.all(userLists.map(x => UserLists.pack(x)));
});
diff --git a/src/server/api/endpoints/users/lists/pull.ts b/src/server/api/endpoints/users/lists/pull.ts
index 0eee1975db..524670b341 100644
--- a/src/server/api/endpoints/users/lists/pull.ts
+++ b/src/server/api/endpoints/users/lists/pull.ts
@@ -1,11 +1,10 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../../misc/cafy-id';
-import UserList from '../../../../../models/user-list';
-import { pack as packUser } from '../../../../../models/user';
+import { ID } from '../../../../../misc/cafy-id';
import { publishUserListStream } from '../../../../../services/stream';
import define from '../../../define';
import { ApiError } from '../../../error';
import { getUser } from '../../../common/getters';
+import { UserLists, UserListJoinings, Users } from '../../../../../models';
export const meta = {
desc: {
@@ -17,17 +16,15 @@ export const meta = {
requireCredential: true,
- kind: 'account-write',
+ kind: 'write:account',
params: {
listId: {
validator: $.type(ID),
- transform: transform,
},
userId: {
validator: $.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象のユーザーのID',
'en-US': 'Target user ID'
@@ -52,9 +49,9 @@ export const meta = {
export default define(meta, async (ps, me) => {
// Fetch the list
- const userList = await UserList.findOne({
- _id: ps.listId,
- userId: me._id,
+ const userList = await UserLists.findOne({
+ id: ps.listId,
+ userId: me.id,
});
if (userList == null) {
@@ -68,11 +65,7 @@ export default define(meta, async (ps, me) => {
});
// Pull the user
- await UserList.update({ _id: userList._id }, {
- $pull: {
- userIds: user._id
- }
- });
+ await UserListJoinings.delete({ userId: user.id });
- publishUserListStream(userList._id, 'userRemoved', await packUser(user));
+ publishUserListStream(userList.id, 'userRemoved', await Users.pack(user));
});
diff --git a/src/server/api/endpoints/users/lists/push.ts b/src/server/api/endpoints/users/lists/push.ts
index eea2f39a8c..2763b3a19c 100644
--- a/src/server/api/endpoints/users/lists/push.ts
+++ b/src/server/api/endpoints/users/lists/push.ts
@@ -1,10 +1,10 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../../misc/cafy-id';
-import UserList from '../../../../../models/user-list';
+import { ID } from '../../../../../misc/cafy-id';
import define from '../../../define';
import { ApiError } from '../../../error';
import { getUser } from '../../../common/getters';
import { pushUserToUserList } from '../../../../../services/user-list/push';
+import { UserLists, UserListJoinings } from '../../../../../models';
export const meta = {
desc: {
@@ -16,17 +16,15 @@ export const meta = {
requireCredential: true,
- kind: 'account-write',
+ kind: 'write:account',
params: {
listId: {
validator: $.type(ID),
- transform: transform,
},
userId: {
validator: $.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象のユーザーのID',
'en-US': 'Target user ID'
@@ -57,9 +55,9 @@ export const meta = {
export default define(meta, async (ps, me) => {
// Fetch the list
- const userList = await UserList.findOne({
- _id: ps.listId,
- userId: me._id,
+ const userList = await UserLists.findOne({
+ id: ps.listId,
+ userId: me.id,
});
if (userList == null) {
@@ -72,7 +70,12 @@ export default define(meta, async (ps, me) => {
throw e;
});
- if (userList.userIds.map(id => id.toHexString()).includes(user._id.toHexString())) {
+ const exist = await UserListJoinings.findOne({
+ userListId: userList.id,
+ userId: user.id
+ });
+
+ if (exist) {
throw new ApiError(meta.errors.alreadyAdded);
}
diff --git a/src/server/api/endpoints/users/lists/show.ts b/src/server/api/endpoints/users/lists/show.ts
index 0fab2fa499..1a997ec7c5 100644
--- a/src/server/api/endpoints/users/lists/show.ts
+++ b/src/server/api/endpoints/users/lists/show.ts
@@ -1,8 +1,8 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../../misc/cafy-id';
-import UserList, { pack } from '../../../../../models/user-list';
+import { ID } from '../../../../../misc/cafy-id';
import define from '../../../define';
import { ApiError } from '../../../error';
+import { UserLists } from '../../../../../models';
export const meta = {
desc: {
@@ -14,12 +14,11 @@ export const meta = {
requireCredential: true,
- kind: 'account-read',
+ kind: 'read:account',
params: {
listId: {
validator: $.type(ID),
- transform: transform,
},
},
@@ -38,14 +37,14 @@ export const meta = {
export default define(meta, async (ps, me) => {
// Fetch the list
- const userList = await UserList.findOne({
- _id: ps.listId,
- userId: me._id,
+ const userList = await UserLists.findOne({
+ id: ps.listId,
+ userId: me.id,
});
if (userList == null) {
throw new ApiError(meta.errors.noSuchList);
}
- return await pack(userList);
+ return await UserLists.pack(userList);
});
diff --git a/src/server/api/endpoints/users/lists/update.ts b/src/server/api/endpoints/users/lists/update.ts
index 5897693144..dc08d59f6a 100644
--- a/src/server/api/endpoints/users/lists/update.ts
+++ b/src/server/api/endpoints/users/lists/update.ts
@@ -1,8 +1,8 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../../misc/cafy-id';
-import UserList, { pack } from '../../../../../models/user-list';
+import { ID } from '../../../../../misc/cafy-id';
import define from '../../../define';
import { ApiError } from '../../../error';
+import { UserLists } from '../../../../../models';
export const meta = {
desc: {
@@ -14,19 +14,18 @@ export const meta = {
requireCredential: true,
- kind: 'account-write',
+ kind: 'write:account',
params: {
listId: {
validator: $.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象となるユーザーリストのID',
'en-US': 'ID of target user list'
}
},
- title: {
+ name: {
validator: $.str.range(1, 100),
desc: {
'ja-JP': 'このユーザーリストの名前',
@@ -46,20 +45,18 @@ export const meta = {
export default define(meta, async (ps, user) => {
// Fetch the list
- const userList = await UserList.findOne({
- _id: ps.listId,
- userId: user._id
+ const userList = await UserLists.findOne({
+ id: ps.listId,
+ userId: user.id
});
if (userList == null) {
throw new ApiError(meta.errors.noSuchList);
}
- await UserList.update({ _id: userList._id }, {
- $set: {
- title: ps.title
- }
+ await UserLists.update(userList.id, {
+ name: ps.name
});
- return await pack(userList._id);
+ return await UserLists.pack(userList.id);
});
diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts
index 10d2f37fc2..6df394cbb1 100644
--- a/src/server/api/endpoints/users/notes.ts
+++ b/src/server/api/endpoints/users/notes.ts
@@ -1,10 +1,13 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../misc/cafy-id';
-import Note, { packMany } from '../../../../models/note';
+import { ID } from '../../../../misc/cafy-id';
import define from '../../define';
-import Following from '../../../../models/following';
import { ApiError } from '../../error';
import { getUser } from '../../common/getters';
+import { makePaginationQuery } from '../../common/make-pagination-query';
+import { generateVisibilityQuery } from '../../common/generate-visibility-query';
+import { Notes } from '../../../../models';
+import { generateMuteQuery } from '../../common/generate-mute-query';
+import { Brackets } from 'typeorm';
export const meta = {
desc: {
@@ -16,7 +19,6 @@ export const meta = {
params: {
userId: {
validator: $.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象のユーザーのID',
'en-US': 'Target user ID'
@@ -42,17 +44,15 @@ export const meta = {
sinceId: {
validator: $.optional.type(ID),
- transform: transform,
desc: {
- 'ja-JP': '指定すると、この投稿を基点としてより新しい投稿を取得します'
+ 'ja-JP': '指定すると、その投稿を基点としてより新しい投稿を取得します'
}
},
untilId: {
validator: $.optional.type(ID),
- transform: transform,
desc: {
- 'ja-JP': '指定すると、この投稿を基点としてより古い投稿を取得します'
+ 'ja-JP': '指定すると、その投稿を基点としてより古い投稿を取得します'
}
},
@@ -102,15 +102,6 @@ export const meta = {
}
},
- mediaOnly: {
- validator: $.optional.bool,
- default: false,
- deprecated: true,
- desc: {
- 'ja-JP': 'true にすると、ファイルが添付された投稿だけ取得します (このパラメータは廃止予定です。代わりに withFiles を使ってください。)'
- }
- },
-
fileType: {
validator: $.optional.arr($.str),
desc: {
@@ -150,67 +141,44 @@ export default define(meta, async (ps, me) => {
throw e;
});
- const isFollowing = me == null ? false : ((await Following.findOne({
- followerId: me._id,
- followeeId: user._id
- })) != null);
-
//#region Construct query
- const sort = { } as any;
+ const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
+ .andWhere('note.userId = :userId', { userId: user.id })
+ .leftJoinAndSelect('note.user', 'user');
- const visibleQuery = me == null ? [{
- visibility: { $in: ['public', 'home'] }
- }] : [{
- visibility: {
- $in: isFollowing ? ['public', 'home', 'followers'] : ['public', 'home']
- }
- }, {
- // myself (for specified/private)
- userId: me._id
- }, {
- // to me (for specified)
- visibleUserIds: { $in: [ me._id ] }
- }];
+ if (me) generateVisibilityQuery(query, me);
+ if (me) generateMuteQuery(query, me);
+
+ if (ps.withFiles) {
+ query.andWhere('note.fileIds != \'{}\'');
+ }
- const query = {
- $and: [ {} ],
- deletedAt: null,
- userId: user._id,
- $or: visibleQuery
- } as any;
+ if (ps.fileType) {
+ query.andWhere('note.fileIds != \'{}\'');
+ query.andWhere(new Brackets(qb => {
+ for (const type of ps.fileType) {
+ const i = ps.fileType.indexOf(type);
+ qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { [`type${i}`]: type });
+ }
+ }));
- if (ps.sinceId) {
- sort._id = 1;
- query._id = {
- $gt: ps.sinceId
- };
- } else if (ps.untilId) {
- sort._id = -1;
- query._id = {
- $lt: ps.untilId
- };
- } else if (ps.sinceDate) {
- sort.createdAt = 1;
- query.createdAt = {
- $gt: new Date(ps.sinceDate)
- };
- } else if (ps.untilDate) {
- sort.createdAt = -1;
- query.createdAt = {
- $lt: new Date(ps.untilDate)
- };
- } else {
- sort._id = -1;
+ if (ps.excludeNsfw) {
+ // v11 TODO
+ /*query['_files.isSensitive'] = {
+ $ne: true
+ };*/
+ }
}
if (!ps.includeReplies) {
- query.replyId = null;
+ query.andWhere('note.replyId IS NULL');
}
+ /* TODO
if (ps.includeMyRenotes === false) {
query.$and.push({
$or: [{
- userId: { $ne: user._id }
+ userId: { $ne: user.id }
}, {
renoteId: null
}, {
@@ -222,35 +190,11 @@ export default define(meta, async (ps, me) => {
}]
});
}
+ */
- const withFiles = ps.withFiles != null ? ps.withFiles : ps.mediaOnly;
-
- if (withFiles) {
- query.fileIds = {
- $exists: true,
- $ne: []
- };
- }
-
- if (ps.fileType) {
- query.fileIds = { $exists: true, $ne: [] };
-
- query['_files.contentType'] = {
- $in: ps.fileType
- };
-
- if (ps.excludeNsfw) {
- query['_files.metadata.isSensitive'] = {
- $ne: true
- };
- }
- }
//#endregion
- const notes = await Note.find(query, {
- limit: ps.limit,
- sort: sort
- });
+ const timeline = await query.take(ps.limit).getMany();
- return await packMany(notes, me);
+ return await Notes.packMany(timeline, user);
});
diff --git a/src/server/api/endpoints/users/recommendation.ts b/src/server/api/endpoints/users/recommendation.ts
index 60710fffca..2c82d6613e 100644
--- a/src/server/api/endpoints/users/recommendation.ts
+++ b/src/server/api/endpoints/users/recommendation.ts
@@ -1,14 +1,8 @@
import * as ms from 'ms';
import $ from 'cafy';
-import User, { pack, ILocalUser } from '../../../../models/user';
-import { getFriendIds } from '../../common/get-friends';
-import * as request from 'request-promise-native';
-import config from '../../../../config';
import define from '../../define';
-import fetchMeta from '../../../../misc/fetch-meta';
-import resolveUser from '../../../../remote/resolve-user';
-import { getHideUserIds } from '../../common/get-hide-users';
-import { apiLogger } from '../../logger';
+import { Users, Followings } from '../../../../models';
+import { generateMuteQueryForUsers } from '../../common/generate-mute-query';
export const meta = {
desc: {
@@ -19,7 +13,7 @@ export const meta = {
requireCredential: true,
- kind: 'account-read',
+ kind: 'read:account',
params: {
limit: {
@@ -42,83 +36,24 @@ export const meta = {
};
export default define(meta, async (ps, me) => {
- const instance = await fetchMeta();
+ const query = Users.createQueryBuilder('user')
+ .where('user.isLocked = FALSE')
+ .where('user.host IS NULL')
+ .where('user.updatedAt >= :date', { date: new Date(Date.now() - ms('7days')) })
+ .orderBy('user.followersCount', 'DESC');
- if (instance.enableExternalUserRecommendation) {
- const userName = me.username;
- const hostName = config.hostname;
- const limit = ps.limit;
- const offset = ps.offset;
- const timeout = instance.externalUserRecommendationTimeout;
- const engine = instance.externalUserRecommendationEngine;
- const url = engine
- .replace('{{host}}', hostName)
- .replace('{{user}}', userName)
- .replace('{{limit}}', limit.toString())
- .replace('{{offset}}', offset.toString());
+ generateMuteQueryForUsers(query, me);
- const users = await request({
- url: url,
- proxy: config.proxy,
- timeout: timeout,
- json: true,
- followRedirect: true,
- followAllRedirects: true
- })
- .then(body => convertUsers(body, me));
+ const followingQuery = Followings.createQueryBuilder('following')
+ .select('following.followeeId')
+ .where('following.followerId = :followerId', { followerId: me.id });
- return users;
- } else {
- // ID list of the user itself and other users who the user follows
- const followingIds = await getFriendIds(me._id);
+ query
+ .andWhere(`user.id NOT IN (${ followingQuery.getQuery() })`);
- // 隠すユーザーを取得
- const hideUserIds = await getHideUserIds(me);
+ query.setParameters(followingQuery.getParameters());
- const users = await User.find({
- _id: {
- $nin: followingIds.concat(hideUserIds)
- },
- isLocked: { $ne: true },
- updatedAt: {
- $gte: new Date(Date.now() - ms('7days'))
- },
- host: null
- }, {
- limit: ps.limit,
- skip: ps.offset,
- sort: {
- followersCount: -1
- }
- });
+ const users = await query.take(ps.limit).skip(ps.offset).getMany();
- return await Promise.all(users.map(user => pack(user, me, { detail: true })));
- }
+ return await Users.packMany(users, me, { detail: true });
});
-
-type IRecommendUser = {
- name: string;
- username: string;
- host: string;
- description: string;
- avatarUrl: string;
-};
-
-/**
- * Resolve/Pack dummy users
- */
-async function convertUsers(src: IRecommendUser[], me: ILocalUser) {
- const packed = await Promise.all(src.map(async x => {
- const user = await resolveUser(x.username, x.host)
- .catch(() => {
- apiLogger.warn(`Can't resolve ${x.username}@${x.host}`);
- return null;
- });
-
- if (user == null) return x;
-
- return await pack(user, me, { detail: true });
- }));
-
- return packed;
-}
diff --git a/src/server/api/endpoints/users/relation.ts b/src/server/api/endpoints/users/relation.ts
index f4121aa0d0..4971738d32 100644
--- a/src/server/api/endpoints/users/relation.ts
+++ b/src/server/api/endpoints/users/relation.ts
@@ -1,7 +1,7 @@
import $ from 'cafy';
-import ID, { transform, ObjectId } from '../../../../misc/cafy-id';
-import { getRelation } from '../../../../models/user';
import define from '../../define';
+import { ID } from '../../../../misc/cafy-id';
+import { Users } from '../../../../models';
export const meta = {
desc: {
@@ -15,7 +15,6 @@ export const meta = {
params: {
userId: {
validator: $.either($.type(ID), $.arr($.type(ID)).unique()),
- transform: (v: any): ObjectId | ObjectId[] => Array.isArray(v) ? v.map(x => transform(x)) : transform(v),
desc: {
'ja-JP': 'ユーザーID (配列でも可)'
}
@@ -26,7 +25,7 @@ export const meta = {
export default define(meta, async (ps, me) => {
const ids = Array.isArray(ps.userId) ? ps.userId : [ps.userId];
- const relations = await Promise.all(ids.map(id => getRelation(me._id, id)));
+ const relations = await Promise.all(ids.map(id => Users.getRelation(me.id, id)));
return Array.isArray(ps.userId) ? relations : relations[0];
});
diff --git a/src/server/api/endpoints/users/report-abuse.ts b/src/server/api/endpoints/users/report-abuse.ts
index 0f23f8f0c3..2ee28c9002 100644
--- a/src/server/api/endpoints/users/report-abuse.ts
+++ b/src/server/api/endpoints/users/report-abuse.ts
@@ -1,11 +1,11 @@
import $ from 'cafy';
-import ID, { transform } from '../../../../misc/cafy-id';
+import { ID } from '../../../../misc/cafy-id';
import define from '../../define';
-import User from '../../../../models/user';
-import AbuseUserReport from '../../../../models/abuse-user-report';
import { publishAdminStream } from '../../../../services/stream';
import { ApiError } from '../../error';
import { getUser } from '../../common/getters';
+import { AbuseUserReports, Users } from '../../../../models';
+import { genId } from '../../../../misc/gen-id';
export const meta = {
desc: {
@@ -19,7 +19,6 @@ export const meta = {
params: {
userId: {
validator: $.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象のユーザーのID',
'en-US': 'Target user ID'
@@ -62,7 +61,7 @@ export default define(meta, async (ps, me) => {
throw e;
});
- if (user._id.equals(me._id)) {
+ if (user.id === me.id) {
throw new ApiError(meta.errors.cannotReportYourself);
}
@@ -70,17 +69,18 @@ export default define(meta, async (ps, me) => {
throw new ApiError(meta.errors.cannotReportAdmin);
}
- const report = await AbuseUserReport.insert({
+ const report = await AbuseUserReports.save({
+ id: genId(),
createdAt: new Date(),
- userId: user._id,
- reporterId: me._id,
+ userId: user.id,
+ reporterId: me.id,
comment: ps.comment
});
// Publish event to moderators
setTimeout(async () => {
- const moderators = await User.find({
- $or: [{
+ const moderators = await Users.find({
+ where: [{
isAdmin: true
}, {
isModerator: true
@@ -88,8 +88,8 @@ export default define(meta, async (ps, me) => {
});
for (const moderator of moderators) {
- publishAdminStream(moderator._id, 'newAbuseUserReport', {
- id: report._id,
+ publishAdminStream(moderator.id, 'newAbuseUserReport', {
+ id: report.id,
userId: report.userId,
reporterId: report.reporterId,
comment: report.comment
diff --git a/src/server/api/endpoints/users/search.ts b/src/server/api/endpoints/users/search.ts
index a95f6df6de..2e76546ade 100644
--- a/src/server/api/endpoints/users/search.ts
+++ b/src/server/api/endpoints/users/search.ts
@@ -1,7 +1,7 @@
import $ from 'cafy';
-import * as escapeRegexp from 'escape-regexp';
-import User, { pack, validateUsername, IUser } from '../../../../models/user';
import define from '../../define';
+import { Users } from '../../../../models';
+import { User } from '../../../../models/entities/user';
export const meta = {
desc: {
@@ -62,34 +62,30 @@ export const meta = {
};
export default define(meta, async (ps, me) => {
- const isUsername = validateUsername(ps.query.replace('@', ''), !ps.localOnly);
+ const isUsername = Users.validateUsername(ps.query.replace('@', ''), !ps.localOnly);
- let users: IUser[] = [];
+ let users: User[] = [];
if (isUsername) {
- users = await User
- .find({
- host: null,
- usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase())),
- isSuspended: { $ne: true }
- }, {
- limit: ps.limit,
- skip: ps.offset
- });
+ users = await Users.createQueryBuilder('user')
+ .where('user.host IS NULL')
+ .where('user.isSuspended = FALSE')
+ .where('user.usernameLower like :username', { username: ps.query.replace('@', '').toLowerCase() + '%' })
+ .take(ps.limit)
+ .skip(ps.offset)
+ .getMany();
if (users.length < ps.limit && !ps.localOnly) {
- const otherUsers = await User
- .find({
- host: { $ne: null },
- usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase())),
- isSuspended: { $ne: true }
- }, {
- limit: ps.limit - users.length
- });
+ const otherUsers = await Users.createQueryBuilder('user')
+ .where('user.host IS NOT NULL')
+ .where('user.isSuspended = FALSE')
+ .where('user.usernameLower like :username', { username: ps.query.replace('@', '').toLowerCase() + '%' })
+ .take(ps.limit - users.length)
+ .getMany();
users = users.concat(otherUsers);
}
}
- return await Promise.all(users.map(user => pack(user, me, { detail: ps.detail })));
+ return await Users.packMany(users, me, { detail: ps.detail });
});
diff --git a/src/server/api/endpoints/users/show.ts b/src/server/api/endpoints/users/show.ts
index 4e59945eba..a605eaf30a 100644
--- a/src/server/api/endpoints/users/show.ts
+++ b/src/server/api/endpoints/users/show.ts
@@ -1,12 +1,11 @@
import $ from 'cafy';
-import ID, { transform, transformMany } from '../../../../misc/cafy-id';
-import User, { pack, isRemoteUser } from '../../../../models/user';
import resolveRemoteUser from '../../../../remote/resolve-user';
import define from '../../define';
import { apiLogger } from '../../logger';
import { ApiError } from '../../error';
-
-const cursorOption = { fields: { data: false } };
+import { ID } from '../../../../misc/cafy-id';
+import { Users } from '../../../../models';
+import { In } from 'typeorm';
export const meta = {
desc: {
@@ -20,7 +19,6 @@ export const meta = {
params: {
userId: {
validator: $.optional.type(ID),
- transform: transform,
desc: {
'ja-JP': '対象のユーザーのID',
'en-US': 'Target user ID'
@@ -29,7 +27,6 @@ export const meta = {
userIds: {
validator: $.optional.arr($.type(ID)).unique(),
- transform: transformMany,
desc: {
'ja-JP': 'ユーザーID (配列)'
}
@@ -68,42 +65,40 @@ export default define(meta, async (ps, me) => {
let user;
if (ps.userIds) {
- const users = await User.find({
- _id: {
- $in: ps.userIds
- }
+ const users = await Users.find({
+ id: In(ps.userIds)
});
- return await Promise.all(users.map(u => pack(u, me, {
+ return await Promise.all(users.map(u => Users.pack(u, me, {
detail: true
})));
} else {
// Lookup user
if (typeof ps.host === 'string') {
- user = await resolveRemoteUser(ps.username, ps.host, cursorOption).catch(e => {
+ user = await resolveRemoteUser(ps.username, ps.host).catch(e => {
apiLogger.warn(`failed to resolve remote user: ${e}`);
throw new ApiError(meta.errors.failedToResolveRemoteUser);
});
} else {
const q: any = ps.userId != null
- ? { _id: ps.userId }
+ ? { id: ps.userId }
: { usernameLower: ps.username.toLowerCase(), host: null };
- user = await User.findOne(q, cursorOption);
+ user = await Users.findOne(q);
}
- if (user === null) {
+ if (user == null) {
throw new ApiError(meta.errors.noSuchUser);
}
// ユーザー情報更新
- if (isRemoteUser(user)) {
+ if (Users.isRemoteUser(user)) {
if (user.lastFetchedAt == null || Date.now() - user.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
resolveRemoteUser(ps.username, ps.host, { }, true);
}
}
- return await pack(user, me, {
+ return await Users.pack(user, me, {
detail: true
});
}