summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints/users/groups
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-11-12 02:02:25 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2021-11-12 02:02:25 +0900
commit0e4a111f81cceed275d9bec2695f6e401fb654d8 (patch)
tree40874799472fa07416f17b50a398ac33b7771905 /packages/backend/src/server/api/endpoints/users/groups
parentupdate deps (diff)
downloadmisskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.gz
misskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.bz2
misskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.zip
refactoring
Resolve #7779
Diffstat (limited to 'packages/backend/src/server/api/endpoints/users/groups')
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/create.ts45
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/delete.ts40
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts54
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts44
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/invite.ts102
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/joined.ts36
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/leave.ts50
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/owned.ts28
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/pull.ts69
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/show.ts55
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/transfer.ts83
-rw-r--r--packages/backend/src/server/api/endpoints/users/groups/update.ts55
12 files changed, 661 insertions, 0 deletions
diff --git a/packages/backend/src/server/api/endpoints/users/groups/create.ts b/packages/backend/src/server/api/endpoints/users/groups/create.ts
new file mode 100644
index 0000000000..dc1ee3879e
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/create.ts
@@ -0,0 +1,45 @@
+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/packages/backend/src/server/api/endpoints/users/groups/delete.ts b/packages/backend/src/server/api/endpoints/users/groups/delete.ts
new file mode 100644
index 0000000000..7da1b4a273
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/delete.ts
@@ -0,0 +1,40 @@
+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/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts
new file mode 100644
index 0000000000..09e6ae2647
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/invitations/accept.ts
@@ -0,0 +1,54 @@
+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/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts b/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts
new file mode 100644
index 0000000000..741fcefb35
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/invitations/reject.ts
@@ -0,0 +1,44 @@
+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/packages/backend/src/server/api/endpoints/users/groups/invite.ts b/packages/backend/src/server/api/endpoints/users/groups/invite.ts
new file mode 100644
index 0000000000..f1ee8bf8b7
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/invite.ts
@@ -0,0 +1,102 @@
+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/packages/backend/src/server/api/endpoints/users/groups/joined.ts b/packages/backend/src/server/api/endpoints/users/groups/joined.ts
new file mode 100644
index 0000000000..d5e8fe4032
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/joined.ts
@@ -0,0 +1,36 @@
+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/packages/backend/src/server/api/endpoints/users/groups/leave.ts b/packages/backend/src/server/api/endpoints/users/groups/leave.ts
new file mode 100644
index 0000000000..0e52f2abdf
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/leave.ts
@@ -0,0 +1,50 @@
+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/packages/backend/src/server/api/endpoints/users/groups/owned.ts b/packages/backend/src/server/api/endpoints/users/groups/owned.ts
new file mode 100644
index 0000000000..17de370dbc
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/owned.ts
@@ -0,0 +1,28 @@
+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/packages/backend/src/server/api/endpoints/users/groups/pull.ts b/packages/backend/src/server/api/endpoints/users/groups/pull.ts
new file mode 100644
index 0000000000..ce4d2e2881
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/pull.ts
@@ -0,0 +1,69 @@
+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/packages/backend/src/server/api/endpoints/users/groups/show.ts b/packages/backend/src/server/api/endpoints/users/groups/show.ts
new file mode 100644
index 0000000000..3c030bf3a5
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/show.ts
@@ -0,0 +1,55 @@
+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/packages/backend/src/server/api/endpoints/users/groups/transfer.ts b/packages/backend/src/server/api/endpoints/users/groups/transfer.ts
new file mode 100644
index 0000000000..17c42e1127
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/transfer.ts
@@ -0,0 +1,83 @@
+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/packages/backend/src/server/api/endpoints/users/groups/update.ts b/packages/backend/src/server/api/endpoints/users/groups/update.ts
new file mode 100644
index 0000000000..127bbc47a1
--- /dev/null
+++ b/packages/backend/src/server/api/endpoints/users/groups/update.ts
@@ -0,0 +1,55 @@
+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);
+});