diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-11-12 02:02:25 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2021-11-12 02:02:25 +0900 |
| commit | 0e4a111f81cceed275d9bec2695f6e401fb654d8 (patch) | |
| tree | 40874799472fa07416f17b50a398ac33b7771905 /src/server/api/endpoints/users | |
| parent | update deps (diff) | |
| download | sharkey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.gz sharkey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.bz2 sharkey-0e4a111f81cceed275d9bec2695f6e401fb654d8.zip | |
refactoring
Resolve #7779
Diffstat (limited to 'src/server/api/endpoints/users')
34 files changed, 0 insertions, 2432 deletions
diff --git a/src/server/api/endpoints/users/clips.ts b/src/server/api/endpoints/users/clips.ts deleted file mode 100644 index 8feca9422a..0000000000 --- a/src/server/api/endpoints/users/clips.ts +++ /dev/null @@ -1,40 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Clips } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; - -export const meta = { - tags: ['users', 'clips'], - - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10 - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - } -}; - -export default define(meta, async (ps, user) => { - const query = makePaginationQuery(Clips.createQueryBuilder('clip'), ps.sinceId, ps.untilId) - .andWhere(`clip.userId = :userId`, { userId: ps.userId }) - .andWhere('clip.isPublic = true'); - - const clips = await query - .take(ps.limit!) - .getMany(); - - return await Clips.packMany(clips); -}); diff --git a/src/server/api/endpoints/users/followers.ts b/src/server/api/endpoints/users/followers.ts deleted file mode 100644 index 6d042a2861..0000000000 --- a/src/server/api/endpoints/users/followers.ts +++ /dev/null @@ -1,104 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Users, Followings, UserProfiles } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { toPunyNullable } from '@/misc/convert-host'; - -export const meta = { - tags: ['users'], - - requireCredential: false as const, - - params: { - userId: { - validator: $.optional.type(ID), - }, - - username: { - validator: $.optional.str - }, - - host: { - validator: $.optional.nullable.str - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10 - }, - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'Following', - } - }, - - errors: { - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '27fa5435-88ab-43de-9360-387de88727cd' - }, - - forbidden: { - message: 'Forbidden.', - code: 'FORBIDDEN', - id: '3c6a84db-d619-26af-ca14-06232a21df8a' - }, - } -}; - -export default define(meta, async (ps, me) => { - const user = await Users.findOne(ps.userId != null - ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) }); - - if (user == null) { - throw new ApiError(meta.errors.noSuchUser); - } - - const profile = await UserProfiles.findOneOrFail(user.id); - - if (profile.ffVisibility === 'private') { - if (me == null || (me.id !== user.id)) { - throw new ApiError(meta.errors.forbidden); - } - } else if (profile.ffVisibility === 'followers') { - if (me == null) { - throw new ApiError(meta.errors.forbidden); - } else if (me.id !== user.id) { - const following = await Followings.findOne({ - followeeId: user.id, - followerId: me.id, - }); - if (following == null) { - throw new ApiError(meta.errors.forbidden); - } - } - } - - const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) - .andWhere(`following.followeeId = :userId`, { userId: user.id }) - .innerJoinAndSelect('following.follower', 'follower'); - - const followings = await query - .take(ps.limit!) - .getMany(); - - 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 deleted file mode 100644 index 1033117ef8..0000000000 --- a/src/server/api/endpoints/users/following.ts +++ /dev/null @@ -1,104 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { Users, Followings, UserProfiles } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { toPunyNullable } from '@/misc/convert-host'; - -export const meta = { - tags: ['users'], - - requireCredential: false as const, - - params: { - userId: { - validator: $.optional.type(ID), - }, - - username: { - validator: $.optional.str - }, - - host: { - validator: $.optional.nullable.str - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10 - }, - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'Following', - } - }, - - errors: { - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '63e4aba4-4156-4e53-be25-c9559e42d71b' - }, - - forbidden: { - message: 'Forbidden.', - code: 'FORBIDDEN', - id: 'f6cdb0df-c19f-ec5c-7dbb-0ba84a1f92ba' - }, - } -}; - -export default define(meta, async (ps, me) => { - const user = await Users.findOne(ps.userId != null - ? { id: ps.userId } - : { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) }); - - if (user == null) { - throw new ApiError(meta.errors.noSuchUser); - } - - const profile = await UserProfiles.findOneOrFail(user.id); - - if (profile.ffVisibility === 'private') { - if (me == null || (me.id !== user.id)) { - throw new ApiError(meta.errors.forbidden); - } - } else if (profile.ffVisibility === 'followers') { - if (me == null) { - throw new ApiError(meta.errors.forbidden); - } else if (me.id !== user.id) { - const following = await Followings.findOne({ - followeeId: user.id, - followerId: me.id, - }); - if (following == null) { - throw new ApiError(meta.errors.forbidden); - } - } - } - - const query = makePaginationQuery(Followings.createQueryBuilder('following'), ps.sinceId, ps.untilId) - .andWhere(`following.followerId = :userId`, { userId: user.id }) - .innerJoinAndSelect('following.followee', 'followee'); - - const followings = await query - .take(ps.limit!) - .getMany(); - - return await Followings.packMany(followings, me, { populateFollowee: true }); -}); diff --git a/src/server/api/endpoints/users/gallery/posts.ts b/src/server/api/endpoints/users/gallery/posts.ts deleted file mode 100644 index 845de1089c..0000000000 --- a/src/server/api/endpoints/users/gallery/posts.ts +++ /dev/null @@ -1,39 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { GalleryPosts } from '@/models/index'; -import { makePaginationQuery } from '../../../common/make-pagination-query'; - -export const meta = { - tags: ['users', 'gallery'], - - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10 - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - } -}; - -export default define(meta, async (ps, user) => { - const query = makePaginationQuery(GalleryPosts.createQueryBuilder('post'), ps.sinceId, ps.untilId) - .andWhere(`post.userId = :userId`, { userId: ps.userId }); - - const posts = await query - .take(ps.limit!) - .getMany(); - - return await GalleryPosts.packMany(posts, user); -}); diff --git a/src/server/api/endpoints/users/get-frequently-replied-users.ts b/src/server/api/endpoints/users/get-frequently-replied-users.ts deleted file mode 100644 index 32ebfd683a..0000000000 --- a/src/server/api/endpoints/users/get-frequently-replied-users.ts +++ /dev/null @@ -1,105 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { maximum } from '@/prelude/array'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { Not, In, IsNull } from 'typeorm'; -import { Notes, Users } from '@/models/index'; - -export const meta = { - tags: ['users'], - - requireCredential: false as const, - - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10 - }, - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - } - }, - - errors: { - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'e6965129-7b2a-40a4-bae2-cd84cd434822' - } - } -}; - -export default define(meta, async (ps, me) => { - // Lookup user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - // Fetch recent notes - const recentNotes = await Notes.find({ - where: { - userId: user.id, - replyId: Not(IsNull()) - }, - order: { - id: -1 - }, - take: 1000, - select: ['replyId'] - }); - - // 投稿が少なかったら中断 - if (recentNotes.length === 0) { - return []; - } - - // TODO ミュートを考慮 - const replyTargetNotes = await Notes.find({ - where: { - id: In(recentNotes.map(p => p.replyId)), - }, - select: ['userId'] - }); - - const repliedUsers: any = {}; - - // Extract replies from recent notes - for (const userId of replyTargetNotes.map(x => x.userId.toString())) { - if (repliedUsers[userId]) { - repliedUsers[userId]++; - } else { - repliedUsers[userId] = 1; - } - } - - // Calc peak - const peak = maximum(Object.values(repliedUsers)); - - // Sort replies by frequency - const repliedUsersSorted = Object.keys(repliedUsers).sort((a, b) => repliedUsers[b] - repliedUsers[a]); - - // Extract top replied users - const topRepliedUsers = repliedUsersSorted.slice(0, ps.limit!); - - // Make replies object (includes weights) - const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({ - user: await Users.pack(user, me, { detail: true }), - weight: repliedUsers[user] / peak - }))); - - return repliesObj; -}); diff --git a/src/server/api/endpoints/users/groups/create.ts b/src/server/api/endpoints/users/groups/create.ts deleted file mode 100644 index dc1ee3879e..0000000000 --- a/src/server/api/endpoints/users/groups/create.ts +++ /dev/null @@ -1,45 +0,0 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { UserGroup } from '@/models/entities/user-group'; -import { UserGroupJoining } from '@/models/entities/user-group-joining'; - -export const meta = { - tags: ['groups'], - - requireCredential: true as const, - - kind: 'write:user-groups', - - params: { - name: { - validator: $.str.range(1, 100) - } - }, - - res: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserGroup', - }, -}; - -export default define(meta, async (ps, user) => { - const userGroup = await UserGroups.insert({ - id: genId(), - createdAt: new Date(), - userId: user.id, - name: ps.name, - } as UserGroup).then(x => UserGroups.findOneOrFail(x.identifiers[0])); - - // Push the owner - await UserGroupJoinings.insert({ - id: genId(), - createdAt: new Date(), - userId: user.id, - userGroupId: userGroup.id - } as UserGroupJoining); - - return await UserGroups.pack(userGroup); -}); diff --git a/src/server/api/endpoints/users/groups/delete.ts b/src/server/api/endpoints/users/groups/delete.ts deleted file mode 100644 index 7da1b4a273..0000000000 --- a/src/server/api/endpoints/users/groups/delete.ts +++ /dev/null @@ -1,40 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserGroups } from '@/models/index'; - -export const meta = { - tags: ['groups'], - - requireCredential: true as const, - - kind: 'write:user-groups', - - params: { - groupId: { - validator: $.type(ID), - } - }, - - errors: { - noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '63dbd64c-cd77-413f-8e08-61781e210b38' - } - } -}; - -export default define(meta, async (ps, user) => { - const userGroup = await UserGroups.findOne({ - id: ps.groupId, - userId: user.id - }); - - if (userGroup == null) { - throw new ApiError(meta.errors.noSuchGroup); - } - - await UserGroups.delete(userGroup.id); -}); diff --git a/src/server/api/endpoints/users/groups/invitations/accept.ts b/src/server/api/endpoints/users/groups/invitations/accept.ts deleted file mode 100644 index 09e6ae2647..0000000000 --- a/src/server/api/endpoints/users/groups/invitations/accept.ts +++ /dev/null @@ -1,54 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../../define'; -import { ApiError } from '../../../../error'; -import { UserGroupJoinings, UserGroupInvitations } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { UserGroupJoining } from '@/models/entities/user-group-joining'; - -export const meta = { - tags: ['groups', 'users'], - - requireCredential: true as const, - - kind: 'write:user-groups', - - params: { - invitationId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchInvitation: { - message: 'No such invitation.', - code: 'NO_SUCH_INVITATION', - id: '98c11eca-c890-4f42-9806-c8c8303ebb5e' - }, - } -}; - -export default define(meta, async (ps, user) => { - // Fetch the invitation - const invitation = await UserGroupInvitations.findOne({ - id: ps.invitationId, - }); - - if (invitation == null) { - throw new ApiError(meta.errors.noSuchInvitation); - } - - if (invitation.userId !== user.id) { - throw new ApiError(meta.errors.noSuchInvitation); - } - - // Push the user - await UserGroupJoinings.insert({ - id: genId(), - createdAt: new Date(), - userId: user.id, - userGroupId: invitation.userGroupId - } as UserGroupJoining); - - UserGroupInvitations.delete(invitation.id); -}); diff --git a/src/server/api/endpoints/users/groups/invitations/reject.ts b/src/server/api/endpoints/users/groups/invitations/reject.ts deleted file mode 100644 index 741fcefb35..0000000000 --- a/src/server/api/endpoints/users/groups/invitations/reject.ts +++ /dev/null @@ -1,44 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../../define'; -import { ApiError } from '../../../../error'; -import { UserGroupInvitations } from '@/models/index'; - -export const meta = { - tags: ['groups', 'users'], - - requireCredential: true as const, - - kind: 'write:user-groups', - - params: { - invitationId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchInvitation: { - message: 'No such invitation.', - code: 'NO_SUCH_INVITATION', - id: 'ad7471d4-2cd9-44b4-ac68-e7136b4ce656' - }, - } -}; - -export default define(meta, async (ps, user) => { - // Fetch the invitation - const invitation = await UserGroupInvitations.findOne({ - id: ps.invitationId, - }); - - if (invitation == null) { - throw new ApiError(meta.errors.noSuchInvitation); - } - - if (invitation.userId !== user.id) { - throw new ApiError(meta.errors.noSuchInvitation); - } - - await UserGroupInvitations.delete(invitation.id); -}); diff --git a/src/server/api/endpoints/users/groups/invite.ts b/src/server/api/endpoints/users/groups/invite.ts deleted file mode 100644 index f1ee8bf8b7..0000000000 --- a/src/server/api/endpoints/users/groups/invite.ts +++ /dev/null @@ -1,102 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { UserGroups, UserGroupJoinings, UserGroupInvitations } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { UserGroupInvitation } from '@/models/entities/user-group-invitation'; -import { createNotification } from '@/services/create-notification'; - -export const meta = { - tags: ['groups', 'users'], - - requireCredential: true as const, - - kind: 'write:user-groups', - - params: { - groupId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '583f8bc0-8eee-4b78-9299-1e14fc91e409' - }, - - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'da52de61-002c-475b-90e1-ba64f9cf13a8' - }, - - alreadyAdded: { - message: 'That user has already been added to that group.', - code: 'ALREADY_ADDED', - id: '7e35c6a0-39b2-4488-aea6-6ee20bd5da2c' - }, - - alreadyInvited: { - message: 'That user has already been invited to that group.', - code: 'ALREADY_INVITED', - id: 'ee0f58b4-b529-4d13-b761-b9a3e69f97e6' - } - } -}; - -export default define(meta, async (ps, me) => { - // Fetch the group - const userGroup = await UserGroups.findOne({ - id: ps.groupId, - userId: me.id, - }); - - if (userGroup == null) { - throw new ApiError(meta.errors.noSuchGroup); - } - - // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - const joining = await UserGroupJoinings.findOne({ - userGroupId: userGroup.id, - userId: user.id - }); - - if (joining) { - throw new ApiError(meta.errors.alreadyAdded); - } - - const existInvitation = await UserGroupInvitations.findOne({ - userGroupId: userGroup.id, - userId: user.id - }); - - if (existInvitation) { - throw new ApiError(meta.errors.alreadyInvited); - } - - const invitation = await UserGroupInvitations.insert({ - id: genId(), - createdAt: new Date(), - userId: user.id, - userGroupId: userGroup.id - } as UserGroupInvitation).then(x => UserGroupInvitations.findOneOrFail(x.identifiers[0])); - - // 通知を作成 - createNotification(user.id, 'groupInvited', { - notifierId: me.id, - userGroupInvitationId: invitation.id - }); -}); diff --git a/src/server/api/endpoints/users/groups/joined.ts b/src/server/api/endpoints/users/groups/joined.ts deleted file mode 100644 index d5e8fe4032..0000000000 --- a/src/server/api/endpoints/users/groups/joined.ts +++ /dev/null @@ -1,36 +0,0 @@ -import define from '../../../define'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; -import { Not, In } from 'typeorm'; - -export const meta = { - tags: ['groups', 'account'], - - requireCredential: true as const, - - kind: 'read:user-groups', - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserGroup', - } - }, -}; - -export default define(meta, async (ps, me) => { - const ownedGroups = await UserGroups.find({ - userId: me.id, - }); - - const joinings = await UserGroupJoinings.find({ - userId: me.id, - ...(ownedGroups.length > 0 ? { - userGroupId: Not(In(ownedGroups.map(x => x.id))) - } : {}) - }); - - return await Promise.all(joinings.map(x => UserGroups.pack(x.userGroupId))); -}); diff --git a/src/server/api/endpoints/users/groups/leave.ts b/src/server/api/endpoints/users/groups/leave.ts deleted file mode 100644 index 0e52f2abdf..0000000000 --- a/src/server/api/endpoints/users/groups/leave.ts +++ /dev/null @@ -1,50 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; - -export const meta = { - tags: ['groups', 'users'], - - requireCredential: true as const, - - kind: 'write:user-groups', - - params: { - groupId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '62780270-1f67-5dc0-daca-3eb510612e31' - }, - - youAreOwner: { - message: 'Your are the owner.', - code: 'YOU_ARE_OWNER', - id: 'b6d6e0c2-ef8a-9bb8-653d-79f4a3107c69' - }, - } -}; - -export default define(meta, async (ps, me) => { - // Fetch the group - const userGroup = await UserGroups.findOne({ - id: ps.groupId, - }); - - if (userGroup == null) { - throw new ApiError(meta.errors.noSuchGroup); - } - - if (me.id === userGroup.userId) { - throw new ApiError(meta.errors.youAreOwner); - } - - await UserGroupJoinings.delete({ userGroupId: userGroup.id, userId: me.id }); -}); diff --git a/src/server/api/endpoints/users/groups/owned.ts b/src/server/api/endpoints/users/groups/owned.ts deleted file mode 100644 index 17de370dbc..0000000000 --- a/src/server/api/endpoints/users/groups/owned.ts +++ /dev/null @@ -1,28 +0,0 @@ -import define from '../../../define'; -import { UserGroups } from '@/models/index'; - -export const meta = { - tags: ['groups', 'account'], - - requireCredential: true as const, - - kind: 'read:user-groups', - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserGroup', - } - }, -}; - -export default define(meta, async (ps, me) => { - const userGroups = await UserGroups.find({ - userId: me.id, - }); - - return await Promise.all(userGroups.map(x => UserGroups.pack(x))); -}); diff --git a/src/server/api/endpoints/users/groups/pull.ts b/src/server/api/endpoints/users/groups/pull.ts deleted file mode 100644 index ce4d2e2881..0000000000 --- a/src/server/api/endpoints/users/groups/pull.ts +++ /dev/null @@ -1,69 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; - -export const meta = { - tags: ['groups', 'users'], - - requireCredential: true as const, - - kind: 'write:user-groups', - - params: { - groupId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '4662487c-05b1-4b78-86e5-fd46998aba74' - }, - - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '0b5cc374-3681-41da-861e-8bc1146f7a55' - }, - - isOwner: { - message: 'The user is the owner.', - code: 'IS_OWNER', - id: '1546eed5-4414-4dea-81c1-b0aec4f6d2af' - }, - } -}; - -export default define(meta, async (ps, me) => { - // Fetch the group - const userGroup = await UserGroups.findOne({ - id: ps.groupId, - userId: me.id, - }); - - if (userGroup == null) { - throw new ApiError(meta.errors.noSuchGroup); - } - - // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - if (user.id === userGroup.userId) { - throw new ApiError(meta.errors.isOwner); - } - - // Pull the user - await UserGroupJoinings.delete({ userGroupId: userGroup.id, userId: user.id }); -}); diff --git a/src/server/api/endpoints/users/groups/show.ts b/src/server/api/endpoints/users/groups/show.ts deleted file mode 100644 index 3c030bf3a5..0000000000 --- a/src/server/api/endpoints/users/groups/show.ts +++ /dev/null @@ -1,55 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; - -export const meta = { - tags: ['groups', 'account'], - - requireCredential: true as const, - - kind: 'read:user-groups', - - params: { - groupId: { - validator: $.type(ID), - }, - }, - - res: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserGroup', - }, - - errors: { - noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: 'ea04751e-9b7e-487b-a509-330fb6bd6b9b' - }, - } -}; - -export default define(meta, async (ps, me) => { - // Fetch the group - const userGroup = await UserGroups.findOne({ - id: ps.groupId, - }); - - if (userGroup == null) { - throw new ApiError(meta.errors.noSuchGroup); - } - - const joining = await UserGroupJoinings.findOne({ - userId: me.id, - userGroupId: userGroup.id - }); - - if (joining == null && userGroup.userId !== me.id) { - throw new ApiError(meta.errors.noSuchGroup); - } - - return await UserGroups.pack(userGroup); -}); diff --git a/src/server/api/endpoints/users/groups/transfer.ts b/src/server/api/endpoints/users/groups/transfer.ts deleted file mode 100644 index 17c42e1127..0000000000 --- a/src/server/api/endpoints/users/groups/transfer.ts +++ /dev/null @@ -1,83 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { getUser } from '../../../common/getters'; -import { UserGroups, UserGroupJoinings } from '@/models/index'; - -export const meta = { - tags: ['groups', 'users'], - - requireCredential: true as const, - - kind: 'write:user-groups', - - params: { - groupId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - - res: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserGroup', - }, - - errors: { - noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '8e31d36b-2f88-4ccd-a438-e2d78a9162db' - }, - - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '711f7ebb-bbb9-4dfa-b540-b27809fed5e9' - }, - - noSuchGroupMember: { - message: 'No such group member.', - code: 'NO_SUCH_GROUP_MEMBER', - id: 'd31bebee-196d-42c2-9a3e-9474d4be6cc4' - }, - } -}; - -export default define(meta, async (ps, me) => { - // Fetch the group - const userGroup = await UserGroups.findOne({ - id: ps.groupId, - userId: me.id, - }); - - if (userGroup == null) { - throw new ApiError(meta.errors.noSuchGroup); - } - - // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - const joining = await UserGroupJoinings.findOne({ - userGroupId: userGroup.id, - userId: user.id - }); - - if (joining == null) { - throw new ApiError(meta.errors.noSuchGroupMember); - } - - await UserGroups.update(userGroup.id, { - userId: ps.userId - }); - - return await UserGroups.pack(userGroup.id); -}); diff --git a/src/server/api/endpoints/users/groups/update.ts b/src/server/api/endpoints/users/groups/update.ts deleted file mode 100644 index 127bbc47a1..0000000000 --- a/src/server/api/endpoints/users/groups/update.ts +++ /dev/null @@ -1,55 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserGroups } from '@/models/index'; - -export const meta = { - tags: ['groups'], - - requireCredential: true as const, - - kind: 'write:user-groups', - - params: { - groupId: { - validator: $.type(ID), - }, - - name: { - validator: $.str.range(1, 100), - } - }, - - res: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserGroup', - }, - - errors: { - noSuchGroup: { - message: 'No such group.', - code: 'NO_SUCH_GROUP', - id: '9081cda3-7a9e-4fac-a6ce-908d70f282f6' - }, - } -}; - -export default define(meta, async (ps, me) => { - // Fetch the group - const userGroup = await UserGroups.findOne({ - id: ps.groupId, - userId: me.id - }); - - if (userGroup == null) { - throw new ApiError(meta.errors.noSuchGroup); - } - - await UserGroups.update(userGroup.id, { - name: ps.name - }); - - return await UserGroups.pack(userGroup.id); -}); diff --git a/src/server/api/endpoints/users/lists/create.ts b/src/server/api/endpoints/users/lists/create.ts deleted file mode 100644 index e0bfe611fc..0000000000 --- a/src/server/api/endpoints/users/lists/create.ts +++ /dev/null @@ -1,36 +0,0 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { UserLists } from '@/models/index'; -import { genId } from '@/misc/gen-id'; -import { UserList } from '@/models/entities/user-list'; - -export const meta = { - tags: ['lists'], - - requireCredential: true as const, - - kind: 'write:account', - - params: { - name: { - validator: $.str.range(1, 100) - } - }, - - res: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserList', - }, -}; - -export default define(meta, async (ps, user) => { - const userList = await UserLists.insert({ - id: genId(), - createdAt: new Date(), - userId: user.id, - name: ps.name, - } as UserList).then(x => UserLists.findOneOrFail(x.identifiers[0])); - - 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 deleted file mode 100644 index 5fe3bfb03d..0000000000 --- a/src/server/api/endpoints/users/lists/delete.ts +++ /dev/null @@ -1,40 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserLists } from '@/models/index'; - -export const meta = { - tags: ['lists'], - - requireCredential: true as const, - - kind: 'write:account', - - params: { - listId: { - validator: $.type(ID), - } - }, - - errors: { - noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '78436795-db79-42f5-b1e2-55ea2cf19166' - } - } -}; - -export default define(meta, async (ps, user) => { - const userList = await UserLists.findOne({ - id: ps.listId, - userId: user.id - }); - - if (userList == null) { - throw new ApiError(meta.errors.noSuchList); - } - - 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 deleted file mode 100644 index cf0c92bb84..0000000000 --- a/src/server/api/endpoints/users/lists/list.ts +++ /dev/null @@ -1,28 +0,0 @@ -import define from '../../../define'; -import { UserLists } from '@/models/index'; - -export const meta = { - tags: ['lists', 'account'], - - requireCredential: true as const, - - kind: 'read:account', - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserList', - } - }, -}; - -export default define(meta, async (ps, me) => { - const userLists = await UserLists.find({ - userId: me.id, - }); - - 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 deleted file mode 100644 index d4357fc5e7..0000000000 --- a/src/server/api/endpoints/users/lists/pull.ts +++ /dev/null @@ -1,62 +0,0 @@ -import $ from 'cafy'; -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/index'; - -export const meta = { - tags: ['lists', 'users'], - - requireCredential: true as const, - - kind: 'write:account', - - params: { - listId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '7f44670e-ab16-43b8-b4c1-ccd2ee89cc02' - }, - - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '588e7f72-c744-4a61-b180-d354e912bda2' - } - } -}; - -export default define(meta, async (ps, me) => { - // Fetch the list - const userList = await UserLists.findOne({ - id: ps.listId, - userId: me.id, - }); - - if (userList == null) { - throw new ApiError(meta.errors.noSuchList); - } - - // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - // Pull the user - await UserListJoinings.delete({ userListId: userList.id, userId: user.id }); - - 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 deleted file mode 100644 index 8e21059d3d..0000000000 --- a/src/server/api/endpoints/users/lists/push.ts +++ /dev/null @@ -1,92 +0,0 @@ -import $ from 'cafy'; -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, Blockings } from '@/models/index'; - -export const meta = { - tags: ['lists', 'users'], - - requireCredential: true as const, - - kind: 'write:account', - - params: { - listId: { - validator: $.type(ID), - }, - - userId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '2214501d-ac96-4049-b717-91e42272a711' - }, - - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: 'a89abd3d-f0bc-4cce-beb1-2f446f4f1e6a' - }, - - alreadyAdded: { - message: 'That user has already been added to that list.', - code: 'ALREADY_ADDED', - id: '1de7c884-1595-49e9-857e-61f12f4d4fc5' - }, - - youHaveBeenBlocked: { - message: 'You cannot push this user because you have been blocked by this user.', - code: 'YOU_HAVE_BEEN_BLOCKED', - id: '990232c5-3f9d-4d83-9f3f-ef27b6332a4b' - }, - } -}; - -export default define(meta, async (ps, me) => { - // Fetch the list - const userList = await UserLists.findOne({ - id: ps.listId, - userId: me.id, - }); - - if (userList == null) { - throw new ApiError(meta.errors.noSuchList); - } - - // Fetch the user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - // Check blocking - if (user.id !== me.id) { - const block = await Blockings.findOne({ - blockerId: user.id, - blockeeId: me.id, - }); - if (block) { - throw new ApiError(meta.errors.youHaveBeenBlocked); - } - } - - const exist = await UserListJoinings.findOne({ - userListId: userList.id, - userId: user.id - }); - - if (exist) { - throw new ApiError(meta.errors.alreadyAdded); - } - - // Push the user - await pushUserToUserList(user, userList); -}); diff --git a/src/server/api/endpoints/users/lists/show.ts b/src/server/api/endpoints/users/lists/show.ts deleted file mode 100644 index f9a35cdab3..0000000000 --- a/src/server/api/endpoints/users/lists/show.ts +++ /dev/null @@ -1,47 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserLists } from '@/models/index'; - -export const meta = { - tags: ['lists', 'account'], - - requireCredential: true as const, - - kind: 'read:account', - - params: { - listId: { - validator: $.type(ID), - }, - }, - - res: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserList', - }, - - errors: { - noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '7bc05c21-1d7a-41ae-88f1-66820f4dc686' - }, - } -}; - -export default define(meta, async (ps, me) => { - // Fetch the list - const userList = await UserLists.findOne({ - id: ps.listId, - userId: me.id, - }); - - if (userList == null) { - throw new ApiError(meta.errors.noSuchList); - } - - 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 deleted file mode 100644 index 1185af5043..0000000000 --- a/src/server/api/endpoints/users/lists/update.ts +++ /dev/null @@ -1,55 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; -import { ApiError } from '../../../error'; -import { UserLists } from '@/models/index'; - -export const meta = { - tags: ['lists'], - - requireCredential: true as const, - - kind: 'write:account', - - params: { - listId: { - validator: $.type(ID), - }, - - name: { - validator: $.str.range(1, 100), - } - }, - - res: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'UserList', - }, - - errors: { - noSuchList: { - message: 'No such list.', - code: 'NO_SUCH_LIST', - id: '796666fe-3dff-4d39-becb-8a5932c1d5b7' - }, - } -}; - -export default define(meta, async (ps, user) => { - // Fetch the list - const userList = await UserLists.findOne({ - id: ps.listId, - userId: user.id - }); - - if (userList == null) { - throw new ApiError(meta.errors.noSuchList); - } - - await UserLists.update(userList.id, { - name: ps.name - }); - - return await UserLists.pack(userList.id); -}); diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts deleted file mode 100644 index 0afbad9d04..0000000000 --- a/src/server/api/endpoints/users/notes.ts +++ /dev/null @@ -1,144 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -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/index'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { Brackets } from 'typeorm'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; - -export const meta = { - tags: ['users', 'notes'], - - params: { - userId: { - validator: $.type(ID), - }, - - includeReplies: { - validator: $.optional.bool, - default: true, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - - includeMyRenotes: { - validator: $.optional.bool, - default: true, - }, - - withFiles: { - validator: $.optional.bool, - default: false, - }, - - fileType: { - validator: $.optional.arr($.str), - }, - - excludeNsfw: { - validator: $.optional.bool, - default: false, - }, - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'Note', - } - }, - - errors: { - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '27e494ba-2ac2-48e8-893b-10d4d8c2387b' - } - } -}; - -export default define(meta, async (ps, me) => { - // Lookup user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - //#region Construct query - const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere('note.userId = :userId', { userId: user.id }) - .innerJoinAndSelect('note.user', 'user') - .leftJoinAndSelect('note.reply', 'reply') - .leftJoinAndSelect('note.renote', 'renote') - .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); - - generateVisibilityQuery(query, me); - if (me) generateMutedUserQuery(query, me, user); - if (me) generateBlockedUserQuery(query, me); - - if (ps.withFiles) { - query.andWhere('note.fileIds != \'{}\''); - } - - if (ps.fileType != null) { - 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.excludeNsfw) { - query.andWhere('note.cw IS NULL'); - query.andWhere('0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)'); - } - } - - if (!ps.includeReplies) { - query.andWhere('note.replyId IS NULL'); - } - - if (ps.includeMyRenotes === false) { - query.andWhere(new Brackets(qb => { - qb.orWhere('note.userId != :userId', { userId: user.id }); - qb.orWhere('note.renoteId IS NULL'); - qb.orWhere('note.text IS NOT NULL'); - qb.orWhere('note.fileIds != \'{}\''); - qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)'); - })); - } - - //#endregion - - const timeline = await query.take(ps.limit!).getMany(); - - return await Notes.packMany(timeline, me); -}); diff --git a/src/server/api/endpoints/users/pages.ts b/src/server/api/endpoints/users/pages.ts deleted file mode 100644 index 24e9e207fd..0000000000 --- a/src/server/api/endpoints/users/pages.ts +++ /dev/null @@ -1,40 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { Pages } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; - -export const meta = { - tags: ['users', 'pages'], - - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10 - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - } -}; - -export default define(meta, async (ps, user) => { - const query = makePaginationQuery(Pages.createQueryBuilder('page'), ps.sinceId, ps.untilId) - .andWhere(`page.userId = :userId`, { userId: ps.userId }) - .andWhere('page.visibility = \'public\''); - - const pages = await query - .take(ps.limit!) - .getMany(); - - return await Pages.packMany(pages); -}); diff --git a/src/server/api/endpoints/users/reactions.ts b/src/server/api/endpoints/users/reactions.ts deleted file mode 100644 index fe5e4d84a9..0000000000 --- a/src/server/api/endpoints/users/reactions.ts +++ /dev/null @@ -1,79 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { NoteReactions, UserProfiles } from '@/models/index'; -import { makePaginationQuery } from '../../common/make-pagination-query'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { ApiError } from '../../error'; - -export const meta = { - tags: ['users', 'reactions'], - - requireCredential: false as const, - - params: { - userId: { - validator: $.type(ID), - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - sinceId: { - validator: $.optional.type(ID), - }, - - untilId: { - validator: $.optional.type(ID), - }, - - sinceDate: { - validator: $.optional.num, - }, - - untilDate: { - validator: $.optional.num, - }, - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'NoteReaction', - } - }, - - errors: { - reactionsNotPublic: { - message: 'Reactions of the user is not public.', - code: 'REACTIONS_NOT_PUBLIC', - id: '673a7dd2-6924-1093-e0c0-e68456ceae5c' - }, - } -}; - -export default define(meta, async (ps, me) => { - const profile = await UserProfiles.findOneOrFail(ps.userId); - - if (me == null || (me.id !== ps.userId && !profile.publicReactions)) { - throw new ApiError(meta.errors.reactionsNotPublic); - } - - const query = makePaginationQuery(NoteReactions.createQueryBuilder('reaction'), - ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) - .andWhere(`reaction.userId = :userId`, { userId: ps.userId }) - .leftJoinAndSelect('reaction.note', 'note'); - - generateVisibilityQuery(query, me); - - const reactions = await query - .take(ps.limit!) - .getMany(); - - return await Promise.all(reactions.map(reaction => NoteReactions.pack(reaction, me, { withNote: true }))); -}); diff --git a/src/server/api/endpoints/users/recommendation.ts b/src/server/api/endpoints/users/recommendation.ts deleted file mode 100644 index dde6bb1037..0000000000 --- a/src/server/api/endpoints/users/recommendation.ts +++ /dev/null @@ -1,63 +0,0 @@ -import * as ms from 'ms'; -import $ from 'cafy'; -import define from '../../define'; -import { Users, Followings } from '@/models/index'; -import { generateMutedUserQueryForUsers } from '../../common/generate-muted-user-query'; -import { generateBlockedUserQuery, generateBlockQueryForUsers } from '../../common/generate-block-query'; - -export const meta = { - tags: ['users'], - - requireCredential: true as const, - - kind: 'read:account', - - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10 - }, - - offset: { - validator: $.optional.num.min(0), - default: 0 - } - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - } - }, -}; - -export default define(meta, async (ps, me) => { - const query = Users.createQueryBuilder('user') - .where('user.isLocked = FALSE') - .andWhere('user.isExplorable = TRUE') - .andWhere('user.host IS NULL') - .andWhere('user.updatedAt >= :date', { date: new Date(Date.now() - ms('7days')) }) - .andWhere('user.id != :meId', { meId: me.id }) - .orderBy('user.followersCount', 'DESC'); - - generateMutedUserQueryForUsers(query, me); - generateBlockQueryForUsers(query, me); - generateBlockedUserQuery(query, me); - - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: me.id }); - - query - .andWhere(`user.id NOT IN (${ followingQuery.getQuery() })`); - - query.setParameters(followingQuery.getParameters()); - - const users = await query.take(ps.limit!).skip(ps.offset).getMany(); - - return await Users.packMany(users, me, { detail: true }); -}); diff --git a/src/server/api/endpoints/users/relation.ts b/src/server/api/endpoints/users/relation.ts deleted file mode 100644 index 32d76a5322..0000000000 --- a/src/server/api/endpoints/users/relation.ts +++ /dev/null @@ -1,111 +0,0 @@ -import $ from 'cafy'; -import define from '../../define'; -import { ID } from '@/misc/cafy-id'; -import { Users } from '@/models/index'; - -export const meta = { - tags: ['users'], - - requireCredential: true as const, - - params: { - userId: { - validator: $.either($.type(ID), $.arr($.type(ID)).unique()), - } - }, - - res: { - oneOf: [ - { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id' - }, - isFollowing: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - hasPendingFollowRequestFromYou: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - hasPendingFollowRequestToYou: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - isFollowed: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - isBlocking: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - isBlocked: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - isMuted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - } - } - }, - { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - properties: { - id: { - type: 'string' as const, - optional: false as const, nullable: false as const, - format: 'id' - }, - isFollowing: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - hasPendingFollowRequestFromYou: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - hasPendingFollowRequestToYou: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - isFollowed: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - isBlocking: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - isBlocked: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - }, - isMuted: { - type: 'boolean' as const, - optional: false as const, nullable: false as const - } - } - } - } - ] - } -}; - -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 => 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 deleted file mode 100644 index 2c8672cd47..0000000000 --- a/src/server/api/endpoints/users/report-abuse.ts +++ /dev/null @@ -1,90 +0,0 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { publishAdminStream } from '@/services/stream'; -import { ApiError } from '../../error'; -import { getUser } from '../../common/getters'; -import { AbuseUserReports, Users } from '@/models/index'; -import { genId } from '@/misc/gen-id'; - -export const meta = { - tags: ['users'], - - requireCredential: true as const, - - params: { - userId: { - validator: $.type(ID), - }, - - comment: { - validator: $.str.range(1, 2048), - }, - }, - - errors: { - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '1acefcb5-0959-43fd-9685-b48305736cb5' - }, - - cannotReportYourself: { - message: 'Cannot report yourself.', - code: 'CANNOT_REPORT_YOURSELF', - id: '1e13149e-b1e8-43cf-902e-c01dbfcb202f' - }, - - cannotReportAdmin: { - message: 'Cannot report the admin.', - code: 'CANNOT_REPORT_THE_ADMIN', - id: '35e166f5-05fb-4f87-a2d5-adb42676d48f' - } - } -}; - -export default define(meta, async (ps, me) => { - // Lookup user - const user = await getUser(ps.userId).catch(e => { - if (e.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - if (user.id === me.id) { - throw new ApiError(meta.errors.cannotReportYourself); - } - - if (user.isAdmin) { - throw new ApiError(meta.errors.cannotReportAdmin); - } - - const report = await AbuseUserReports.save({ - id: genId(), - createdAt: new Date(), - targetUserId: user.id, - targetUserHost: user.host, - reporterId: me.id, - reporterHost: null, - comment: ps.comment, - }); - - // Publish event to moderators - setTimeout(async () => { - const moderators = await Users.find({ - where: [{ - isAdmin: true - }, { - isModerator: true - }] - }); - - for (const moderator of moderators) { - publishAdminStream(moderator.id, 'newAbuseUserReport', { - id: report.id, - targetUserId: report.targetUserId, - reporterId: report.reporterId, - comment: report.comment - }); - } - }, 1); -}); diff --git a/src/server/api/endpoints/users/search-by-username-and-host.ts b/src/server/api/endpoints/users/search-by-username-and-host.ts deleted file mode 100644 index 1ec5e1a743..0000000000 --- a/src/server/api/endpoints/users/search-by-username-and-host.ts +++ /dev/null @@ -1,116 +0,0 @@ -import $ from 'cafy'; -import define from '../../define'; -import { Followings, Users } from '@/models/index'; -import { Brackets } from 'typeorm'; -import { USER_ACTIVE_THRESHOLD } from '@/const'; -import { User } from '@/models/entities/user'; - -export const meta = { - tags: ['users'], - - requireCredential: false as const, - - params: { - username: { - validator: $.optional.nullable.str, - }, - - host: { - validator: $.optional.nullable.str, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - detail: { - validator: $.optional.bool, - default: true, - }, - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - } - }, -}; - -export default define(meta, async (ps, me) => { - const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 - - if (ps.host) { - const q = Users.createQueryBuilder('user') - .where('user.isSuspended = FALSE') - .andWhere('user.host LIKE :host', { host: ps.host.toLowerCase() + '%' }); - - if (ps.username) { - q.andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }); - } - - q.andWhere('user.updatedAt IS NOT NULL'); - q.orderBy('user.updatedAt', 'DESC'); - - const users = await q.take(ps.limit!).getMany(); - - return await Users.packMany(users, me, { detail: ps.detail }); - } else if (ps.username) { - let users: User[] = []; - - if (me) { - const followingQuery = Followings.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: me.id }); - - const query = Users.createQueryBuilder('user') - .where(`user.id IN (${ followingQuery.getQuery() })`) - .andWhere(`user.id != :meId`, { meId: me.id }) - .andWhere('user.isSuspended = FALSE') - .andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) - .andWhere(new Brackets(qb => { qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })); - - query.setParameters(followingQuery.getParameters()); - - users = await query - .orderBy('user.usernameLower', 'ASC') - .take(ps.limit!) - .getMany(); - - if (users.length < ps.limit!) { - const otherQuery = await Users.createQueryBuilder('user') - .where(`user.id NOT IN (${ followingQuery.getQuery() })`) - .andWhere(`user.id != :meId`, { meId: me.id }) - .andWhere('user.isSuspended = FALSE') - .andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) - .andWhere('user.updatedAt IS NOT NULL'); - - otherQuery.setParameters(followingQuery.getParameters()); - - const otherUsers = await otherQuery - .orderBy('user.updatedAt', 'DESC') - .take(ps.limit! - users.length) - .getMany(); - - users = users.concat(otherUsers); - } - } else { - users = await Users.createQueryBuilder('user') - .where('user.isSuspended = FALSE') - .andWhere('user.usernameLower LIKE :username', { username: ps.username.toLowerCase() + '%' }) - .andWhere('user.updatedAt IS NOT NULL') - .orderBy('user.updatedAt', 'DESC') - .take(ps.limit! - users.length) - .getMany(); - } - - return await Users.packMany(users, me, { detail: ps.detail }); - } -}); diff --git a/src/server/api/endpoints/users/search.ts b/src/server/api/endpoints/users/search.ts deleted file mode 100644 index 9aa988d9ed..0000000000 --- a/src/server/api/endpoints/users/search.ts +++ /dev/null @@ -1,127 +0,0 @@ -import $ from 'cafy'; -import define from '../../define'; -import { UserProfiles, Users } from '@/models/index'; -import { User } from '@/models/entities/user'; -import { Brackets } from 'typeorm'; - -export const meta = { - tags: ['users'], - - requireCredential: false as const, - - params: { - query: { - validator: $.str, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - origin: { - validator: $.optional.str.or(['local', 'remote', 'combined']), - default: 'combined', - }, - - detail: { - validator: $.optional.bool, - default: true, - }, - }, - - res: { - type: 'array' as const, - optional: false as const, nullable: false as const, - items: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - } - }, -}; - -export default define(meta, async (ps, me) => { - const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 - - const isUsername = ps.query.startsWith('@'); - - let users: User[] = []; - - if (isUsername) { - const usernameQuery = Users.createQueryBuilder('user') - .where('user.usernameLower LIKE :username', { username: ps.query.replace('@', '').toLowerCase() + '%' }) - .andWhere(new Brackets(qb => { qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })) - .andWhere('user.isSuspended = FALSE'); - - if (ps.origin === 'local') { - usernameQuery.andWhere('user.host IS NULL'); - } else if (ps.origin === 'remote') { - usernameQuery.andWhere('user.host IS NOT NULL'); - } - - users = await usernameQuery - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') - .take(ps.limit!) - .skip(ps.offset) - .getMany(); - } else { - const nameQuery = Users.createQueryBuilder('user') - .where('user.name ILIKE :query', { query: '%' + ps.query + '%' }) - .andWhere(new Brackets(qb => { qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })) - .andWhere('user.isSuspended = FALSE'); - - if (ps.origin === 'local') { - nameQuery.andWhere('user.host IS NULL'); - } else if (ps.origin === 'remote') { - nameQuery.andWhere('user.host IS NOT NULL'); - } - - users = await nameQuery - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') - .take(ps.limit!) - .skip(ps.offset) - .getMany(); - - if (users.length < ps.limit!) { - const profQuery = UserProfiles.createQueryBuilder('prof') - .select('prof.userId') - .where('prof.description ILIKE :query', { query: '%' + ps.query + '%' }); - - if (ps.origin === 'local') { - profQuery.andWhere('prof.userHost IS NULL'); - } else if (ps.origin === 'remote') { - profQuery.andWhere('prof.userHost IS NOT NULL'); - } - - const query = Users.createQueryBuilder('user') - .where(`user.id IN (${ profQuery.getQuery() })`) - .andWhere(new Brackets(qb => { qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })) - .andWhere('user.isSuspended = FALSE') - .setParameters(profQuery.getParameters()); - - users = users.concat(await query - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') - .take(ps.limit!) - .skip(ps.offset) - .getMany() - ); - } - } - - 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 deleted file mode 100644 index f056983636..0000000000 --- a/src/server/api/endpoints/users/show.ts +++ /dev/null @@ -1,105 +0,0 @@ -import $ from 'cafy'; -import { resolveUser } from '@/remote/resolve-user'; -import define from '../../define'; -import { apiLogger } from '../../logger'; -import { ApiError } from '../../error'; -import { ID } from '@/misc/cafy-id'; -import { Users } from '@/models/index'; -import { In } from 'typeorm'; -import { User } from '@/models/entities/user'; - -export const meta = { - tags: ['users'], - - requireCredential: false as const, - - params: { - userId: { - validator: $.optional.type(ID), - }, - - userIds: { - validator: $.optional.arr($.type(ID)).unique(), - }, - - username: { - validator: $.optional.str - }, - - host: { - validator: $.optional.nullable.str - } - }, - - res: { - type: 'object' as const, - optional: false as const, nullable: false as const, - ref: 'User', - }, - - errors: { - failedToResolveRemoteUser: { - message: 'Failed to resolve remote user.', - code: 'FAILED_TO_RESOLVE_REMOTE_USER', - id: 'ef7b9be4-9cba-4e6f-ab41-90ed171c7d3c', - kind: 'server' as const - }, - - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '4362f8dc-731f-4ad8-a694-be5a88922a24' - }, - } -}; - -export default define(meta, async (ps, me) => { - let user; - - const isAdminOrModerator = me && (me.isAdmin || me.isModerator); - - if (ps.userIds) { - if (ps.userIds.length === 0) { - return []; - } - - const users = await Users.find(isAdminOrModerator ? { - id: In(ps.userIds) - } : { - id: In(ps.userIds), - isSuspended: false - }); - - // リクエストされた通りに並べ替え - const _users: User[] = []; - for (const id of ps.userIds) { - _users.push(users.find(x => x.id === id)!); - } - - return await Promise.all(_users.map(u => Users.pack(u, me, { - detail: true - }))); - } else { - // Lookup user - if (typeof ps.host === 'string' && typeof ps.username === 'string') { - user = await resolveUser(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 } - : { usernameLower: ps.username!.toLowerCase(), host: null }; - - user = await Users.findOne(q); - } - - if (user == null || (!isAdminOrModerator && user.isSuspended)) { - throw new ApiError(meta.errors.noSuchUser); - } - - return await Users.pack(user, me, { - detail: true - }); - } -}); diff --git a/src/server/api/endpoints/users/stats.ts b/src/server/api/endpoints/users/stats.ts deleted file mode 100644 index ef8afd5625..0000000000 --- a/src/server/api/endpoints/users/stats.ts +++ /dev/null @@ -1,144 +0,0 @@ -import $ from 'cafy'; -import define from '../../define'; -import { ApiError } from '../../error'; -import { ID } from '@/misc/cafy-id'; -import { DriveFiles, Followings, NoteFavorites, NoteReactions, Notes, PageLikes, PollVotes, ReversiGames, Users } from '@/models/index'; - -export const meta = { - tags: ['users'], - - requireCredential: false as const, - - params: { - userId: { - validator: $.type(ID), - }, - }, - - errors: { - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '9e638e45-3b25-4ef7-8f95-07e8498f1819' - }, - } -}; - -export default define(meta, async (ps, me) => { - const user = await Users.findOne(ps.userId); - if (user == null) { - throw new ApiError(meta.errors.noSuchUser); - } - - const [ - notesCount, - repliesCount, - renotesCount, - repliedCount, - renotedCount, - pollVotesCount, - pollVotedCount, - localFollowingCount, - remoteFollowingCount, - localFollowersCount, - remoteFollowersCount, - sentReactionsCount, - receivedReactionsCount, - noteFavoritesCount, - pageLikesCount, - pageLikedCount, - driveFilesCount, - driveUsage, - reversiCount, - ] = await Promise.all([ - Notes.createQueryBuilder('note') - .where('note.userId = :userId', { userId: user.id }) - .getCount(), - Notes.createQueryBuilder('note') - .where('note.userId = :userId', { userId: user.id }) - .andWhere('note.replyId IS NOT NULL') - .getCount(), - Notes.createQueryBuilder('note') - .where('note.userId = :userId', { userId: user.id }) - .andWhere('note.renoteId IS NOT NULL') - .getCount(), - Notes.createQueryBuilder('note') - .where('note.replyUserId = :userId', { userId: user.id }) - .getCount(), - Notes.createQueryBuilder('note') - .where('note.renoteUserId = :userId', { userId: user.id }) - .getCount(), - PollVotes.createQueryBuilder('vote') - .where('vote.userId = :userId', { userId: user.id }) - .getCount(), - PollVotes.createQueryBuilder('vote') - .innerJoin('vote.note', 'note') - .where('note.userId = :userId', { userId: user.id }) - .getCount(), - Followings.createQueryBuilder('following') - .where('following.followerId = :userId', { userId: user.id }) - .andWhere('following.followeeHost IS NULL') - .getCount(), - Followings.createQueryBuilder('following') - .where('following.followerId = :userId', { userId: user.id }) - .andWhere('following.followeeHost IS NOT NULL') - .getCount(), - Followings.createQueryBuilder('following') - .where('following.followeeId = :userId', { userId: user.id }) - .andWhere('following.followerHost IS NULL') - .getCount(), - Followings.createQueryBuilder('following') - .where('following.followeeId = :userId', { userId: user.id }) - .andWhere('following.followerHost IS NOT NULL') - .getCount(), - NoteReactions.createQueryBuilder('reaction') - .where('reaction.userId = :userId', { userId: user.id }) - .getCount(), - NoteReactions.createQueryBuilder('reaction') - .innerJoin('reaction.note', 'note') - .where('note.userId = :userId', { userId: user.id }) - .getCount(), - NoteFavorites.createQueryBuilder('favorite') - .where('favorite.userId = :userId', { userId: user.id }) - .getCount(), - PageLikes.createQueryBuilder('like') - .where('like.userId = :userId', { userId: user.id }) - .getCount(), - PageLikes.createQueryBuilder('like') - .innerJoin('like.page', 'page') - .where('page.userId = :userId', { userId: user.id }) - .getCount(), - DriveFiles.createQueryBuilder('file') - .where('file.userId = :userId', { userId: user.id }) - .getCount(), - DriveFiles.calcDriveUsageOf(user), - ReversiGames.createQueryBuilder('game') - .where('game.user1Id = :userId', { userId: user.id }) - .orWhere('game.user2Id = :userId', { userId: user.id }) - .getCount(), - ]); - - return { - notesCount, - repliesCount, - renotesCount, - repliedCount, - renotedCount, - pollVotesCount, - pollVotedCount, - localFollowingCount, - remoteFollowingCount, - localFollowersCount, - remoteFollowersCount, - followingCount: localFollowingCount + remoteFollowingCount, - followersCount: localFollowersCount + remoteFollowersCount, - sentReactionsCount, - receivedReactionsCount, - noteFavoritesCount, - pageLikesCount, - pageLikedCount, - driveFilesCount, - driveUsage, - reversiCount, - }; -}); |