Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented Reply functionality for DirectChat and GroupChat #2420

Open
wants to merge 42 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a8c02f8
Updated subscriptions and added mutations for directChat and groupChat
disha1202 Jul 15, 2024
fe6907d
Update index.ts
disha1202 Jul 16, 2024
3a9799d
Update messageSentToDirectChat.ts
disha1202 Jul 16, 2024
2fa65b1
Update createDirectChat.spec.ts
disha1202 Jul 16, 2024
f68bb01
Update createDirectChat.spec.ts
disha1202 Jul 16, 2024
f7089b9
fix: linting errors
disha1202 Jul 16, 2024
2fe5353
fix: lint errors
disha1202 Jul 16, 2024
7e31c14
fix: formatting issues
disha1202 Jul 16, 2024
0bf28a2
Merge branch 'develop' into chat-feature
disha1202 Jul 16, 2024
9c44ea4
fix: formatting issues
disha1202 Jul 16, 2024
fa5f6ec
fix: test cases
disha1202 Jul 16, 2024
3db8381
fix test cases
disha1202 Jul 16, 2024
a1379bf
Update messageSentToDirectChat.ts
disha1202 Jul 18, 2024
bd98a6b
Update messageSentToDirectChat.ts
disha1202 Jul 18, 2024
7ec1773
added test cases for query directChatById
Jul 18, 2024
3781ede
Update directChatById.spec.ts
disha1202 Jul 18, 2024
8aaf5f3
Update directChatById.spec.ts
disha1202 Jul 18, 2024
e83657d
Update directChatById.spec.ts
disha1202 Jul 18, 2024
23a9676
Added test cases
disha1202 Jul 18, 2024
9576d4a
fix: test cases
disha1202 Jul 18, 2024
c2af22d
fix: tests
disha1202 Jul 18, 2024
ad48619
fix test cases
disha1202 Jul 18, 2024
77c7fde
Merge branch 'chat-feature' of https://github.com/disha1202/talawa-ap…
disha1202 Jul 18, 2024
d18843a
added support to reply to direct chat and group chat
disha1202 Jul 24, 2024
cf27ca6
Merge branch 'develop' of https://github.com/disha1202/talawa-api int…
disha1202 Jul 24, 2024
8469653
fix: test cases
disha1202 Jul 24, 2024
f936adc
removed console logs
disha1202 Jul 28, 2024
babf1c0
Merge branch 'develop' into reply-functionality
disha1202 Jul 28, 2024
c84f33a
Merge branch 'develop' into reply-functionality
disha1202 Jul 30, 2024
ef2d45d
Merge branch 'develop' into reply-functionality
disha1202 Aug 18, 2024
a2ccfb0
Removed unwanted code
disha1202 Aug 18, 2024
52165f1
Merge branch 'reply-functionality' of https://github.com/disha1202/ta…
disha1202 Aug 18, 2024
369a81d
Merge branch 'develop' into reply-functionality
disha1202 Aug 21, 2024
979bf37
Merge branch 'develop' into reply-functionality
disha1202 Aug 21, 2024
dd9120f
Merge branch 'develop' into reply-functionality
disha1202 Aug 23, 2024
08a6fed
Merge branch 'develop' into reply-functionality
disha1202 Aug 24, 2024
b6fa93e
added test cases
disha1202 Aug 24, 2024
0e0b1d3
Merge branch 'reply-functionality' of https://github.com/disha1202/ta…
disha1202 Aug 24, 2024
4f9ea48
removed unwanted comments
disha1202 Aug 24, 2024
7baed1d
Merge branch 'develop' into reply-functionality
disha1202 Sep 1, 2024
b3032db
Merge branch 'develop' into reply-functionality
disha1202 Sep 22, 2024
d0b54f6
Merge branch 'develop' into reply-functionality
disha1202 Oct 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ type Mutation {
revokeRefreshTokenForUser: Boolean!
saveFcmToken(token: String): Boolean!
sendMembershipRequest(organizationId: ID!): MembershipRequest!
sendMessageToDirectChat(chatId: ID!, messageContent: String!): DirectChatMessage!
sendMessageToDirectChat(chatId: ID!, messageContent: String!, replyTo: ID): DirectChatMessage!
sendMessageToGroupChat(chatId: ID!, messageContent: String!): GroupChatMessage!
signUp(data: UserInput!, file: String): AuthData!
togglePostPin(id: ID!, title: String): Post!
Expand Down
7 changes: 7 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ export const CHAT_NOT_FOUND_ERROR = Object.freeze({
PARAM: "chat",
});

export const MESSAGE_NOT_FOUND_ERROR = Object.freeze({
DESC: "Message not found",
CODE: "message.notFound",
MESSAGE: "message.notFound",
PARAM: "message",
});

export const VENUE_ALREADY_EXISTS_ERROR = Object.freeze({
DESC: "Venue already exists",
CODE: "venue.alreadyExists",
Expand Down
6 changes: 6 additions & 0 deletions src/models/DirectChatMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface InterfaceDirectChatMessage {
directChatMessageBelongsTo: PopulatedDoc<InterfaceDirectChat & Document>;
sender: PopulatedDoc<InterfaceUser & Document>;
receiver: PopulatedDoc<InterfaceUser & Document>;
replyTo: PopulatedDoc<InterfaceDirectChatMessage & Document>;
messageContent: string;
status: string;
createdAt: Date;
Expand Down Expand Up @@ -45,6 +46,11 @@ const directChatMessageSchema = new Schema(
ref: "User",
required: true,
},
replyTo: {
type: Schema.Types.ObjectId,
ref: "DirectChatMessage",
required: false,
},
messageContent: {
type: String,
required: true,
Expand Down
6 changes: 6 additions & 0 deletions src/models/GroupChatMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface InterfaceGroupChatMessage {
sender: PopulatedDoc<InterfaceUser & Document>;
createdAt: Date;
updatedAt: Date;
replyTo: PopulatedDoc<InterfaceGroupChatMessage & Document>;
messageContent: string;
status: string;
}
Expand All @@ -39,6 +40,11 @@ const groupChatMessageSchema = new Schema(
ref: "User",
required: true,
},
replyTo: {
type: Schema.Types.ObjectId,
ref: "GroupChatMessage",
required: false,
},
messageContent: {
type: String,
required: true,
Expand Down
2 changes: 2 additions & 0 deletions src/resolvers/DirectChatMessage/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { DirectChatMessageResolvers } from "../../types/generatedGraphQLTypes";
import { directChatMessageBelongsTo } from "./directChatMessageBelongsTo";
import { receiver } from "./receiver";
import { replyTo } from "./replyTo";
import { sender } from "./sender";

export const DirectChatMessage: DirectChatMessageResolvers = {
directChatMessageBelongsTo,
receiver,
sender,
replyTo,
};
31 changes: 31 additions & 0 deletions src/resolvers/DirectChatMessage/replyTo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { DirectChatMessageResolvers } from "../../types/generatedGraphQLTypes";
import { DirectChatMessage } from "../../models";
import { MESSAGE_NOT_FOUND_ERROR } from "../../constants";
import { errors, requestContext } from "../../libraries";
/**
* This resolver function will fetch and return the receiver(user) of the Direct chat from the database.
* @param parent - An object that is the return value of the resolver for this field's parent.
* @returns An `object` that contains User's data.
*/
export const replyTo: DirectChatMessageResolvers["replyTo"] = async (
parent,
) => {
console.log("PARENT ", parent);
disha1202 marked this conversation as resolved.
Show resolved Hide resolved
if (parent.replyTo) {
const result = await DirectChatMessage.findOne({
_id: parent.replyTo,
}).lean();

if (result) {
return result;
} else {
throw new errors.NotFoundError(
requestContext.translate(MESSAGE_NOT_FOUND_ERROR.MESSAGE),
MESSAGE_NOT_FOUND_ERROR.CODE,
MESSAGE_NOT_FOUND_ERROR.PARAM,
);
}
} else {
return null;
}
};
2 changes: 2 additions & 0 deletions src/resolvers/GroupChatMessage/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { GroupChatMessageResolvers } from "../../types/generatedGraphQLTypes";
import { groupChatMessageBelongsTo } from "./groupChatMessageBelongsTo";
import { replyTo } from "./replyTo";
import { sender } from "./sender";

export const GroupChatMessage: GroupChatMessageResolvers = {
groupChatMessageBelongsTo,
sender,
replyTo,
};
29 changes: 29 additions & 0 deletions src/resolvers/GroupChatMessage/replyTo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { GroupChatMessageResolvers } from "../../types/generatedGraphQLTypes";
disha1202 marked this conversation as resolved.
Show resolved Hide resolved
import { GroupChatMessage } from "../../models";
import { MESSAGE_NOT_FOUND_ERROR } from "../../constants";
import { errors, requestContext } from "../../libraries";
/**
* This resolver function will fetch and return the receiver(user) of the Direct chat from the database.
* @param parent - An object that is the return value of the resolver for this field's parent.
* @returns An `object` that contains User's data.
*/
export const replyTo: GroupChatMessageResolvers["replyTo"] = async (parent) => {
console.log("PARENT ", parent);
disha1202 marked this conversation as resolved.
Show resolved Hide resolved
if (parent.replyTo) {
const result = await GroupChatMessage.findOne({
_id: parent.replyTo,
}).lean();

if (result) {
return result;
} else {
throw new errors.NotFoundError(
requestContext.translate(MESSAGE_NOT_FOUND_ERROR.MESSAGE),
MESSAGE_NOT_FOUND_ERROR.CODE,
MESSAGE_NOT_FOUND_ERROR.PARAM,
);
}
} else {
return null;
}
};
1 change: 1 addition & 0 deletions src/resolvers/Mutation/sendMessageToDirectChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const sendMessageToDirectChat: MutationResolvers["sendMessageToDirectChat
sender: context.userId,
receiver: directChat.users[receiverIndex],
messageContent: args.messageContent,
replyTo: args.replyTo,
});

// add createdDirectChatMessage to directChat
Expand Down
1 change: 1 addition & 0 deletions src/resolvers/Mutation/sendMessageToGroupChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const sendMessageToGroupChat: MutationResolvers["sendMessageToGroupChat"]
sender: context.userId,
createdAt: new Date(),
messageContent: args.messageContent,
replyTo: args.replyTo,
});

// add createdGroupChatMessage to groupChat
Expand Down
2 changes: 2 additions & 0 deletions src/typeDefs/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,13 @@ export const mutations = gql`
sendMessageToDirectChat(
chatId: ID!
messageContent: String!
replyTo: ID
): DirectChatMessage! @auth

sendMessageToGroupChat(
chatId: ID!
messageContent: String!
replyTo: ID
): GroupChatMessage! @auth

signUp(data: UserInput!, file: String): AuthData!
Expand Down
2 changes: 2 additions & 0 deletions src/typeDefs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ export const types = gql`
directChatMessageBelongsTo: DirectChat!
sender: User!
receiver: User!
replyTo: DirectChatMessage
createdAt: DateTime!
updatedAt: DateTime!
messageContent: String!
Expand Down Expand Up @@ -385,6 +386,7 @@ export const types = gql`
_id: ID!
groupChatMessageBelongsTo: GroupChat!
sender: User!
replyTo: GroupChatMessage
createdAt: DateTime!
updatedAt: DateTime!
messageContent: String!
Expand Down
6 changes: 6 additions & 0 deletions src/types/generatedGraphQLTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ export type DirectChatMessage = {
directChatMessageBelongsTo: DirectChat;
messageContent: Scalars['String']['output'];
receiver: User;
replyTo?: Maybe<DirectChatMessage>;
sender: User;
updatedAt: Scalars['DateTime']['output'];
};
Expand Down Expand Up @@ -1012,6 +1013,7 @@ export type GroupChatMessage = {
createdAt: Scalars['DateTime']['output'];
groupChatMessageBelongsTo: GroupChat;
messageContent: Scalars['String']['output'];
replyTo?: Maybe<GroupChatMessage>;
sender: User;
updatedAt: Scalars['DateTime']['output'];
};
Expand Down Expand Up @@ -1751,12 +1753,14 @@ export type MutationSendMembershipRequestArgs = {
export type MutationSendMessageToDirectChatArgs = {
chatId: Scalars['ID']['input'];
messageContent: Scalars['String']['input'];
replyTo?: InputMaybe<Scalars['ID']['input']>;
};


export type MutationSendMessageToGroupChatArgs = {
chatId: Scalars['ID']['input'];
messageContent: Scalars['String']['input'];
replyTo?: InputMaybe<Scalars['ID']['input']>;
};


Expand Down Expand Up @@ -3952,6 +3956,7 @@ export type DirectChatMessageResolvers<ContextType = any, ParentType extends Res
directChatMessageBelongsTo?: Resolver<ResolversTypes['DirectChat'], ParentType, ContextType>;
messageContent?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
receiver?: Resolver<ResolversTypes['User'], ParentType, ContextType>;
replyTo?: Resolver<Maybe<ResolversTypes['DirectChatMessage']>, ParentType, ContextType>;
sender?: Resolver<ResolversTypes['User'], ParentType, ContextType>;
updatedAt?: Resolver<ResolversTypes['DateTime'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
Expand Down Expand Up @@ -4144,6 +4149,7 @@ export type GroupChatMessageResolvers<ContextType = any, ParentType extends Reso
createdAt?: Resolver<ResolversTypes['DateTime'], ParentType, ContextType>;
groupChatMessageBelongsTo?: Resolver<ResolversTypes['GroupChat'], ParentType, ContextType>;
messageContent?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
replyTo?: Resolver<Maybe<ResolversTypes['GroupChatMessage']>, ParentType, ContextType>;
sender?: Resolver<ResolversTypes['User'], ParentType, ContextType>;
updatedAt?: Resolver<ResolversTypes['DateTime'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
Expand Down
7 changes: 7 additions & 0 deletions tests/helpers/directChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import type { Document } from "mongoose";

export type TestDirectChatType =
| (InterfaceDirectChat & Document<any, any, InterfaceDirectChat>)

Check warning on line 12 in tests/helpers/directChat.ts

View workflow job for this annotation

GitHub Actions / Check for linting, formatting, and type errors

Unexpected any. Specify a different type

Check warning on line 12 in tests/helpers/directChat.ts

View workflow job for this annotation

GitHub Actions / Check for linting, formatting, and type errors

Unexpected any. Specify a different type
| null;

export type TestDirectChatMessageType =
Expand Down Expand Up @@ -45,11 +45,18 @@
const [testUser, testOrganization, testDirectChat] =
await createTestDirectChat();

const directChatMessage = await createDirectChatMessage(
testUser?._id,
testUser?._id,
testDirectChat?._id,
);

if (testDirectChat && testUser) {
const testDirectChatMessage = await DirectChatMessage.create({
directChatMessageBelongsTo: testDirectChat._id,
sender: testUser._id,
receiver: testUser._id,
replyTo: directChatMessage?._id,
messageContent: `msgContent${nanoid().toLowerCase()}`,
});
return [testUser, testOrganization, testDirectChat, testDirectChatMessage];
Expand Down
20 changes: 20 additions & 0 deletions tests/helpers/groupChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import type { Document } from "mongoose";

export type TestGroupChatType =
| (InterfaceGroupChat & Document<any, any, InterfaceGroupChat>)

Check warning on line 12 in tests/helpers/groupChat.ts

View workflow job for this annotation

GitHub Actions / Check for linting, formatting, and type errors

Unexpected any. Specify a different type

Check warning on line 12 in tests/helpers/groupChat.ts

View workflow job for this annotation

GitHub Actions / Check for linting, formatting, and type errors

Unexpected any. Specify a different type
| null;

export type TestGroupChatMessageType =
Expand Down Expand Up @@ -46,16 +46,36 @@
const [testUser, testOrganization, testGroupChat] =
await createTestGroupChat();

const message = await createGroupChatMessage(
testUser?._id,
testGroupChat?._id,
);
Comment on lines +49 to +52
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential null values for 'testUser' and 'testGroupChat' before using their IDs

The use of optional chaining testUser?._id and testGroupChat?._id suggests that testUser or testGroupChat might be null or undefined. Passing undefined to createGroupChatMessage could lead to unexpected behavior or errors. It's advisable to check if these variables are not null before proceeding.

Apply this diff to handle potential null values:

 const [testUser, testOrganization, testGroupChat] =
   await createTestGroupChat();

+ if (!testUser || !testGroupChat) {
+   // Handle the error or return appropriately
+   throw new Error('Failed to create test user or group chat');
+ }

 const message = await createGroupChatMessage(
   testUser._id,
   testGroupChat._id,
 );

Committable suggestion was skipped due to low confidence.


if (testGroupChat && testUser) {
const testGroupChatMessage = await GroupChatMessage.create({
groupChatMessageBelongsTo: testGroupChat._id,
sender: testUser._id,
createdAt: new Date(),
messageContent: `messageContent${nanoid().toLowerCase()}`,
replyTo: message?._id,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure 'message' is not null before setting 'replyTo'

Using message?._id implies that message might be null or undefined. If message is null, replyTo will be set to undefined, which may not be the intended behavior. Consider checking if message exists before assigning replyTo.

Apply this diff to check for a valid 'message':

 const testGroupChatMessage = await GroupChatMessage.create({
   groupChatMessageBelongsTo: testGroupChat._id,
   sender: testUser._id,
   createdAt: new Date(),
   messageContent: `messageContent${nanoid().toLowerCase()}`,
-  replyTo: message?._id,
+  replyTo: message ? message._id : undefined,
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
replyTo: message?._id,
replyTo: message ? message._id : undefined,

});

return [testUser, testOrganization, testGroupChat, testGroupChatMessage];
} else {
return [testUser, testOrganization, testGroupChat, null];
}
};

export const createGroupChatMessage = async (
senderId: string,
groupChatId: string,
): Promise<TestGroupChatMessageType> => {
const directChatMessage = await GroupChatMessage.create({
groupChatMessageBelongsTo: groupChatId,
sender: senderId,
createdAt: new Date(),
messageContent: `messageContent${nanoid().toLowerCase()}`,
});

return directChatMessage;
};
72 changes: 72 additions & 0 deletions tests/resolvers/DirectChatMessage/replyTo.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import "dotenv/config";
import { replyTo as replyToResolver } from "../../../src/resolvers/DirectChatMessage/replyTo";
import { connect, disconnect } from "../../helpers/db";
import type mongoose from "mongoose";
import { DirectChatMessage } from "../../../src/models";
import { beforeAll, afterAll, describe, it, expect, vi } from "vitest";
import type { TestDirectChatMessageType } from "../../helpers/directChat";
import { createTestDirectChatMessage } from "../../helpers/directChat";
import { Types } from "mongoose";
import { MESSAGE_NOT_FOUND_ERROR } from "../../../src/constants";

let testDirectChatMessage: TestDirectChatMessageType;
let MONGOOSE_INSTANCE: typeof mongoose;

beforeAll(async () => {
MONGOOSE_INSTANCE = await connect();
const temp = await createTestDirectChatMessage();
testDirectChatMessage = temp[3];
});

afterAll(async () => {
await disconnect(MONGOOSE_INSTANCE);
});

describe("resolvers -> DirectChatMessage -> directChatMessageBelongsTo", () => {
it(`returns directChat object for parent.directChatMessageBelongsTo`, async () => {
const parent = testDirectChatMessage?.toObject();

if (!parent) {
throw new Error("Parent object is undefined.");
}

if (typeof replyToResolver !== "function") {
throw new Error("replyToResolver is not a function.");
}

const replyToPayload = await replyToResolver(parent, {}, {});

const replyTo = await DirectChatMessage.findOne({
_id: testDirectChatMessage?.replyTo,
}).lean();

expect(replyToPayload).toEqual(replyTo);
});
it(`throws NotFoundError if no directChat exists`, async () => {
const { requestContext } = await import("../../../src/libraries");
const spy = vi
.spyOn(requestContext, "translate")
.mockImplementationOnce((message) => message);

const parent = {
...testDirectChatMessage?.toObject(),
replyTo: new Types.ObjectId(), // Set to a non-existing ObjectId
};

if (!parent) {
throw new Error("Parent object is undefined.");
}

if (typeof replyToResolver !== "function") {
throw new Error("replyToResolver is not a function.");
}

try {
// @ts-expect-error - Testing for error
await replyToResolver(parent, {}, {});
} catch (error: unknown) {
expect(spy).toBeCalledWith(MESSAGE_NOT_FOUND_ERROR.MESSAGE);
expect((error as Error).message).toEqual(MESSAGE_NOT_FOUND_ERROR.MESSAGE);
}
});
});
Loading
Loading