From 3bc9ecee3f834d9ed956653be38c0977ae30b164 Mon Sep 17 00:00:00 2001 From: Shekhar Patel <90516956+duplixx@users.noreply.github.com> Date: Fri, 31 May 2024 10:39:27 +0530 Subject: [PATCH 01/18] eventsAttended added --- src/models/User.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/models/User.ts b/src/models/User.ts index 9d5f4341ba..e657461a00 100644 --- a/src/models/User.ts +++ b/src/models/User.ts @@ -46,7 +46,7 @@ export interface InterfaceUser { mobile: string; work: string; }; - + eventsAttended: PopulatedDoc[]; registeredEvents: PopulatedDoc[]; status: string; @@ -76,6 +76,7 @@ export interface InterfaceUser { * @param phone - User contact numbers, for mobile, home and work * @param registeredEvents - Collection of user registered Events, each object refer to `Event` model. + * @param eventsAttended - Collection of user attended Events, each object refer to `Event` model. * @param status - Status * @@ -218,6 +219,12 @@ const userSchema = new Schema( ref: "Event", }, ], + eventsAttended: [ + { + type: Schema.Types.ObjectId, + ref: "Event", + }, + ], status: { type: String, required: true, From 8f9f6ec478ccb655121ca608baaa8d43c3807ee7 Mon Sep 17 00:00:00 2001 From: Shekhar Patel <90516956+duplixx@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:41:18 +0530 Subject: [PATCH 02/18] events attended support added --- schema.graphql | 1 + src/models/User.ts | 1 + src/resolvers/Mutation/checkIn.ts | 9 ++++-- src/resolvers/Query/eventsAttendedByUser.ts | 28 +++++++++++++++++++ src/resolvers/Query/index.ts | 3 ++ .../Query/organizationsMemberConnection.ts | 2 ++ src/typeDefs/queries.ts | 2 ++ src/types/generatedGraphQLTypes.ts | 12 ++++++-- 8 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 src/resolvers/Query/eventsAttendedByUser.ts diff --git a/schema.graphql b/schema.graphql index e05f855023..25c31cd626 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1442,6 +1442,7 @@ type Query { directChatsMessagesByChatID(id: ID!): [DirectChatMessage] event(id: ID!): Event eventVolunteersByEvent(id: ID!): [EventVolunteer] + eventsAttendedByUser(id: ID, orderBy: EventOrderByInput): [Event] eventsByOrganization(id: ID, orderBy: EventOrderByInput): [Event] eventsByOrganizationConnection(first: Int, orderBy: EventOrderByInput, skip: Int, where: EventWhereInput): [Event!]! fundsByOrganization(organizationId: ID!, where: FundWhereInput): [Fund] diff --git a/src/models/User.ts b/src/models/User.ts index e657461a00..7092293404 100644 --- a/src/models/User.ts +++ b/src/models/User.ts @@ -47,6 +47,7 @@ export interface InterfaceUser { work: string; }; eventsAttended: PopulatedDoc[]; + registeredEvents: PopulatedDoc[]; status: string; diff --git a/src/resolvers/Mutation/checkIn.ts b/src/resolvers/Mutation/checkIn.ts index 5f840ebad6..eb771bcdbf 100644 --- a/src/resolvers/Mutation/checkIn.ts +++ b/src/resolvers/Mutation/checkIn.ts @@ -180,8 +180,13 @@ export const checkIn: MutationResolvers["checkIn"] = async ( userId: args.data.userId, }, { - checkInId: checkIn._id, - isCheckedIn: true, + $set: { + checkInId: checkIn._id, + isCheckedIn: true, + }, + $addToSet: { + eventsAttended: args.data.eventId, + }, }, ); diff --git a/src/resolvers/Query/eventsAttendedByUser.ts b/src/resolvers/Query/eventsAttendedByUser.ts new file mode 100644 index 0000000000..202a962707 --- /dev/null +++ b/src/resolvers/Query/eventsAttendedByUser.ts @@ -0,0 +1,28 @@ +import type { QueryResolvers } from "../../types/generatedGraphQLTypes"; +import { Event } from "../../models"; +import { getSort } from "./helperFunctions/getSort"; + +/** + * This query will fetch all the events for which user attended from the database. + * @param _parent- + * @param args - An object that contains `id` of the user and `orderBy`. + * @returns An object that contains the Event data. + * @remarks The query function uses `getSort()` function to sort the data in specified. + */ +export const eventsAttendedByUser: QueryResolvers["eventsAttendedByUser"] = + async (_parent, args) => { + const sort = getSort(args.orderBy); + + return await Event.find({ + registrants: { + $elemMatch: { + userId: args.id, + status: "ACTIVE", + }, + }, + }) + .sort(sort) + .populate("creatorId", "-password") + .populate("admins", "-password") + .lean(); + }; diff --git a/src/resolvers/Query/index.ts b/src/resolvers/Query/index.ts index 3f67d7597a..f90a58fe57 100644 --- a/src/resolvers/Query/index.ts +++ b/src/resolvers/Query/index.ts @@ -44,6 +44,8 @@ import { getEventAttendeesByEventId } from "./getEventAttendeesByEventId"; import { getVenueByOrgId } from "./getVenueByOrgId"; import { getAllNotesForAgendaItem } from "./getAllNotesForAgendaItem"; import { getNoteById } from "./getNoteById"; +import { eventsAttendedByUser } from "./eventsAttendedByUser"; + export const Query: QueryResolvers = { actionItemsByEvent, agendaCategory, @@ -90,4 +92,5 @@ export const Query: QueryResolvers = { getEventAttendee, getEventAttendeesByEventId, getVenueByOrgId, + eventsAttendedByUser, }; diff --git a/src/resolvers/Query/organizationsMemberConnection.ts b/src/resolvers/Query/organizationsMemberConnection.ts index 76a85c4d88..185447dbf9 100644 --- a/src/resolvers/Query/organizationsMemberConnection.ts +++ b/src/resolvers/Query/organizationsMemberConnection.ts @@ -140,6 +140,7 @@ export const organizationsMemberConnection: QueryResolvers["organizationsMemberC registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, })); } else { users = usersModel.docs.map((user) => ({ @@ -173,6 +174,7 @@ export const organizationsMemberConnection: QueryResolvers["organizationsMemberC registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, })); } diff --git a/src/typeDefs/queries.ts b/src/typeDefs/queries.ts index f5fe8cf49e..bed7d464ff 100644 --- a/src/typeDefs/queries.ts +++ b/src/typeDefs/queries.ts @@ -158,5 +158,7 @@ export const queries = gql` ): [UserData]! @auth venue(id: ID!): Venue + + eventsAttendedByUser(id: ID, orderBy: EventOrderByInput): [Event] } `; diff --git a/src/types/generatedGraphQLTypes.ts b/src/types/generatedGraphQLTypes.ts index eb366ab924..10f1b95c38 100644 --- a/src/types/generatedGraphQLTypes.ts +++ b/src/types/generatedGraphQLTypes.ts @@ -2237,6 +2237,7 @@ export type Query = { directChatsMessagesByChatID?: Maybe>>; event?: Maybe; eventVolunteersByEvent?: Maybe>>; + eventsAttendedByUser?: Maybe>>; eventsByOrganization?: Maybe>>; eventsByOrganizationConnection: Array; fundsByOrganization?: Maybe>>; @@ -2348,6 +2349,12 @@ export type QueryEventVolunteersByEventArgs = { }; +export type QueryEventsAttendedByUserArgs = { + id?: InputMaybe; + orderBy?: InputMaybe; +}; + + export type QueryEventsByOrganizationArgs = { id?: InputMaybe; orderBy?: InputMaybe; @@ -3161,7 +3168,7 @@ export type DirectiveResolverFn TResult | Promise; /** Mapping of union types */ -export type ResolversUnionTypes> = { +export type ResolversUnionTypes<_RefType extends Record> = { ConnectionError: ( InvalidCursor ) | ( MaximumValueError ); CreateAdminError: ( OrganizationMemberNotFoundError ) | ( OrganizationNotFoundError ) | ( UserNotAuthorizedError ) | ( UserNotFoundError ); CreateCommentError: ( PostNotFoundError ); @@ -3170,7 +3177,7 @@ export type ResolversUnionTypes> = { }; /** Mapping of interface types */ -export type ResolversInterfaceTypes> = { +export type ResolversInterfaceTypes<_RefType extends Record> = { ConnectionPageInfo: ( DefaultConnectionPageInfo ); Error: ( MemberNotFoundError ) | ( OrganizationMemberNotFoundError ) | ( OrganizationNotFoundError ) | ( PostNotFoundError ) | ( UnauthenticatedError ) | ( UnauthorizedError ) | ( UserNotAuthorizedAdminError ) | ( UserNotAuthorizedError ) | ( UserNotFoundError ); FieldError: ( InvalidCursor ) | ( MaximumLengthError ) | ( MaximumValueError ) | ( MinimumLengthError ) | ( MinimumValueError ); @@ -4458,6 +4465,7 @@ export type QueryResolvers>>, ParentType, ContextType, RequireFields>; event?: Resolver, ParentType, ContextType, RequireFields>; eventVolunteersByEvent?: Resolver>>, ParentType, ContextType, RequireFields>; + eventsAttendedByUser?: Resolver>>, ParentType, ContextType, Partial>; eventsByOrganization?: Resolver>>, ParentType, ContextType, Partial>; eventsByOrganizationConnection?: Resolver, ParentType, ContextType, Partial>; fundsByOrganization?: Resolver>>, ParentType, ContextType, RequireFields>; From dcc38669389e841c0a3d1adfb44a8c09fb2252ab Mon Sep 17 00:00:00 2001 From: Shekhar Patel <90516956+duplixx@users.noreply.github.com> Date: Tue, 18 Jun 2024 21:48:07 +0530 Subject: [PATCH 03/18] eventsAttended added in user --- schema.graphql | 1 + src/typeDefs/types.ts | 1 + src/types/generatedGraphQLTypes.ts | 2 ++ 3 files changed, 4 insertions(+) diff --git a/schema.graphql b/schema.graphql index 25c31cd626..ec61ee8e5f 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1762,6 +1762,7 @@ type User { email: EmailAddress! employmentStatus: EmploymentStatus eventAdmin: [Event] + eventsAttended: [Event] firstName: String! gender: Gender image: String diff --git a/src/typeDefs/types.ts b/src/typeDefs/types.ts index 10afcbfccf..ad20319d6f 100644 --- a/src/typeDefs/types.ts +++ b/src/typeDefs/types.ts @@ -645,6 +645,7 @@ export const types = gql` phone: UserPhone membershipRequests: [MembershipRequest] registeredEvents: [Event] + eventsAttended: [Event] pluginCreationAllowed: Boolean! tagsAssignedWith( after: String diff --git a/src/types/generatedGraphQLTypes.ts b/src/types/generatedGraphQLTypes.ts index 10f1b95c38..222780dc66 100644 --- a/src/types/generatedGraphQLTypes.ts +++ b/src/types/generatedGraphQLTypes.ts @@ -2827,6 +2827,7 @@ export type User = { email: Scalars['EmailAddress']['output']; employmentStatus?: Maybe; eventAdmin?: Maybe>>; + eventsAttended?: Maybe>>; firstName: Scalars['String']['output']; gender?: Maybe; image?: Maybe; @@ -4585,6 +4586,7 @@ export type UserResolvers; employmentStatus?: Resolver, ParentType, ContextType>; eventAdmin?: Resolver>>, ParentType, ContextType>; + eventsAttended?: Resolver>>, ParentType, ContextType>; firstName?: Resolver; gender?: Resolver, ParentType, ContextType>; image?: Resolver, ParentType, ContextType>; From 5978b13bbcc66541f17638a031ba943ef1a8484d Mon Sep 17 00:00:00 2001 From: ratankods <90516956+duplixx@users.noreply.github.com> Date: Sat, 3 Aug 2024 17:48:51 +0530 Subject: [PATCH 04/18] changes implemented for eventsattended --- src/resolvers/Mutation/checkIn.ts | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/resolvers/Mutation/checkIn.ts b/src/resolvers/Mutation/checkIn.ts index eb771bcdbf..a40eb8890b 100644 --- a/src/resolvers/Mutation/checkIn.ts +++ b/src/resolvers/Mutation/checkIn.ts @@ -176,19 +176,36 @@ export const checkIn: MutationResolvers["checkIn"] = async ( await EventAttendee.updateOne( { + _id: attendeeData._id, eventId: args.data.eventId, - userId: args.data.userId, }, { $set: { checkInId: checkIn._id, isCheckedIn: true, }, - $addToSet: { - eventsAttended: args.data.eventId, - }, }, ); + try { + const updateResult = await User.findByIdAndUpdate( + args.data.userId, + { + $addToSet: { + eventsAttended: args.data.eventId.toString(), + }, + }, + { new: true }, + ); + + if (!updateResult) { + console.log("User not found or update failed"); + } else { + console.log("Updated user:", updateResult); + } + } catch (error) { + console.error("Error updating user:", error); + } + return checkIn.toObject(); }; From f366deebb124007b61a7c0279761f2363ed47656 Mon Sep 17 00:00:00 2001 From: ratankods <90516956+duplixx@users.noreply.github.com> Date: Mon, 5 Aug 2024 04:55:47 +0530 Subject: [PATCH 05/18] changes added in add Event Attendee --- src/resolvers/Mutation/addEventAttendee.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/resolvers/Mutation/addEventAttendee.ts b/src/resolvers/Mutation/addEventAttendee.ts index 816635f522..c10dcaea81 100644 --- a/src/resolvers/Mutation/addEventAttendee.ts +++ b/src/resolvers/Mutation/addEventAttendee.ts @@ -144,6 +144,20 @@ export const addEventAttendee: MutationResolvers["addEventAttendee"] = async ( } await EventAttendee.create({ ...args.data }); - + const updateResult = await User.findByIdAndUpdate( + args.data.userId, + { + $push: { + eventsAttended: args.data.eventId.toString(), + }, + }, + { new: true }, + ); + console.log("testing eventID", args.data.eventId); + if (!updateResult) { + console.log("User not found or update failed"); + } else { + console.log("Updated user:", updateResult); + } return requestUser; }; From 1d65fe0d462b606629f9b8a77b391b7ebd4dcbe6 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Tue, 27 Aug 2024 19:27:12 +0530 Subject: [PATCH 06/18] added event supported --- schema.graphql | 1 + src/resolvers/Query/getRecurringEvents.ts | 25 +++++++++++++++++++++++ src/resolvers/Query/index.ts | 2 ++ src/typeDefs/queries.ts | 2 ++ src/types/generatedGraphQLTypes.ts | 7 +++++++ 5 files changed, 37 insertions(+) create mode 100644 src/resolvers/Query/getRecurringEvents.ts diff --git a/schema.graphql b/schema.graphql index 0e4ccb0e3b..9dcf51255c 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1491,6 +1491,7 @@ type Query { getFundraisingCampaignPledgeById(id: ID!): FundraisingCampaignPledge! getNoteById(id: ID!): Note! getPlugins: [Plugin] + getRecurringEvents(baseRecurringEventId: ID!): [Event] getVenueByOrgId(first: Int, orderBy: VenueOrderByInput, orgId: ID!, skip: Int, where: VenueWhereInput): [Venue] getlanguage(lang_code: String!): [Translation] hasSubmittedFeedback(eventId: ID!, userId: ID!): Boolean diff --git a/src/resolvers/Query/getRecurringEvents.ts b/src/resolvers/Query/getRecurringEvents.ts new file mode 100644 index 0000000000..0e92603180 --- /dev/null +++ b/src/resolvers/Query/getRecurringEvents.ts @@ -0,0 +1,25 @@ +import type { QueryResolvers } from "../../types/generatedGraphQLTypes"; +import { Event } from "../../models"; + +/** + * This query will fetch all the events with the same BaseRecurringEventId from the database. + * @param _parent - + * @param args - An object that contains `baseRecurringEventId` of the base recurring event. + * @returns An array of `Event` objects that are instances of the base recurring event. + */ + +export const getRecurringEvents: QueryResolvers["getRecurringEvents"] = async ( + _parent, + args, +) => { + try { + const recurringEvents = await Event.find({ + baseRecurringEventId: args.baseRecurringEventId, + }).lean(); + + return recurringEvents; + } catch (error) { + console.error("Error fetching recurring events:", error); + throw error; + } +}; diff --git a/src/resolvers/Query/index.ts b/src/resolvers/Query/index.ts index ad99aa075d..d9c15b48d3 100644 --- a/src/resolvers/Query/index.ts +++ b/src/resolvers/Query/index.ts @@ -47,6 +47,7 @@ import { getVenueByOrgId } from "./getVenueByOrgId"; import { getAllNotesForAgendaItem } from "./getAllNotesForAgendaItem"; import { getNoteById } from "./getNoteById"; import { eventsAttendedByUser } from "./eventsAttendedByUser"; +import { getRecurringEvents } from "./getRecurringEvents"; export const Query: QueryResolvers = { actionItemsByEvent, @@ -77,6 +78,7 @@ export const Query: QueryResolvers = { getNoteById, getlanguage, getPlugins, + getRecurringEvents, isSampleOrganization, me, myLanguage, diff --git a/src/typeDefs/queries.ts b/src/typeDefs/queries.ts index 06ca69f791..1b4ca1df8b 100644 --- a/src/typeDefs/queries.ts +++ b/src/typeDefs/queries.ts @@ -107,6 +107,8 @@ export const queries = gql` getAllNotesForAgendaItem(agendaItemId: ID!): [Note] + getRecurringEvents(baseRecurringEventId: ID!): [Event] + advertisementsConnection( after: String before: String diff --git a/src/types/generatedGraphQLTypes.ts b/src/types/generatedGraphQLTypes.ts index 00cc304c08..e0e1709452 100644 --- a/src/types/generatedGraphQLTypes.ts +++ b/src/types/generatedGraphQLTypes.ts @@ -2283,6 +2283,7 @@ export type Query = { getFundraisingCampaignPledgeById: FundraisingCampaignPledge; getNoteById: Note; getPlugins?: Maybe>>; + getRecurringEvents?: Maybe>>; getVenueByOrgId?: Maybe>>; getlanguage?: Maybe>>; hasSubmittedFeedback?: Maybe; @@ -2484,6 +2485,11 @@ export type QueryGetNoteByIdArgs = { }; +export type QueryGetRecurringEventsArgs = { + baseRecurringEventId: Scalars['ID']['input']; +}; + + export type QueryGetVenueByOrgIdArgs = { first?: InputMaybe; orderBy?: InputMaybe; @@ -4533,6 +4539,7 @@ export type QueryResolvers>; getNoteById?: Resolver>; getPlugins?: Resolver>>, ParentType, ContextType>; + getRecurringEvents?: Resolver>>, ParentType, ContextType, RequireFields>; getVenueByOrgId?: Resolver>>, ParentType, ContextType, RequireFields>; getlanguage?: Resolver>>, ParentType, ContextType, RequireFields>; hasSubmittedFeedback?: Resolver, ParentType, ContextType, RequireFields>; From 9bace40f12dec1e12cf2a7e652043f84d2b70faa Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:11:41 +0530 Subject: [PATCH 07/18] added eventsattended on expected reponse --- src/types/generatedGraphQLTypes.ts | 4 ++-- .../Query/organizationsMemberConnection.spec.ts | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/types/generatedGraphQLTypes.ts b/src/types/generatedGraphQLTypes.ts index 42c5ff6424..757fe7749e 100644 --- a/src/types/generatedGraphQLTypes.ts +++ b/src/types/generatedGraphQLTypes.ts @@ -2536,8 +2536,6 @@ export type QueryGetRecurringEventsArgs = { }; - - export type QueryGetUserTagArgs = { id: Scalars['ID']['input']; }; @@ -2546,6 +2544,8 @@ export type QueryGetUserTagArgs = { export type QueryGetUserTagAncestorsArgs = { id: Scalars['ID']['input']; }; + + export type QueryGetVenueByOrgIdArgs = { first?: InputMaybe; orderBy?: InputMaybe; diff --git a/tests/resolvers/Query/organizationsMemberConnection.spec.ts b/tests/resolvers/Query/organizationsMemberConnection.spec.ts index 2ce491dc82..7d56f68d26 100644 --- a/tests/resolvers/Query/organizationsMemberConnection.spec.ts +++ b/tests/resolvers/Query/organizationsMemberConnection.spec.ts @@ -247,6 +247,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); @@ -339,6 +340,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); // console.log(organizationsMemberConnectionPayload, usersWithPassword); @@ -430,6 +432,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); @@ -524,6 +527,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); @@ -618,6 +622,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); @@ -700,6 +705,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); @@ -881,6 +887,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); @@ -952,6 +959,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); @@ -1052,6 +1060,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); @@ -1133,6 +1142,7 @@ describe("resolvers -> Query -> organizationsMemberConnection", () => { registeredEvents: user.registeredEvents, status: user.status, updatedAt: user.updatedAt, + eventsAttended: user.eventsAttended, }; }); From a96ef2472731e2320920c498f0440e9ba46c89b2 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Wed, 2 Oct 2024 00:27:25 +0530 Subject: [PATCH 08/18] added suggested changes --- src/resolvers/Mutation/addEventAttendee.ts | 21 +++++++------ src/resolvers/Mutation/checkIn.ts | 30 +++---------------- .../Mutation/addEventAttendee.spec.ts | 8 +++-- 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/resolvers/Mutation/addEventAttendee.ts b/src/resolvers/Mutation/addEventAttendee.ts index 821911cc3e..a32d537ef7 100644 --- a/src/resolvers/Mutation/addEventAttendee.ts +++ b/src/resolvers/Mutation/addEventAttendee.ts @@ -171,20 +171,23 @@ export const addEventAttendee: MutationResolvers["addEventAttendee"] = async ( } await EventAttendee.create({ ...args.data }); - const updateResult = await User.findByIdAndUpdate( + + const updatedUser = await User.findByIdAndUpdate( args.data.userId, { $push: { - eventsAttended: args.data.eventId.toString(), + eventsAttended: args.data.eventId, }, }, { new: true }, ); - console.log("testing eventID", args.data.eventId); - if (!updateResult) { - console.log("User not found or update failed"); - } else { - console.log("Updated user:", updateResult); + + if (!updatedUser) { + throw new errors.NotFoundError( + requestContext.translate(USER_NOT_FOUND_ERROR.MESSAGE), + USER_NOT_FOUND_ERROR.CODE, + USER_NOT_FOUND_ERROR.PARAM, + ); } - return requestUser; -}; + return updatedUser; +} \ No newline at end of file diff --git a/src/resolvers/Mutation/checkIn.ts b/src/resolvers/Mutation/checkIn.ts index a40eb8890b..e04041eb9b 100644 --- a/src/resolvers/Mutation/checkIn.ts +++ b/src/resolvers/Mutation/checkIn.ts @@ -176,36 +176,14 @@ export const checkIn: MutationResolvers["checkIn"] = async ( await EventAttendee.updateOne( { - _id: attendeeData._id, eventId: args.data.eventId, + userId: args.data.userId, }, { - $set: { - checkInId: checkIn._id, - isCheckedIn: true, - }, + checkInId: checkIn._id, + isCheckedIn: true, }, ); - try { - const updateResult = await User.findByIdAndUpdate( - args.data.userId, - { - $addToSet: { - eventsAttended: args.data.eventId.toString(), - }, - }, - { new: true }, - ); - - if (!updateResult) { - console.log("User not found or update failed"); - } else { - console.log("Updated user:", updateResult); - } - } catch (error) { - console.error("Error updating user:", error); - } - return checkIn.toObject(); -}; +}; \ No newline at end of file diff --git a/tests/resolvers/Mutation/addEventAttendee.spec.ts b/tests/resolvers/Mutation/addEventAttendee.spec.ts index a83a1d0d81..021fb47cf6 100644 --- a/tests/resolvers/Mutation/addEventAttendee.spec.ts +++ b/tests/resolvers/Mutation/addEventAttendee.spec.ts @@ -175,17 +175,19 @@ describe("resolvers -> Mutation -> addEventAttendee", () => { ); const payload = await addEventAttendeeResolver?.({}, args, context); + if (!payload) { + throw new Error("Payload is undefined"); + } + const requestUser = await User.findOne({ _id: userId?._id, }).lean(); - + expect(payload).toEqual(expect.objectContaining(requestUser)); const isUserRegistered = await EventAttendee.exists({ ...args.data, }); - expect(payload).toEqual(requestUser); expect(isUserRegistered).toBeTruthy(); }); - it(`throws UnauthorizedError if the requestUser is not a member of the organization`, async () => { const { requestContext } = await import("../../../src/libraries"); From 693f686f52f1bb2539897163dd4102fdb9ab66b8 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Wed, 2 Oct 2024 00:46:03 +0530 Subject: [PATCH 09/18] added expected payload --- tests/resolvers/Mutation/addEventAttendee.spec.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/resolvers/Mutation/addEventAttendee.spec.ts b/tests/resolvers/Mutation/addEventAttendee.spec.ts index 021fb47cf6..9f3118b2f5 100644 --- a/tests/resolvers/Mutation/addEventAttendee.spec.ts +++ b/tests/resolvers/Mutation/addEventAttendee.spec.ts @@ -175,9 +175,7 @@ describe("resolvers -> Mutation -> addEventAttendee", () => { ); const payload = await addEventAttendeeResolver?.({}, args, context); - if (!payload) { - throw new Error("Payload is undefined"); - } + expect(payload).toBeDefined(); const requestUser = await User.findOne({ _id: userId?._id, From 9637068e6c0b4bb5694f5c81a265bcc344e6f87d Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Wed, 2 Oct 2024 00:49:51 +0530 Subject: [PATCH 10/18] formatting done --- src/resolvers/Mutation/addEventAttendee.ts | 2 +- src/resolvers/Mutation/checkIn.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resolvers/Mutation/addEventAttendee.ts b/src/resolvers/Mutation/addEventAttendee.ts index a32d537ef7..bc5ad8b3a3 100644 --- a/src/resolvers/Mutation/addEventAttendee.ts +++ b/src/resolvers/Mutation/addEventAttendee.ts @@ -190,4 +190,4 @@ export const addEventAttendee: MutationResolvers["addEventAttendee"] = async ( ); } return updatedUser; -} \ No newline at end of file +}; diff --git a/src/resolvers/Mutation/checkIn.ts b/src/resolvers/Mutation/checkIn.ts index e04041eb9b..5f840ebad6 100644 --- a/src/resolvers/Mutation/checkIn.ts +++ b/src/resolvers/Mutation/checkIn.ts @@ -186,4 +186,4 @@ export const checkIn: MutationResolvers["checkIn"] = async ( ); return checkIn.toObject(); -}; \ No newline at end of file +}; From e10941858a2d0df5bcc4b4f554ac2c55698a6e66 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Fri, 4 Oct 2024 19:18:42 +0530 Subject: [PATCH 11/18] added test cases --- src/resolvers/Mutation/addEventAttendee.ts | 6 +- .../Mutation/addEventAttendee.spec.ts | 95 +++++++++----- .../Query/eventAttendedByUser.spec.ts | 117 ++++++++++++++++++ .../Query/getRecurringEvents.spec.ts | 101 +++++++++++++++ 4 files changed, 286 insertions(+), 33 deletions(-) create mode 100644 tests/resolvers/Query/eventAttendedByUser.spec.ts create mode 100644 tests/resolvers/Query/getRecurringEvents.spec.ts diff --git a/src/resolvers/Mutation/addEventAttendee.ts b/src/resolvers/Mutation/addEventAttendee.ts index bc5ad8b3a3..7309a7b74d 100644 --- a/src/resolvers/Mutation/addEventAttendee.ts +++ b/src/resolvers/Mutation/addEventAttendee.ts @@ -184,9 +184,9 @@ export const addEventAttendee: MutationResolvers["addEventAttendee"] = async ( if (!updatedUser) { throw new errors.NotFoundError( - requestContext.translate(USER_NOT_FOUND_ERROR.MESSAGE), - USER_NOT_FOUND_ERROR.CODE, - USER_NOT_FOUND_ERROR.PARAM, + requestContext.translate(USER_NOT_AUTHORIZED_ERROR.MESSAGE), + USER_NOT_AUTHORIZED_ERROR.CODE, + USER_NOT_AUTHORIZED_ERROR.PARAM, ); } return updatedUser; diff --git a/tests/resolvers/Mutation/addEventAttendee.spec.ts b/tests/resolvers/Mutation/addEventAttendee.spec.ts index 9f3118b2f5..0f0960d398 100644 --- a/tests/resolvers/Mutation/addEventAttendee.spec.ts +++ b/tests/resolvers/Mutation/addEventAttendee.spec.ts @@ -153,38 +153,40 @@ describe("resolvers -> Mutation -> addEventAttendee", () => { }); it(`registers the request user for the event successfully and returns the request user`, async () => { - const eventOrganizationId = testEvent?.organization._id; - const userId = randomTestUser?._id; + if (testEvent?.organization) { + const eventOrganizationId = testEvent?.organization._id; + const userId = randomTestUser?._id; - await User.updateOne( - { _id: userId }, - { $addToSet: { joinedOrganizations: eventOrganizationId } }, - ); - - const args: MutationAddEventAttendeeArgs = { - data: { - userId: userId, - eventId: testEvent?._id ?? "", - }, - }; - - const context = { userId: testUser?._id }; + await User.updateOne( + { _id: userId }, + { $addToSet: { joinedOrganizations: eventOrganizationId } }, + ); - const { addEventAttendee: addEventAttendeeResolver } = await import( - "../../../src/resolvers/Mutation/addEventAttendee" - ); - const payload = await addEventAttendeeResolver?.({}, args, context); + const args: MutationAddEventAttendeeArgs = { + data: { + userId: userId, + eventId: testEvent?._id.toString() ?? "", + }, + }; - expect(payload).toBeDefined(); + const context = { userId: testUser?._id }; - const requestUser = await User.findOne({ - _id: userId?._id, - }).lean(); - expect(payload).toEqual(expect.objectContaining(requestUser)); - const isUserRegistered = await EventAttendee.exists({ - ...args.data, - }); - expect(isUserRegistered).toBeTruthy(); + const { addEventAttendee: addEventAttendeeResolver } = await import( + "../../../src/resolvers/Mutation/addEventAttendee" + ); + const payload = await addEventAttendeeResolver?.({}, args, context); + + expect(payload).toBeDefined(); + + const requestUser = await User.findOne({ + _id: userId?._id, + }).lean(); + expect(payload).toEqual(expect.objectContaining(requestUser)); + const isUserRegistered = await EventAttendee.exists({ + ...args.data, + }); + expect(isUserRegistered).toBeTruthy(); + } }); it(`throws UnauthorizedError if the requestUser is not a member of the organization`, async () => { const { requestContext } = await import("../../../src/libraries"); @@ -199,11 +201,10 @@ describe("resolvers -> Mutation -> addEventAttendee", () => { ); try { - // Create a test user who is not a member of the organization const args: MutationAddEventAttendeeArgs = { data: { userId: testUser?._id, - eventId: testEvent!._id, + eventId: testEvent!._id.toString(), }, }; @@ -291,4 +292,38 @@ describe("resolvers -> Mutation -> addEventAttendee", () => { ); } }); + it("throws NotFoundError if the user is not found after update", async () => { + const { requestContext } = await import("../../../src/libraries"); + + const spy = vi + .spyOn(requestContext, "translate") + .mockImplementationOnce((message) => `Translated ${message}`); + + const mockFindByIdAndUpdate = vi + .spyOn(User, "findByIdAndUpdate") + .mockResolvedValueOnce(null); + + const args: MutationAddEventAttendeeArgs = { + data: { + userId: testUser?._id, + eventId: testEvent?._id.toString() ?? "", + }, + }; + + const context = { userId: testUser?._id }; + + try { + const { addEventAttendee: addEventAttendeeResolver } = await import( + "../../../src/resolvers/Mutation/addEventAttendee" + ); + + await addEventAttendeeResolver?.({}, args, context); + } catch (error: unknown) { + expect((error as Error).message).toEqual( + `Translated ${USER_NOT_AUTHORIZED_ERROR.MESSAGE}`, + ); + expect(spy).toHaveBeenLastCalledWith(USER_NOT_AUTHORIZED_ERROR.MESSAGE); + } + mockFindByIdAndUpdate.mockRestore(); + }); }); diff --git a/tests/resolvers/Query/eventAttendedByUser.spec.ts b/tests/resolvers/Query/eventAttendedByUser.spec.ts new file mode 100644 index 0000000000..1a1fd7bb56 --- /dev/null +++ b/tests/resolvers/Query/eventAttendedByUser.spec.ts @@ -0,0 +1,117 @@ +import "dotenv/config"; +import { eventsAttendedByUser } from "../../../src/resolvers/Query/eventsAttendedByUser"; +import { connect, disconnect } from "../../helpers/db"; +import type mongoose from "mongoose"; +import { Event, User } from "../../../src/models"; +import { beforeAll, afterAll, describe, it, expect } from "vitest"; +import { Types } from "mongoose"; + +let MONGOOSE_INSTANCE: typeof mongoose; +let testUser: any; +let testEvents: any[]; + +beforeAll(async () => { + MONGOOSE_INSTANCE = await connect(); + + testUser = await User.create({ + firstName: "Test", + lastName: "User", + email: "testuser@example.com", + password: "password123", + }); + + const organizationId = new Types.ObjectId(); + const creatorId = new Types.ObjectId(); + + testEvents = await Event.create([ + { + title: "Event 1", + description: "Description 1", + allDay: false, + startDate: new Date(), + startTime: new Date(), + endTime: new Date(), + isPublic: true, + isRegisterable: true, + organization: organizationId, + creatorId: creatorId, + registrants: [{ userId: testUser._id, status: "ACTIVE" }], + }, + { + title: "Event 2", + description: "Description 2", + allDay: false, + startDate: new Date(), + startTime: new Date(), + endTime: new Date(), + isPublic: true, + isRegisterable: true, + organization: organizationId, + creatorId: creatorId, + registrants: [{ userId: testUser._id, status: "ACTIVE" }], + }, + { + title: "Event 3", + description: "Description 3", + allDay: false, + startDate: new Date(), + startTime: new Date(), + endTime: new Date(), + isPublic: true, + isRegisterable: true, + organization: organizationId, + creatorId: creatorId, + registrants: [{ userId: testUser._id, status: "INACTIVE" }], + }, + ]); +}); + +afterAll(async () => { + await User.deleteMany({}); + await Event.deleteMany({}); + await disconnect(MONGOOSE_INSTANCE); +}); + +describe("resolvers -> Query -> eventsAttendedByUser", () => { + it("returns events attended by the user with ACTIVE status", async () => { + const args = { id: testUser._id.toString() }; + const result = await eventsAttendedByUser({}, args, {} as any); + + expect(result).toHaveLength(2); + expect(result[0].title).toBe("Event 1"); + expect(result[1].title).toBe("Event 2"); + }); + + it("does not return events with INACTIVE status", async () => { + const args = { id: testUser._id.toString() }; + const result = await eventsAttendedByUser({}, args, {} as any); + + const inactiveEvent = result.find((event) => event.title === "Event 3"); + expect(inactiveEvent).toBeUndefined(); + }); + + it("returns an empty array when user has not attended any events", async () => { + const newUser = await User.create({ + firstName: "New", + lastName: "User", + email: "newuser@example.com", + password: "password123", + }); + + const args = { id: newUser._id.toString() }; + const result = await eventsAttendedByUser({}, args, {} as any); + + expect(result).toHaveLength(0); + }); + + it("sorts events based on the provided orderBy argument", async () => { + const args = { + id: testUser._id.toString(), + orderBy: "title_DESC", + }; + const result = await eventsAttendedByUser({}, args, {} as any); + + expect(result[0].title).toBe("Event 2"); + expect(result[1].title).toBe("Event 1"); + }); +}); diff --git a/tests/resolvers/Query/getRecurringEvents.spec.ts b/tests/resolvers/Query/getRecurringEvents.spec.ts new file mode 100644 index 0000000000..25c269fa02 --- /dev/null +++ b/tests/resolvers/Query/getRecurringEvents.spec.ts @@ -0,0 +1,101 @@ +import "dotenv/config"; +import { getRecurringEvents } from "../../../src/resolvers/Query/getRecurringEvents"; +import { connect, disconnect } from "../../helpers/db"; +import type mongoose from "mongoose"; +import { Event } from "../../../src/models"; +import { beforeAll, afterAll, describe, it, expect, vi } from "vitest"; +import { Types } from "mongoose"; + +let MONGOOSE_INSTANCE: typeof mongoose; + +beforeAll(async () => { + MONGOOSE_INSTANCE = await connect(); +}); + +afterAll(async () => { + await disconnect(MONGOOSE_INSTANCE); +}); + +describe("resolvers -> Query -> getRecurringEvents", () => { + it("returns list of recurring events for a given baseRecurringEventId", async () => { + const baseRecurringEventId = new Types.ObjectId(); + const organizationId = new Types.ObjectId(); + const creatorId = new Types.ObjectId(); + + const testEvents = [ + { + title: "Event 1", + description: "Description 1", + allDay: false, + startDate: new Date(), + startTime: new Date(), + endTime: new Date(), + isPublic: true, + isRegisterable: true, + organization: organizationId, + creatorId: creatorId, + baseRecurringEventId, + }, + { + title: "Event 2", + description: "Description 2", + allDay: false, + startDate: new Date(), + startTime: new Date(), + endTime: new Date(), + isPublic: true, + isRegisterable: true, + organization: organizationId, + creatorId: creatorId, + baseRecurringEventId, + }, + { + title: "Event 3", + description: "Description 3", + allDay: false, + startDate: new Date(), + startTime: new Date(), + endTime: new Date(), + isPublic: true, + isRegisterable: true, + organization: organizationId, + creatorId: creatorId, + baseRecurringEventId: new Types.ObjectId(), + }, + ]; + + await Event.insertMany(testEvents); + + const args = { baseRecurringEventId: baseRecurringEventId.toString() }; + const result = await getRecurringEvents({}, args, {} as any); + + expect(result).toHaveLength(2); + expect(result[0].title).toBe("Event 1"); + expect(result[1].title).toBe("Event 2"); + + // Clean up + await Event.deleteMany({ _id: { $in: result.map((e) => e._id) } }); + }); + + it("returns an empty array when no recurring events are found", async () => { + const nonExistentId = new Types.ObjectId(); + const args = { baseRecurringEventId: nonExistentId.toString() }; + const result = await getRecurringEvents({}, args, {} as any); + + expect(result).toEqual([]); + }); + + it("throws an error when there's a problem fetching events", async () => { + const mockFind = vi.spyOn(Event, "find").mockImplementation(() => { + throw new Error("Database error"); + }); + + const args = { baseRecurringEventId: new Types.ObjectId().toString() }; + + await expect(getRecurringEvents({}, args, {} as any)).rejects.toThrow( + "Database error", + ); + + mockFind.mockRestore(); + }); +}); From e7709168d9b70067b321ca03f77bce1835c009dc Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Sat, 5 Oct 2024 07:21:55 +0530 Subject: [PATCH 12/18] wip --- src/resolvers/Query/getRecurringEvents.ts | 4 +- .../Query/eventAttendedByUser.spec.ts | 156 ++++++++---------- .../Query/getRecurringEvents.spec.ts | 68 ++++---- 3 files changed, 102 insertions(+), 126 deletions(-) diff --git a/src/resolvers/Query/getRecurringEvents.ts b/src/resolvers/Query/getRecurringEvents.ts index 0e92603180..e36ad7bb77 100644 --- a/src/resolvers/Query/getRecurringEvents.ts +++ b/src/resolvers/Query/getRecurringEvents.ts @@ -1,6 +1,6 @@ import type { QueryResolvers } from "../../types/generatedGraphQLTypes"; import { Event } from "../../models"; - +import type { InterfaceEvent } from "../../models/Event"; /** * This query will fetch all the events with the same BaseRecurringEventId from the database. * @param _parent - @@ -17,7 +17,7 @@ export const getRecurringEvents: QueryResolvers["getRecurringEvents"] = async ( baseRecurringEventId: args.baseRecurringEventId, }).lean(); - return recurringEvents; + return recurringEvents as InterfaceEvent[]; } catch (error) { console.error("Error fetching recurring events:", error); throw error; diff --git a/tests/resolvers/Query/eventAttendedByUser.spec.ts b/tests/resolvers/Query/eventAttendedByUser.spec.ts index 1a1fd7bb56..cc0af3dbd9 100644 --- a/tests/resolvers/Query/eventAttendedByUser.spec.ts +++ b/tests/resolvers/Query/eventAttendedByUser.spec.ts @@ -1,117 +1,95 @@ import "dotenv/config"; -import { eventsAttendedByUser } from "../../../src/resolvers/Query/eventsAttendedByUser"; -import { connect, disconnect } from "../../helpers/db"; import type mongoose from "mongoose"; -import { Event, User } from "../../../src/models"; -import { beforeAll, afterAll, describe, it, expect } from "vitest"; import { Types } from "mongoose"; +import { User, Event } from "../../../src/models"; +import type { InterfaceEvent } from "../../../src/models/Event"; +import { beforeAll, afterAll, describe, it, expect } from "vitest"; +import type { InterfaceUser } from "../../../src/models/User"; +import { connect, disconnect } from "../../helpers/db"; +import { eventsAttendedByUser } from "../../../src/resolvers/Query/eventsAttendedByUser"; let MONGOOSE_INSTANCE: typeof mongoose; -let testUser: any; -let testEvents: any[]; beforeAll(async () => { MONGOOSE_INSTANCE = await connect(); - - testUser = await User.create({ - firstName: "Test", - lastName: "User", - email: "testuser@example.com", - password: "password123", - }); - - const organizationId = new Types.ObjectId(); - const creatorId = new Types.ObjectId(); - - testEvents = await Event.create([ - { - title: "Event 1", - description: "Description 1", - allDay: false, - startDate: new Date(), - startTime: new Date(), - endTime: new Date(), - isPublic: true, - isRegisterable: true, - organization: organizationId, - creatorId: creatorId, - registrants: [{ userId: testUser._id, status: "ACTIVE" }], - }, - { - title: "Event 2", - description: "Description 2", - allDay: false, - startDate: new Date(), - startTime: new Date(), - endTime: new Date(), - isPublic: true, - isRegisterable: true, - organization: organizationId, - creatorId: creatorId, - registrants: [{ userId: testUser._id, status: "ACTIVE" }], - }, - { - title: "Event 3", - description: "Description 3", - allDay: false, - startDate: new Date(), - startTime: new Date(), - endTime: new Date(), - isPublic: true, - isRegisterable: true, - organization: organizationId, - creatorId: creatorId, - registrants: [{ userId: testUser._id, status: "INACTIVE" }], - }, - ]); }); afterAll(async () => { - await User.deleteMany({}); - await Event.deleteMany({}); await disconnect(MONGOOSE_INSTANCE); }); -describe("resolvers -> Query -> eventsAttendedByUser", () => { - it("returns events attended by the user with ACTIVE status", async () => { - const args = { id: testUser._id.toString() }; - const result = await eventsAttendedByUser({}, args, {} as any); +describe("resolvers -> Query -> eventAttendedByUser", () => { + let testUser: InterfaceUser; + let testEvents: InterfaceEvent[]; - expect(result).toHaveLength(2); - expect(result[0].title).toBe("Event 1"); - expect(result[1].title).toBe("Event 2"); - }); + beforeAll(async () => { + testUser = await User.create({ + firstName: "Test", + lastName: "User", + email: "testuser@example.com", + password: "pass@123", + }); - it("does not return events with INACTIVE status", async () => { - const args = { id: testUser._id.toString() }; - const result = await eventsAttendedByUser({}, args, {} as any); + const eventData: Partial[] = [ + { + title: "Test Event 1", + description: "Test Description 1", + attendees: testUser._id.toString(), + isRegisterable: true, + isPublic: true, + creatorId: testUser._id, + }, + { + title: "Test Event 2", + description: "Test Description 2", + attendees: "", + isRegisterable: true, + isPublic: true, + creatorId: testUser._id, + }, + ]; - const inactiveEvent = result.find((event) => event.title === "Event 3"); - expect(inactiveEvent).toBeUndefined(); + testEvents = await Event.create(eventData); }); - it("returns an empty array when user has not attended any events", async () => { - const newUser = await User.create({ - firstName: "New", - lastName: "User", - email: "newuser@example.com", - password: "password123", - }); + afterAll(async () => { + await User.deleteMany({}); + await Event.deleteMany({}); + }); - const args = { id: newUser._id.toString() }; - const result = await eventsAttendedByUser({}, args, {} as any); + it("returns true if user has attended the event", async () => { + const args = { + userId: testUser._id.toString(), + eventId: testEvents[0]._id.toString(), + }; + const result = await eventsAttendedByUser({}, args, {} as unknown); + expect(result).toBe(true); + }); - expect(result).toHaveLength(0); + it("returns false if user has not attended the event", async () => { + const args = { + userId: testUser._id.toString(), + eventId: testEvents[1]._id.toString(), + }; + const result = await eventsAttendedByUser({}, args, {} as unknown); + expect(result).toBe(false); }); - it("sorts events based on the provided orderBy argument", async () => { + it("returns false if user does not exist", async () => { const args = { - id: testUser._id.toString(), - orderBy: "title_DESC", + userId: new Types.ObjectId().toString(), + eventId: testEvents[0]._id.toString(), }; - const result = await eventsAttendedByUser({}, args, {} as any); + const result = await eventsAttendedByUser({}, args, {} as unknown); + expect(result).toBe(false); + }); - expect(result[0].title).toBe("Event 2"); - expect(result[1].title).toBe("Event 1"); + it("returns false if event does not exist", async () => { + const args = { + userId: testUser._id.toString(), + eventId: new Types.ObjectId().toString(), + }; + const result = await eventsAttendedByUser({}, args, {} as unknown); + expect(result).toBe(false); }); }); diff --git a/tests/resolvers/Query/getRecurringEvents.spec.ts b/tests/resolvers/Query/getRecurringEvents.spec.ts index 25c269fa02..d2b28bffda 100644 --- a/tests/resolvers/Query/getRecurringEvents.spec.ts +++ b/tests/resolvers/Query/getRecurringEvents.spec.ts @@ -5,13 +5,25 @@ import type mongoose from "mongoose"; import { Event } from "../../../src/models"; import { beforeAll, afterAll, describe, it, expect, vi } from "vitest"; import { Types } from "mongoose"; +import { + createTestUser, + createTestUserAndOrganization, + type TestOrganizationType, + type TestUserType, +} from "../../helpers/userAndOrg"; let MONGOOSE_INSTANCE: typeof mongoose; +let testUser: TestUserType; +let testAdminUser: TestUserType; +let testOrganization: TestOrganizationType; beforeAll(async () => { + const temp = await createTestUserAndOrganization(); + testUser = temp[0]; + testOrganization = temp[1]; MONGOOSE_INSTANCE = await connect(); + testAdminUser = await createTestUser(); }); - afterAll(async () => { await disconnect(MONGOOSE_INSTANCE); }); @@ -19,68 +31,54 @@ afterAll(async () => { describe("resolvers -> Query -> getRecurringEvents", () => { it("returns list of recurring events for a given baseRecurringEventId", async () => { const baseRecurringEventId = new Types.ObjectId(); - const organizationId = new Types.ObjectId(); - const creatorId = new Types.ObjectId(); const testEvents = [ { title: "Event 1", - description: "Description 1", - allDay: false, - startDate: new Date(), - startTime: new Date(), - endTime: new Date(), + description: "description", + allDay: true, + startDate: new Date().toUTCString(), + recurring: true, isPublic: true, isRegisterable: true, - organization: organizationId, - creatorId: creatorId, + creator: testUser._id, + admins: [testAdminUser._id], + registrants: [], + organization: testOrganization._id, baseRecurringEventId, }, { title: "Event 2", - description: "Description 2", - allDay: false, + description: "description", + allDay: true, startDate: new Date(), - startTime: new Date(), - endTime: new Date(), + recurring: true, isPublic: true, isRegisterable: true, - organization: organizationId, - creatorId: creatorId, + creator: testUser._id, + admins: [testAdminUser._id], + registrants: [], + organization: testOrganization._id, baseRecurringEventId, }, - { - title: "Event 3", - description: "Description 3", - allDay: false, - startDate: new Date(), - startTime: new Date(), - endTime: new Date(), - isPublic: true, - isRegisterable: true, - organization: organizationId, - creatorId: creatorId, - baseRecurringEventId: new Types.ObjectId(), - }, ]; await Event.insertMany(testEvents); const args = { baseRecurringEventId: baseRecurringEventId.toString() }; - const result = await getRecurringEvents({}, args, {} as any); + const result = await getRecurringEvents({}, args, {} as unknown); expect(result).toHaveLength(2); expect(result[0].title).toBe("Event 1"); expect(result[1].title).toBe("Event 2"); - // Clean up - await Event.deleteMany({ _id: { $in: result.map((e) => e._id) } }); + await Event.deleteMany({ baseRecurringEventId }); }); it("returns an empty array when no recurring events are found", async () => { const nonExistentId = new Types.ObjectId(); const args = { baseRecurringEventId: nonExistentId.toString() }; - const result = await getRecurringEvents({}, args, {} as any); + const result = await getRecurringEvents({}, args, {} as unknown); expect(result).toEqual([]); }); @@ -92,8 +90,8 @@ describe("resolvers -> Query -> getRecurringEvents", () => { const args = { baseRecurringEventId: new Types.ObjectId().toString() }; - await expect(getRecurringEvents({}, args, {} as any)).rejects.toThrow( - "Database error", + await expect(getRecurringEvents({}, args, {} as unknown)).rejects.toThrow( + "Database error" ); mockFind.mockRestore(); From 440d651874768f2953cb94a33556497ad901b853 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Tue, 8 Oct 2024 07:23:43 +0530 Subject: [PATCH 13/18] added test cases for both queries --- .../Query/eventAttendedByUser.spec.ts | 95 ------------------- .../Query/eventsAttendedByUser.spec.ts | 59 ++++++++++++ .../Query/getRecurringEvents.spec.ts | 25 +++-- 3 files changed, 75 insertions(+), 104 deletions(-) delete mode 100644 tests/resolvers/Query/eventAttendedByUser.spec.ts create mode 100644 tests/resolvers/Query/eventsAttendedByUser.spec.ts diff --git a/tests/resolvers/Query/eventAttendedByUser.spec.ts b/tests/resolvers/Query/eventAttendedByUser.spec.ts deleted file mode 100644 index cc0af3dbd9..0000000000 --- a/tests/resolvers/Query/eventAttendedByUser.spec.ts +++ /dev/null @@ -1,95 +0,0 @@ -import "dotenv/config"; -import type mongoose from "mongoose"; -import { Types } from "mongoose"; -import { User, Event } from "../../../src/models"; -import type { InterfaceEvent } from "../../../src/models/Event"; -import { beforeAll, afterAll, describe, it, expect } from "vitest"; -import type { InterfaceUser } from "../../../src/models/User"; -import { connect, disconnect } from "../../helpers/db"; -import { eventsAttendedByUser } from "../../../src/resolvers/Query/eventsAttendedByUser"; - -let MONGOOSE_INSTANCE: typeof mongoose; - -beforeAll(async () => { - MONGOOSE_INSTANCE = await connect(); -}); - -afterAll(async () => { - await disconnect(MONGOOSE_INSTANCE); -}); - -describe("resolvers -> Query -> eventAttendedByUser", () => { - let testUser: InterfaceUser; - let testEvents: InterfaceEvent[]; - - beforeAll(async () => { - testUser = await User.create({ - firstName: "Test", - lastName: "User", - email: "testuser@example.com", - password: "pass@123", - }); - - const eventData: Partial[] = [ - { - title: "Test Event 1", - description: "Test Description 1", - attendees: testUser._id.toString(), - isRegisterable: true, - isPublic: true, - creatorId: testUser._id, - }, - { - title: "Test Event 2", - description: "Test Description 2", - attendees: "", - isRegisterable: true, - isPublic: true, - creatorId: testUser._id, - }, - ]; - - testEvents = await Event.create(eventData); - }); - - afterAll(async () => { - await User.deleteMany({}); - await Event.deleteMany({}); - }); - - it("returns true if user has attended the event", async () => { - const args = { - userId: testUser._id.toString(), - eventId: testEvents[0]._id.toString(), - }; - const result = await eventsAttendedByUser({}, args, {} as unknown); - expect(result).toBe(true); - }); - - it("returns false if user has not attended the event", async () => { - const args = { - userId: testUser._id.toString(), - eventId: testEvents[1]._id.toString(), - }; - const result = await eventsAttendedByUser({}, args, {} as unknown); - expect(result).toBe(false); - }); - - it("returns false if user does not exist", async () => { - const args = { - userId: new Types.ObjectId().toString(), - eventId: testEvents[0]._id.toString(), - }; - const result = await eventsAttendedByUser({}, args, {} as unknown); - expect(result).toBe(false); - }); - - it("returns false if event does not exist", async () => { - const args = { - userId: testUser._id.toString(), - eventId: new Types.ObjectId().toString(), - }; - const result = await eventsAttendedByUser({}, args, {} as unknown); - expect(result).toBe(false); - }); -}); diff --git a/tests/resolvers/Query/eventsAttendedByUser.spec.ts b/tests/resolvers/Query/eventsAttendedByUser.spec.ts new file mode 100644 index 0000000000..f7b0a3a191 --- /dev/null +++ b/tests/resolvers/Query/eventsAttendedByUser.spec.ts @@ -0,0 +1,59 @@ +import "dotenv/config"; +import type mongoose from "mongoose"; +import { Event } from "../../../src/models"; +import { connect, disconnect } from "../../helpers/db"; +import type { QueryEventsAttendedByUserArgs } from "../../../src/types/generatedGraphQLTypes"; +import { beforeAll, afterAll, describe, it, expect } from "vitest"; +import type { TestUserType, TestOrganizationType } from "../../helpers/userAndOrg"; +import { createTestUserAndOrganization } from "../../helpers/userAndOrg"; +import { createEventWithRegistrant } from "../../helpers/events"; + +let MONGOOSE_INSTANCE: typeof mongoose; +let testUser: TestUserType; +let testOrganization: TestOrganizationType; + +beforeAll(async () => { + MONGOOSE_INSTANCE = await connect(); + [testUser, testOrganization] = await createTestUserAndOrganization(); + + await createEventWithRegistrant(testUser?._id, testOrganization?._id, true); + await createEventWithRegistrant(testUser?._id, testOrganization?._id, true); +}); + +afterAll(async () => { + await disconnect(MONGOOSE_INSTANCE); +}); + +describe("resolvers -> Query -> eventsAttendedByUser", () => { + it(`returns list of all events attended by user sorted by ascending order of event._id if args.orderBy === 'id_ASC'`, async () => { + const args: QueryEventsAttendedByUserArgs = { + id: testUser?._id, + orderBy: "id_ASC", + }; + + const { eventsAttendedByUser } = await import( + "../../../src/resolvers/Query/eventsAttendedByUser" + ); + + const eventsAttendedByUserPayload = await eventsAttendedByUser?.( + {}, + args, + {}, + ); + + const eventsAttendedByUserInfo = await Event.find({ + registrants: { + $elemMatch: { + userId: testUser?._id, + status: "ACTIVE", + }, + }, + }) + .sort({ _id: 1 }) + .populate("creatorId", "-password") + .populate("admins", "-password") + .lean(); + + expect(eventsAttendedByUserPayload).toEqual(eventsAttendedByUserInfo); + }); +}); diff --git a/tests/resolvers/Query/getRecurringEvents.spec.ts b/tests/resolvers/Query/getRecurringEvents.spec.ts index d2b28bffda..631625b37c 100644 --- a/tests/resolvers/Query/getRecurringEvents.spec.ts +++ b/tests/resolvers/Query/getRecurringEvents.spec.ts @@ -18,18 +18,22 @@ let testAdminUser: TestUserType; let testOrganization: TestOrganizationType; beforeAll(async () => { - const temp = await createTestUserAndOrganization(); - testUser = temp[0]; - testOrganization = temp[1]; MONGOOSE_INSTANCE = await connect(); + const result = await createTestUserAndOrganization(); + testUser = result[0]; + testOrganization = result[1]; testAdminUser = await createTestUser(); }); + afterAll(async () => { await disconnect(MONGOOSE_INSTANCE); }); describe("resolvers -> Query -> getRecurringEvents", () => { it("returns list of recurring events for a given baseRecurringEventId", async () => { + if (!testUser || !testAdminUser || !testOrganization) { + throw new Error("Test setup failed"); + } const baseRecurringEventId = new Types.ObjectId(); const testEvents = [ @@ -41,7 +45,7 @@ describe("resolvers -> Query -> getRecurringEvents", () => { recurring: true, isPublic: true, isRegisterable: true, - creator: testUser._id, + creatorId: testUser._id, admins: [testAdminUser._id], registrants: [], organization: testOrganization._id, @@ -55,7 +59,7 @@ describe("resolvers -> Query -> getRecurringEvents", () => { recurring: true, isPublic: true, isRegisterable: true, - creator: testUser._id, + creatorId: testUser._id, admins: [testAdminUser._id], registrants: [], organization: testOrganization._id, @@ -66,7 +70,8 @@ describe("resolvers -> Query -> getRecurringEvents", () => { await Event.insertMany(testEvents); const args = { baseRecurringEventId: baseRecurringEventId.toString() }; - const result = await getRecurringEvents({}, args, {} as unknown); + const getRecurringEventsFunction = getRecurringEvents as unknown as (parent: any, args: any, context: any) => Promise; + const result = await getRecurringEventsFunction({}, args, {}); expect(result).toHaveLength(2); expect(result[0].title).toBe("Event 1"); @@ -78,7 +83,8 @@ describe("resolvers -> Query -> getRecurringEvents", () => { it("returns an empty array when no recurring events are found", async () => { const nonExistentId = new Types.ObjectId(); const args = { baseRecurringEventId: nonExistentId.toString() }; - const result = await getRecurringEvents({}, args, {} as unknown); + const getRecurringEventsFunction = getRecurringEvents as unknown as (parent: any, args: any, context: any) => Promise; + const result = await getRecurringEventsFunction({}, args, {}); expect(result).toEqual([]); }); @@ -89,11 +95,12 @@ describe("resolvers -> Query -> getRecurringEvents", () => { }); const args = { baseRecurringEventId: new Types.ObjectId().toString() }; + const getRecurringEventsFunction = getRecurringEvents as unknown as (parent: any, args: any, context: any) => Promise; - await expect(getRecurringEvents({}, args, {} as unknown)).rejects.toThrow( + await expect(getRecurringEventsFunction({}, args, {})).rejects.toThrow( "Database error" ); mockFind.mockRestore(); }); -}); +}); \ No newline at end of file From 50c6c10aa459d4350db4c72245df697992fecdc0 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Tue, 8 Oct 2024 07:28:34 +0530 Subject: [PATCH 14/18] minor format changes --- .../Query/eventsAttendedByUser.spec.ts | 7 ++++-- .../Query/getRecurringEvents.spec.ts | 22 ++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/tests/resolvers/Query/eventsAttendedByUser.spec.ts b/tests/resolvers/Query/eventsAttendedByUser.spec.ts index f7b0a3a191..7ee2807417 100644 --- a/tests/resolvers/Query/eventsAttendedByUser.spec.ts +++ b/tests/resolvers/Query/eventsAttendedByUser.spec.ts @@ -4,7 +4,10 @@ import { Event } from "../../../src/models"; import { connect, disconnect } from "../../helpers/db"; import type { QueryEventsAttendedByUserArgs } from "../../../src/types/generatedGraphQLTypes"; import { beforeAll, afterAll, describe, it, expect } from "vitest"; -import type { TestUserType, TestOrganizationType } from "../../helpers/userAndOrg"; +import type { + TestUserType, + TestOrganizationType, +} from "../../helpers/userAndOrg"; import { createTestUserAndOrganization } from "../../helpers/userAndOrg"; import { createEventWithRegistrant } from "../../helpers/events"; @@ -15,7 +18,7 @@ let testOrganization: TestOrganizationType; beforeAll(async () => { MONGOOSE_INSTANCE = await connect(); [testUser, testOrganization] = await createTestUserAndOrganization(); - + await createEventWithRegistrant(testUser?._id, testOrganization?._id, true); await createEventWithRegistrant(testUser?._id, testOrganization?._id, true); }); diff --git a/tests/resolvers/Query/getRecurringEvents.spec.ts b/tests/resolvers/Query/getRecurringEvents.spec.ts index 631625b37c..8b995ca4b3 100644 --- a/tests/resolvers/Query/getRecurringEvents.spec.ts +++ b/tests/resolvers/Query/getRecurringEvents.spec.ts @@ -70,7 +70,11 @@ describe("resolvers -> Query -> getRecurringEvents", () => { await Event.insertMany(testEvents); const args = { baseRecurringEventId: baseRecurringEventId.toString() }; - const getRecurringEventsFunction = getRecurringEvents as unknown as (parent: any, args: any, context: any) => Promise; + const getRecurringEventsFunction = getRecurringEvents as unknown as ( + parent: any, + args: any, + context: any, + ) => Promise; const result = await getRecurringEventsFunction({}, args, {}); expect(result).toHaveLength(2); @@ -83,7 +87,11 @@ describe("resolvers -> Query -> getRecurringEvents", () => { it("returns an empty array when no recurring events are found", async () => { const nonExistentId = new Types.ObjectId(); const args = { baseRecurringEventId: nonExistentId.toString() }; - const getRecurringEventsFunction = getRecurringEvents as unknown as (parent: any, args: any, context: any) => Promise; + const getRecurringEventsFunction = getRecurringEvents as unknown as ( + parent: any, + args: any, + context: any, + ) => Promise; const result = await getRecurringEventsFunction({}, args, {}); expect(result).toEqual([]); @@ -95,12 +103,16 @@ describe("resolvers -> Query -> getRecurringEvents", () => { }); const args = { baseRecurringEventId: new Types.ObjectId().toString() }; - const getRecurringEventsFunction = getRecurringEvents as unknown as (parent: any, args: any, context: any) => Promise; + const getRecurringEventsFunction = getRecurringEvents as unknown as ( + parent: any, + args: any, + context: any, + ) => Promise; await expect(getRecurringEventsFunction({}, args, {})).rejects.toThrow( - "Database error" + "Database error", ); mockFind.mockRestore(); }); -}); \ No newline at end of file +}); From 7bfad4457b9ba851b3e1979ed6e40321d0714690 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Tue, 8 Oct 2024 08:07:14 +0530 Subject: [PATCH 15/18] minor changes --- src/resolvers/Mutation/addEventAttendee.ts | 6 +++--- tests/resolvers/Mutation/addEventAttendee.spec.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/resolvers/Mutation/addEventAttendee.ts b/src/resolvers/Mutation/addEventAttendee.ts index 7309a7b74d..bc5ad8b3a3 100644 --- a/src/resolvers/Mutation/addEventAttendee.ts +++ b/src/resolvers/Mutation/addEventAttendee.ts @@ -184,9 +184,9 @@ export const addEventAttendee: MutationResolvers["addEventAttendee"] = async ( if (!updatedUser) { throw new errors.NotFoundError( - requestContext.translate(USER_NOT_AUTHORIZED_ERROR.MESSAGE), - USER_NOT_AUTHORIZED_ERROR.CODE, - USER_NOT_AUTHORIZED_ERROR.PARAM, + requestContext.translate(USER_NOT_FOUND_ERROR.MESSAGE), + USER_NOT_FOUND_ERROR.CODE, + USER_NOT_FOUND_ERROR.PARAM, ); } return updatedUser; diff --git a/tests/resolvers/Mutation/addEventAttendee.spec.ts b/tests/resolvers/Mutation/addEventAttendee.spec.ts index 0f0960d398..6a0d733972 100644 --- a/tests/resolvers/Mutation/addEventAttendee.spec.ts +++ b/tests/resolvers/Mutation/addEventAttendee.spec.ts @@ -320,9 +320,9 @@ describe("resolvers -> Mutation -> addEventAttendee", () => { await addEventAttendeeResolver?.({}, args, context); } catch (error: unknown) { expect((error as Error).message).toEqual( - `Translated ${USER_NOT_AUTHORIZED_ERROR.MESSAGE}`, + `Translated ${USER_NOT_FOUND_ERROR.MESSAGE}`, ); - expect(spy).toHaveBeenLastCalledWith(USER_NOT_AUTHORIZED_ERROR.MESSAGE); + expect(spy).toHaveBeenLastCalledWith(USER_NOT_FOUND_ERROR.MESSAGE); } mockFindByIdAndUpdate.mockRestore(); }); From 30fbe61a4d50e2f7671060a7e0159cf56a873599 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Tue, 8 Oct 2024 08:21:24 +0530 Subject: [PATCH 16/18] minor --- tests/resolvers/Mutation/addEventAttendee.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/resolvers/Mutation/addEventAttendee.spec.ts b/tests/resolvers/Mutation/addEventAttendee.spec.ts index 6a0d733972..0f0960d398 100644 --- a/tests/resolvers/Mutation/addEventAttendee.spec.ts +++ b/tests/resolvers/Mutation/addEventAttendee.spec.ts @@ -320,9 +320,9 @@ describe("resolvers -> Mutation -> addEventAttendee", () => { await addEventAttendeeResolver?.({}, args, context); } catch (error: unknown) { expect((error as Error).message).toEqual( - `Translated ${USER_NOT_FOUND_ERROR.MESSAGE}`, + `Translated ${USER_NOT_AUTHORIZED_ERROR.MESSAGE}`, ); - expect(spy).toHaveBeenLastCalledWith(USER_NOT_FOUND_ERROR.MESSAGE); + expect(spy).toHaveBeenLastCalledWith(USER_NOT_AUTHORIZED_ERROR.MESSAGE); } mockFindByIdAndUpdate.mockRestore(); }); From 87b6ffe28ac862167425d7230287ad4ab5c68523 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:01:21 +0530 Subject: [PATCH 17/18] minor --- src/resolvers/Mutation/addEventAttendee.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/resolvers/Mutation/addEventAttendee.ts b/src/resolvers/Mutation/addEventAttendee.ts index bc5ad8b3a3..26c1fe4e03 100644 --- a/src/resolvers/Mutation/addEventAttendee.ts +++ b/src/resolvers/Mutation/addEventAttendee.ts @@ -181,13 +181,5 @@ export const addEventAttendee: MutationResolvers["addEventAttendee"] = async ( }, { new: true }, ); - - if (!updatedUser) { - throw new errors.NotFoundError( - requestContext.translate(USER_NOT_FOUND_ERROR.MESSAGE), - USER_NOT_FOUND_ERROR.CODE, - USER_NOT_FOUND_ERROR.PARAM, - ); - } return updatedUser; }; From f820db1c32619468a2aeb251b12547a7705d30f1 Mon Sep 17 00:00:00 2001 From: duplixx <90516956+duplixx@users.noreply.github.com> Date: Wed, 9 Oct 2024 23:57:50 +0530 Subject: [PATCH 18/18] reverted the updated user error handling --- src/resolvers/Mutation/addEventAttendee.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/resolvers/Mutation/addEventAttendee.ts b/src/resolvers/Mutation/addEventAttendee.ts index 26c1fe4e03..6a29d729d8 100644 --- a/src/resolvers/Mutation/addEventAttendee.ts +++ b/src/resolvers/Mutation/addEventAttendee.ts @@ -181,5 +181,14 @@ export const addEventAttendee: MutationResolvers["addEventAttendee"] = async ( }, { new: true }, ); + + if (!updatedUser) { + throw new errors.NotFoundError( + requestContext.translate(USER_NOT_FOUND_ERROR.MESSAGE), + USER_NOT_FOUND_ERROR.CODE, + USER_NOT_FOUND_ERROR.PARAM, + ); + } + return updatedUser; };