From d34aa8adcc2c3c38cf38bcc7e98fbe9e3fe5db51 Mon Sep 17 00:00:00 2001 From: Sahil <135227614+Sahi1l-Kumar@users.noreply.github.com> Date: Mon, 11 Mar 2024 07:00:22 +0530 Subject: [PATCH] Fixes the workflow for revoking a block on a user (un-blocking). (#1890) * Updated blockUser.ts * Updated sendMembershipRequest.ts * Updated unblockUser.ts * Added tests --------- Co-authored-by: Peter Harrison <16875803+palisadoes@users.noreply.github.com> --- src/constants.ts | 9 +- src/resolvers/Mutation/blockUser.ts | 16 +- .../Mutation/joinPublicOrganization.ts | 19 ++- .../Mutation/sendMembershipRequest.ts | 58 ++++++- src/resolvers/Mutation/unblockUser.ts | 65 +++++++- tests/resolvers/Mutation/blockUser.spec.ts | 30 ++-- .../Mutation/joinPublicOrganization.spec.ts | 80 +++++++-- .../Mutation/sendMembershipRequest.spec.ts | 157 +++++++++++++++++- tests/resolvers/Mutation/unblockUser.spec.ts | 150 +++++++++++++++-- 9 files changed, 530 insertions(+), 54 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 80f4d2662c..dc3e4408c8 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -132,8 +132,13 @@ export const MEMBERSHIP_REQUEST_NOT_FOUND_ERROR = { MESSAGE: "membershipRequest.notFound", PARAM: "membershipRequest", }; -export const MEMBERSHIP_REQUEST_ALREADY_EXISTS = - "Membership Request already exists"; + +export const MEMBERSHIP_REQUEST_ALREADY_EXISTS = { + DESC: "Membership Request already exists", + CODE: "membershipRequest.alreadyExists", + MESSAGE: "membershipRequest.alreadyExists", + PARAM: "membershipRequest", +}; export const ORGANIZATION_MEMBER_NOT_FOUND_ERROR = { DESC: "Organization's user is not a member", diff --git a/src/resolvers/Mutation/blockUser.ts b/src/resolvers/Mutation/blockUser.ts index bd0efb8529..eeee3bcf5d 100644 --- a/src/resolvers/Mutation/blockUser.ts +++ b/src/resolvers/Mutation/blockUser.ts @@ -42,7 +42,9 @@ export const blockUser: MutationResolvers["blockUser"] = async ( _id: args.organizationId, }).lean(); - await cacheOrganizations([organization!]); + if (organization) { + await cacheOrganizations([organization]); + } } // Checks whether organization exists. @@ -105,7 +107,10 @@ export const blockUser: MutationResolvers["blockUser"] = async ( ); } - // Adds args.userId to blockedUsers list on organization's document. + /* + Adds args.userId to blockedUsers list on organization's document. + Removes args.userId from the organization's members list + */ const updatedOrganization = await Organization.findOneAndUpdate( { _id: organization._id, @@ -114,6 +119,9 @@ export const blockUser: MutationResolvers["blockUser"] = async ( $push: { blockedUsers: args.userId, }, + $pull: { + members: args.userId, + }, }, { new: true, @@ -127,6 +135,7 @@ export const blockUser: MutationResolvers["blockUser"] = async ( /* Adds organization._id to organizationsBlockedBy list on user's document with _id === args.userId and returns the updated user. + Remove organization's id from joinedOrganizations list on args.userId. */ return await User.findOneAndUpdate( { @@ -136,6 +145,9 @@ export const blockUser: MutationResolvers["blockUser"] = async ( $push: { organizationsBlockedBy: organization._id, }, + $pull: { + joinedOrganizations: organization._id, + }, }, { new: true, diff --git a/src/resolvers/Mutation/joinPublicOrganization.ts b/src/resolvers/Mutation/joinPublicOrganization.ts index cacc670301..3647572f38 100644 --- a/src/resolvers/Mutation/joinPublicOrganization.ts +++ b/src/resolvers/Mutation/joinPublicOrganization.ts @@ -37,7 +37,9 @@ export const joinPublicOrganization: MutationResolvers["joinPublicOrganization"] _id: args.organizationId, }).lean(); - await cacheOrganizations([organization!]); + if (organization !== null) { + await cacheOrganizations([organization]); + } } // Checks whether organization exists. @@ -82,6 +84,21 @@ export const joinPublicOrganization: MutationResolvers["joinPublicOrganization"] ); } + // Checks if the user is blocked + const user = await User.findById(context.userId).lean(); + if ( + user !== null && + organization.blockedUsers.some((blockedUser) => + Types.ObjectId(blockedUser).equals(user._id), + ) + ) { + throw new errors.UnauthorizedError( + requestContext.translate(USER_NOT_AUTHORIZED_ERROR.MESSAGE), + USER_NOT_AUTHORIZED_ERROR.CODE, + USER_NOT_AUTHORIZED_ERROR.PARAM, + ); + } + // Adds context.userId to members list of organzation's document. const updatedOrganization = await Organization.findOneAndUpdate( { diff --git a/src/resolvers/Mutation/sendMembershipRequest.ts b/src/resolvers/Mutation/sendMembershipRequest.ts index 66c4f1fdab..5c565cef1c 100644 --- a/src/resolvers/Mutation/sendMembershipRequest.ts +++ b/src/resolvers/Mutation/sendMembershipRequest.ts @@ -1,20 +1,24 @@ import { - MEMBERSHIP_REQUEST_NOT_FOUND_ERROR, + MEMBERSHIP_REQUEST_ALREADY_EXISTS, ORGANIZATION_NOT_FOUND_ERROR, + USER_NOT_FOUND_ERROR, + USER_NOT_AUTHORIZED_ERROR, + USER_ALREADY_MEMBER_ERROR, } from "../../constants"; import type { MutationResolvers } from "../../types/generatedGraphQLTypes"; import { errors, requestContext } from "../../libraries"; import { User, MembershipRequest, Organization } from "../../models"; import { findOrganizationsInCache } from "../../services/OrganizationCache/findOrganizationsInCache"; import { cacheOrganizations } from "../../services/OrganizationCache/cacheOrganizations"; +import { Types } from "mongoose"; /** * This function enables to send membership request. * @param _parent - parent of current request * @param args - payload provided with the request * @param context - context of entire application * @remarks The following checks are done: - * 1. If the user exists. - * 2. If the organization exists + * 1. If the organization exists + * 2. If the user exists. * 3. If the membership request already exists. * @returns Membership request. */ @@ -46,6 +50,48 @@ export const sendMembershipRequest: MutationResolvers["sendMembershipRequest"] = ); } + const userExists = await User.exists({ + _id: context.userId, + }); + + // Checks whether user exists. + if (userExists === false) { + throw new errors.NotFoundError( + requestContext.translate(USER_NOT_FOUND_ERROR.MESSAGE), + USER_NOT_FOUND_ERROR.CODE, + USER_NOT_FOUND_ERROR.PARAM, + ); + } + + // Checks if the user is already a member of the organization + const isMember = organization.members.some((member) => + Types.ObjectId(member).equals(context.userId), + ); + + if (isMember === true) { + throw new errors.ConflictError( + requestContext.translate(USER_ALREADY_MEMBER_ERROR.MESSAGE), + USER_ALREADY_MEMBER_ERROR.CODE, + USER_ALREADY_MEMBER_ERROR.PARAM, + ); + } + + // Checks if the user is blocked + const user = await User.findById(context.userId).lean(); + if ( + user !== null && + organization.blockedUsers.some((blockedUser) => + Types.ObjectId(blockedUser).equals(user._id), + ) + ) { + throw new errors.UnauthorizedError( + requestContext.translate(USER_NOT_AUTHORIZED_ERROR.MESSAGE), + USER_NOT_AUTHORIZED_ERROR.CODE, + USER_NOT_AUTHORIZED_ERROR.PARAM, + ); + } + + // Checks if the membership request already exists const membershipRequestExists = await MembershipRequest.exists({ user: context.userId, organization: organization._id, @@ -53,9 +99,9 @@ export const sendMembershipRequest: MutationResolvers["sendMembershipRequest"] = if (membershipRequestExists === true) { throw new errors.ConflictError( - requestContext.translate(MEMBERSHIP_REQUEST_NOT_FOUND_ERROR.MESSAGE), - MEMBERSHIP_REQUEST_NOT_FOUND_ERROR.CODE, - MEMBERSHIP_REQUEST_NOT_FOUND_ERROR.PARAM, + requestContext.translate(MEMBERSHIP_REQUEST_ALREADY_EXISTS.MESSAGE), + MEMBERSHIP_REQUEST_ALREADY_EXISTS.CODE, + MEMBERSHIP_REQUEST_ALREADY_EXISTS.PARAM, ); } diff --git a/src/resolvers/Mutation/unblockUser.ts b/src/resolvers/Mutation/unblockUser.ts index 6b42ee9a7e..6d5af8de31 100644 --- a/src/resolvers/Mutation/unblockUser.ts +++ b/src/resolvers/Mutation/unblockUser.ts @@ -7,7 +7,7 @@ import { USER_NOT_FOUND_ERROR, } from "../../constants"; import type { InterfaceOrganization } from "../../models"; -import { Organization, User } from "../../models"; +import { MembershipRequest, Organization, User } from "../../models"; import { cacheOrganizations } from "../../services/OrganizationCache/cacheOrganizations"; import { findOrganizationsInCache } from "../../services/OrganizationCache/findOrganizationsInCache"; import { Types } from "mongoose"; @@ -37,8 +37,9 @@ export const unblockUser: MutationResolvers["unblockUser"] = async ( organization = await Organization.findOne({ _id: args.organizationId, }).lean(); - - await cacheOrganizations([organization!]); + if (organization) { + await cacheOrganizations([organization]); + } } else { organization = organizationFoundInCache[0]; } @@ -99,6 +100,64 @@ export const unblockUser: MutationResolvers["unblockUser"] = async ( ).lean(); if (updatedOrganization !== null) { + if (updatedOrganization.userRegistrationRequired === true) { + // create a membership request for the user + const createdMembershipRequest = await MembershipRequest.create({ + user: user._id, + organization: organization._id, + }); + // add membership request to organization + await Organization.findOneAndUpdate( + { + _id: organization._id, + }, + { + $push: { + membershipRequests: createdMembershipRequest._id, + }, + }, + { + new: true, + }, + ).lean(); + // add membership request to user + await User.updateOne( + { + _id: user._id, + }, + { + $push: { + membershipRequests: createdMembershipRequest._id, + }, + }, + ); + } else { + // add user to the members list inside the organization record + await Organization.findOneAndUpdate( + { + _id: organization._id, + }, + { + $push: { + members: user._id, + }, + }, + { + new: true, + }, + ).lean(); + // add organization to the joinedOrganizations list inside the user record + await User.updateOne( + { + _id: user._id, + }, + { + $push: { + joinedOrganizations: organization._id, + }, + }, + ).lean(); + } await cacheOrganizations([updatedOrganization]); } // remove the organization from the organizationsBlockedBy array inside the user record diff --git a/tests/resolvers/Mutation/blockUser.spec.ts b/tests/resolvers/Mutation/blockUser.spec.ts index 374960dca1..ef64f1437b 100644 --- a/tests/resolvers/Mutation/blockUser.spec.ts +++ b/tests/resolvers/Mutation/blockUser.spec.ts @@ -90,8 +90,10 @@ describe("resolvers -> Mutation -> blockUser", () => { }; await blockUserResolver?.({}, args, context); - } catch (error: any) { - expect(error.message).toEqual(ORGANIZATION_NOT_FOUND_ERROR.MESSAGE); + } catch (error: unknown) { + expect((error as Error).message).toEqual( + ORGANIZATION_NOT_FOUND_ERROR.MESSAGE, + ); } }); @@ -107,8 +109,8 @@ describe("resolvers -> Mutation -> blockUser", () => { }; await blockUserResolver?.({}, args, context); - } catch (error: any) { - expect(error.message).toEqual(USER_NOT_FOUND_ERROR.MESSAGE); + } catch (error: unknown) { + expect((error as Error).message).toEqual(USER_NOT_FOUND_ERROR.MESSAGE); } }); @@ -132,8 +134,8 @@ describe("resolvers -> Mutation -> blockUser", () => { ); await blockUserResolverError?.({}, args, context); - } catch (error: any) { - expect(error.message).toEqual(MEMBER_NOT_FOUND_ERROR.MESSAGE); + } catch (error: unknown) { + expect((error as Error).message).toEqual(MEMBER_NOT_FOUND_ERROR.MESSAGE); } }); @@ -157,8 +159,8 @@ describe("resolvers -> Mutation -> blockUser", () => { ); await blockUserResolverError?.({}, args, context); - } catch (error: any) { - expect(error.message).toEqual(USER_BLOCKING_SELF.MESSAGE); + } catch (error: unknown) { + expect((error as Error).message).toEqual(USER_BLOCKING_SELF.MESSAGE); } }); @@ -193,8 +195,10 @@ describe("resolvers -> Mutation -> blockUser", () => { }; await blockUserResolver?.({}, args, context); - } catch (error: any) { - expect(error.message).toEqual(USER_NOT_AUTHORIZED_ADMIN.MESSAGE); + } catch (error: unknown) { + expect((error as Error).message).toEqual( + USER_NOT_AUTHORIZED_ADMIN.MESSAGE, + ); } }); @@ -241,8 +245,10 @@ describe("resolvers -> Mutation -> blockUser", () => { }; await blockUserResolver?.({}, args, context); - } catch (error: any) { - expect(error.message).toEqual(USER_NOT_AUTHORIZED_ERROR.MESSAGE); + } catch (error: unknown) { + expect((error as Error).message).toEqual( + USER_NOT_AUTHORIZED_ERROR.MESSAGE, + ); } }); diff --git a/tests/resolvers/Mutation/joinPublicOrganization.spec.ts b/tests/resolvers/Mutation/joinPublicOrganization.spec.ts index 9db4edf420..b36fa85988 100644 --- a/tests/resolvers/Mutation/joinPublicOrganization.spec.ts +++ b/tests/resolvers/Mutation/joinPublicOrganization.spec.ts @@ -66,9 +66,11 @@ describe("resolvers -> Mutation -> joinPublicOrganization", () => { await import("../../../src/resolvers/Mutation/joinPublicOrganization"); await joinPublicOrganizationResolver?.({}, args, context); - } catch (error: any) { + } catch (error: unknown) { expect(spy).toBeCalledWith(ORGANIZATION_NOT_FOUND_ERROR.MESSAGE); - expect(error.message).toEqual(ORGANIZATION_NOT_FOUND_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + ORGANIZATION_NOT_FOUND_ERROR.MESSAGE, + ); } }); it(`throws UnauthorizedError message if organization with _id === args.organizationId required registration for the users`, async () => { @@ -89,9 +91,11 @@ describe("resolvers -> Mutation -> joinPublicOrganization", () => { await import("../../../src/resolvers/Mutation/joinPublicOrganization"); await joinPublicOrganizationResolver?.({}, args, context); - } catch (error: any) { + } catch (error: unknown) { expect(spy).toBeCalledWith(USER_NOT_AUTHORIZED_ERROR.MESSAGE); - expect(error.message).toEqual(USER_NOT_AUTHORIZED_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + USER_NOT_AUTHORIZED_ERROR.MESSAGE, + ); } }); @@ -115,7 +119,9 @@ describe("resolvers -> Mutation -> joinPublicOrganization", () => { }, ); - await cacheOrganizations([updatedOrganizaiton!]); + if (updatedOrganizaiton !== null) { + await cacheOrganizations([updatedOrganizaiton]); + } const args: MutationJoinPublicOrganizationArgs = { organizationId: testOrganization?.id, @@ -129,9 +135,9 @@ describe("resolvers -> Mutation -> joinPublicOrganization", () => { await import("../../../src/resolvers/Mutation/joinPublicOrganization"); await joinPublicOrganizationResolver?.({}, args, context); - } catch (error: any) { + } catch (error: unknown) { expect(spy).toBeCalledWith(USER_NOT_FOUND_ERROR.MESSAGE); - expect(error.message).toEqual(USER_NOT_FOUND_ERROR.MESSAGE); + expect((error as Error).message).toEqual(USER_NOT_FOUND_ERROR.MESSAGE); } }); @@ -153,9 +159,58 @@ describe("resolvers -> Mutation -> joinPublicOrganization", () => { await import("../../../src/resolvers/Mutation/joinPublicOrganization"); await joinPublicOrganizationResolver?.({}, args, context); - } catch (error: any) { + } catch (error: unknown) { expect(spy).toBeCalledWith(USER_ALREADY_MEMBER_ERROR.MESSAGE); - expect(error.message).toEqual(USER_ALREADY_MEMBER_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + USER_ALREADY_MEMBER_ERROR.MESSAGE, + ); + } + }); + + it(`throws UnauthorizedError if the user is blocked from the organization`, async () => { + const { requestContext } = await import("../../../src/libraries"); + const spy = vi + .spyOn(requestContext, "translate") + .mockImplementationOnce((message) => message); + try { + const updatedOrganization = await Organization.findOneAndUpdate( + { + _id: testOrganization?.id, + }, + { + $pull: { + members: testUser?.id, + }, + $addToSet: { + blockedUsers: testUser?.id, + }, + }, + { + new: true, + }, + ); + + if (updatedOrganization !== null) { + cacheOrganizations([updatedOrganization]); + } + + const args: MutationJoinPublicOrganizationArgs = { + organizationId: testOrganization?.id, + }; + + const context = { + userId: testUser?.id, + }; + + const { joinPublicOrganization: joinPublicOrganizationResolver } = + await import("../../../src/resolvers/Mutation/joinPublicOrganization"); + + await joinPublicOrganizationResolver?.({}, args, context); + } catch (error: unknown) { + expect(spy).toBeCalledWith(USER_NOT_AUTHORIZED_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + USER_NOT_AUTHORIZED_ERROR.MESSAGE, + ); } }); @@ -165,6 +220,9 @@ describe("resolvers -> Mutation -> joinPublicOrganization", () => { _id: testOrganization?._id, }, { + $pull: { + blockedUsers: testUser?.id, + }, $set: { members: [], }, @@ -174,7 +232,9 @@ describe("resolvers -> Mutation -> joinPublicOrganization", () => { }, ); - await cacheOrganizations([updatedOrganizaiton!]); + if (updatedOrganizaiton !== null) { + await cacheOrganizations([updatedOrganizaiton]); + } const args: MutationJoinPublicOrganizationArgs = { organizationId: testOrganization?.id, diff --git a/tests/resolvers/Mutation/sendMembershipRequest.spec.ts b/tests/resolvers/Mutation/sendMembershipRequest.spec.ts index 30493c8e36..273fd40327 100644 --- a/tests/resolvers/Mutation/sendMembershipRequest.spec.ts +++ b/tests/resolvers/Mutation/sendMembershipRequest.spec.ts @@ -7,8 +7,11 @@ import { connect, disconnect } from "../../helpers/db"; import { sendMembershipRequest as sendMembershipRequestResolver } from "../../../src/resolvers/Mutation/sendMembershipRequest"; import { - MEMBERSHIP_REQUEST_NOT_FOUND_ERROR, + MEMBERSHIP_REQUEST_ALREADY_EXISTS, ORGANIZATION_NOT_FOUND_ERROR, + USER_ALREADY_MEMBER_ERROR, + USER_NOT_AUTHORIZED_ERROR, + USER_NOT_FOUND_ERROR, } from "../../../src/constants"; import { beforeAll, afterAll, describe, it, expect, vi } from "vitest"; import type { @@ -17,6 +20,7 @@ import type { } from "../../helpers/userAndOrg"; import type { TestMembershipRequestType } from "../../helpers/membershipRequests"; import { createTestMembershipRequest } from "../../helpers/membershipRequests"; +import { cacheOrganizations } from "../../../src/services/OrganizationCache/cacheOrganizations"; let MONGOOSE_INSTANCE: typeof mongoose; let testUser: TestUserType; @@ -54,14 +58,15 @@ describe("resolvers -> Mutation -> sendMembershipRequest", () => { await import("../../../src/resolvers/Mutation/sendMembershipRequest"); await sendMembershipRequestResolver?.({}, args, context); - } catch (error: any) { + } catch (error: unknown) { expect(spy).toBeCalledWith(ORGANIZATION_NOT_FOUND_ERROR.MESSAGE); - expect(error.message).toEqual(ORGANIZATION_NOT_FOUND_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + ORGANIZATION_NOT_FOUND_ERROR.MESSAGE, + ); } }); - it(`throws NotFoundError if a membershipRequest with fields user === context.userId - and organization === args.organizationId does not exists`, async () => { + it(`throws NotFoundError if no user exists with _id === args.userId`, async () => { const { requestContext } = await import("../../../src/libraries"); const spy = vi .spyOn(requestContext, "translate") @@ -71,6 +76,140 @@ describe("resolvers -> Mutation -> sendMembershipRequest", () => { organizationId: testOrganization?.id, }; + const context = { + userId: Types.ObjectId().toString(), + }; + + const { sendMembershipRequest: sendMembershipRequestResolver } = + await import("../../../src/resolvers/Mutation/sendMembershipRequest"); + + await sendMembershipRequestResolver?.({}, args, context); + } catch (error: unknown) { + expect(spy).toBeCalledWith(USER_NOT_FOUND_ERROR.MESSAGE); + expect((error as Error).message).toEqual(USER_NOT_FOUND_ERROR.MESSAGE); + } + }); + + it(`throws ConflictError message if user with _id === context.userId is already a member of organization with _id === args.organizationId`, async () => { + const { requestContext } = await import("../../../src/libraries"); + const spy = vi + .spyOn(requestContext, "translate") + .mockImplementationOnce((message) => message); + try { + const updatedOrganizaiton = await Organization.findOneAndUpdate( + { + _id: testOrganization?.id, + }, + { + $set: { + members: [testUser?.id], + }, + }, + { + new: true, + }, + ); + + if (updatedOrganizaiton !== null) { + await cacheOrganizations([updatedOrganizaiton]); + } + + const args: MutationSendMembershipRequestArgs = { + organizationId: testOrganization?.id, + }; + + const context = { + userId: testUser?.id, + }; + + const { sendMembershipRequest: sendMembershipRequestResolver } = + await import("../../../src/resolvers/Mutation/sendMembershipRequest"); + + await sendMembershipRequestResolver?.({}, args, context); + } catch (error: unknown) { + expect(spy).toBeCalledWith(USER_ALREADY_MEMBER_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + USER_ALREADY_MEMBER_ERROR.MESSAGE, + ); + } + }); + + it(`throws UnauthorizedError if the user is blocked from the organization`, async () => { + const { requestContext } = await import("../../../src/libraries"); + const spy = vi + .spyOn(requestContext, "translate") + .mockImplementationOnce((message) => message); + try { + const updatedOrganization = await Organization.findOneAndUpdate( + { + _id: testOrganization?.id, + }, + { + $pull: { + members: testUser?.id, + }, + $addToSet: { + blockedUsers: testUser?.id, + }, + }, + { + new: true, + }, + ); + + if (updatedOrganization !== null) { + cacheOrganizations([updatedOrganization]); + } + + const args: MutationSendMembershipRequestArgs = { + organizationId: testOrganization?.id, + }; + + const context = { + userId: testUser?.id, + }; + + const { sendMembershipRequest: sendMembershipRequestResolver } = + await import("../../../src/resolvers/Mutation/sendMembershipRequest"); + + await sendMembershipRequestResolver?.({}, args, context); + } catch (error: unknown) { + expect(spy).toBeCalledWith(USER_NOT_AUTHORIZED_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + USER_NOT_AUTHORIZED_ERROR.MESSAGE, + ); + } + }); + + it(`throws ConflictError message if a membershipRequest with fields user === context.userId + and organization === args.organizationId already exists`, async () => { + const { requestContext } = await import("../../../src/libraries"); + const spy = vi + .spyOn(requestContext, "translate") + .mockImplementationOnce((message) => message); + try { + const updatedOrganization = await Organization.findOneAndUpdate( + { + _id: testOrganization?.id, + }, + { + $pull: { + blockedUsers: testUser?.id, + }, + }, + { + new: true, + }, + ); + + if (updatedOrganization !== null) { + cacheOrganizations([updatedOrganization]); + } + + const args: MutationSendMembershipRequestArgs = { + organizationId: testOrganization?.id, + }; + const context = { userId: testUser?.id, }; @@ -79,9 +218,11 @@ describe("resolvers -> Mutation -> sendMembershipRequest", () => { await import("../../../src/resolvers/Mutation/sendMembershipRequest"); await sendMembershipRequestResolver?.({}, args, context); - } catch (error: any) { - expect(spy).toBeCalledWith(MEMBERSHIP_REQUEST_NOT_FOUND_ERROR.MESSAGE); - expect(error.message).toEqual(MEMBERSHIP_REQUEST_NOT_FOUND_ERROR.MESSAGE); + } catch (error: unknown) { + expect(spy).toBeCalledWith(MEMBERSHIP_REQUEST_ALREADY_EXISTS.MESSAGE); + expect((error as Error).message).toEqual( + MEMBERSHIP_REQUEST_ALREADY_EXISTS.MESSAGE, + ); } }); diff --git a/tests/resolvers/Mutation/unblockUser.spec.ts b/tests/resolvers/Mutation/unblockUser.spec.ts index d73633f308..f3cb288a15 100644 --- a/tests/resolvers/Mutation/unblockUser.spec.ts +++ b/tests/resolvers/Mutation/unblockUser.spec.ts @@ -1,7 +1,7 @@ import "dotenv/config"; import type mongoose from "mongoose"; import { Types } from "mongoose"; -import { User, Organization } from "../../../src/models"; +import { User, Organization, MembershipRequest } from "../../../src/models"; import type { MutationUnblockUserArgs } from "../../../src/types/generatedGraphQLTypes"; import { connect, disconnect } from "../../helpers/db"; @@ -55,9 +55,11 @@ describe("resolvers -> Mutation -> unblockUser", () => { ); await unblockUserResolver?.({}, args, context); - } catch (error: any) { + } catch (error: unknown) { expect(spy).toBeCalledWith(ORGANIZATION_NOT_FOUND_ERROR.MESSAGE); - expect(error.message).toEqual(ORGANIZATION_NOT_FOUND_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + ORGANIZATION_NOT_FOUND_ERROR.MESSAGE, + ); } }); @@ -81,9 +83,9 @@ describe("resolvers -> Mutation -> unblockUser", () => { ); await unblockUserResolver?.({}, args, context); - } catch (error: any) { + } catch (error: unknown) { expect(spy).toBeCalledWith(USER_NOT_FOUND_ERROR.MESSAGE); - expect(error.message).toEqual(USER_NOT_FOUND_ERROR.MESSAGE); + expect((error as Error).message).toEqual(USER_NOT_FOUND_ERROR.MESSAGE); } }); @@ -108,9 +110,11 @@ describe("resolvers -> Mutation -> unblockUser", () => { ); await unblockUserResolver?.({}, args, context); - } catch (error: any) { + } catch (error: unknown) { expect(spy).toBeCalledWith(USER_NOT_AUTHORIZED_ERROR.MESSAGE); - expect(error.message).toEqual(USER_NOT_AUTHORIZED_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + USER_NOT_AUTHORIZED_ERROR.MESSAGE, + ); } }); @@ -157,14 +161,107 @@ describe("resolvers -> Mutation -> unblockUser", () => { ); await unblockUserResolver?.({}, args, context); - } catch (error: any) { + } catch (error: unknown) { expect(spy).toBeCalledWith(USER_NOT_AUTHORIZED_ERROR.MESSAGE); - expect(error.message).toEqual(USER_NOT_AUTHORIZED_ERROR.MESSAGE); + expect((error as Error).message).toEqual( + USER_NOT_AUTHORIZED_ERROR.MESSAGE, + ); + } + }); + + it(`removes the user with _id === args.userId from blockedUsers list of the + organization with _id === args.organizationId set with userRegistrationRequired to true + and returns the updated user`, async () => { + const updatedOrganization = await Organization.findOneAndUpdate( + { + _id: testOrganization?._id, + }, + { + $push: { + blockedUsers: testUser?._id, + }, + $set: { + userRegistrationRequired: true, + }, + }, + { + new: true, + }, + ).lean(); + + if ( + updatedOrganization !== null && + updatedOrganization.userRegistrationRequired === true + ) { + const createdMembershipRequest = await MembershipRequest.create({ + user: testUser?._id, + organization: testOrganization?._id, + }); + + const updatedOrganizaiton = await Organization.findOneAndUpdate( + { + _id: testOrganization?._id, + }, + { + $push: { + membershipRequests: createdMembershipRequest._id, + }, + }, + { + new: true, + }, + ).lean(); + + await User.updateOne( + { + _id: testUser?._id, + }, + { + $push: { + membershipRequests: createdMembershipRequest._id, + }, + }, + ); + + if (updatedOrganizaiton !== null) { + await cacheOrganizations([updatedOrganizaiton]); + } } + + await User.updateOne( + { + _id: testUser?.id, + }, + { + $push: { + organizationsBlockedBy: testOrganization?._id, + }, + }, + ); + + const args: MutationUnblockUserArgs = { + organizationId: testOrganization?.id, + userId: testUser?.id, + }; + + const context = { + userId: testUser?.id, + }; + + const unblockUserPayload = await unblockUserResolver?.({}, args, context); + + const testUnblockUserPayload = await User.findOne({ + _id: testUser?.id, + }) + .select(["-password"]) + .lean(); + + expect(unblockUserPayload).toEqual(testUnblockUserPayload); }); it(`removes the user with _id === args.userId from blockedUsers list of the - organization with _id === args.organizationId and returns the updated user`, async () => { + organization with _id === args.organizationId set with userRegistrationRequired to false + and returns the updated user`, async () => { const updatedOrganization = await Organization.findOneAndUpdate( { _id: testOrganization?._id, @@ -173,12 +270,45 @@ describe("resolvers -> Mutation -> unblockUser", () => { $push: { blockedUsers: testUser?._id, }, + $set: { + userRegistrationRequired: false, + }, }, { new: true, }, ).lean(); + if ( + updatedOrganization !== null && + updatedOrganization.userRegistrationRequired === false + ) { + await Organization.findOneAndUpdate( + { + _id: testOrganization?._id, + }, + { + $push: { + members: testUser?._id, + }, + }, + { + new: true, + }, + ).lean(); + + await User.updateOne( + { + _id: testUser?._id, + }, + { + $push: { + joinedOrganizations: testOrganization?._id, + }, + }, + ).lean(); + } + if (updatedOrganization !== null) { await cacheOrganizations([updatedOrganization]); }