From 7f73f66af4285c86ceacc1cde621a1fa644a1c09 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 4 Mar 2024 09:43:52 -0600 Subject: [PATCH 01/10] Fix Multiple BH making bots not available on opening --- apps/meteor/server/models/raw/Users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/server/models/raw/Users.js b/apps/meteor/server/models/raw/Users.js index 0d56fc76bccf8..37c76436b5ce8 100644 --- a/apps/meteor/server/models/raw/Users.js +++ b/apps/meteor/server/models/raw/Users.js @@ -1036,7 +1036,7 @@ export class UsersRaw extends BaseRaw { updateLivechatStatusBasedOnBusinessHours(userIds = []) { const query = { $or: [{ openBusinessHours: { $exists: false } }, { openBusinessHours: { $size: 0 } }], - roles: 'livechat-agent', + $and: [{ roles: 'livechat-agent' }, { roles: { $ne: 'bot' } }], // exclude deactivated users active: true, // Avoid unnecessary updates From 7f9c5cf67cb1d006a8006d8e88a0e2bc9cc66f69 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 4 Mar 2024 09:45:27 -0600 Subject: [PATCH 02/10] Create brown-houses-rush.md --- .changeset/brown-houses-rush.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/brown-houses-rush.md diff --git a/.changeset/brown-houses-rush.md b/.changeset/brown-houses-rush.md new file mode 100644 index 0000000000000..7a742611262f2 --- /dev/null +++ b/.changeset/brown-houses-rush.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fix: Multiple type of BH making bots not available on opening From ae30b5569c9e8004b8504b21bd84f35c735f0d8d Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Wed, 6 Mar 2024 11:55:19 -0600 Subject: [PATCH 03/10] Update brown-houses-rush.md --- .changeset/brown-houses-rush.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/brown-houses-rush.md b/.changeset/brown-houses-rush.md index 7a742611262f2..67fcb02f95e42 100644 --- a/.changeset/brown-houses-rush.md +++ b/.changeset/brown-houses-rush.md @@ -2,4 +2,4 @@ "@rocket.chat/meteor": patch --- -Fix: Multiple type of BH making bots not available on opening +Fixed a problem that caused Business Hours feature (Multiple) to make bot agents not available when turning on the feature, and not making them available after that. Now, Business Hours will ignore Bot users, allowing admins to decide manually if a bot should be or not be active during a period of time From bae49ee90f9e671bfa93d79fd35158cf4546018b Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 11 Mar 2024 09:28:18 -0600 Subject: [PATCH 04/10] tests --- .../end-to-end/api/livechat/19-business-hours.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts index b6527fbc2bb24..63f5bae9636dc 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts @@ -793,6 +793,20 @@ describe('LIVECHAT - business hours', function () { await deleteUser(newUser); }); + it('should add a bot agent but shouldn change its status', async () => { + const bot = await createUser({ roles: ['bot', 'livechat-agent'] }); + const newUserCredentials = await login(bot.username, password); + await setUserActiveStatus(bot._id, true); + + const latestAgent: ILivechatAgent = await getMe(newUserCredentials); + expect(latestAgent).to.be.an('object'); + expect(latestAgent.openBusinessHours).to.be.undefined; + expect(latestAgent.statusLivechat).to.be.equal(ILivechatAgentStatus.AVAILABLE); + + // cleanup + await deleteUser(bot); + }); + it('should verify if agent is assigned to BH when it is opened', async () => { // first verify if agent is not assigned to any BH let latestAgent: ILivechatAgent = await getMe(agentCredentials as any); From 8823f5591e22d52d41a9439b6ef4e2265380d795 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 11 Mar 2024 10:16:56 -0600 Subject: [PATCH 05/10] should work --- .../end-to-end/api/livechat/19-business-hours.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts index 63f5bae9636dc..ba8ff99a44c33 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts @@ -796,7 +796,14 @@ describe('LIVECHAT - business hours', function () { it('should add a bot agent but shouldn change its status', async () => { const bot = await createUser({ roles: ['bot', 'livechat-agent'] }); const newUserCredentials = await login(bot.username, password); - await setUserActiveStatus(bot._id, true); + await request + .post(api('livechat/agent.status')) + .set(credentials) + .send({ + status: 'available', + agentId: bot._id, + }) + .expect(200); const latestAgent: ILivechatAgent = await getMe(newUserCredentials); expect(latestAgent).to.be.an('object'); @@ -886,8 +893,8 @@ describe('LIVECHAT - business hours', function () { it('should verify if agent becomes unavailable to take chats when user is activated, if business hour is inactive', async () => { await openOrCloseBusinessHour(defaultBH, false); - await setUserActiveStatus(agent._id, false); await setUserActiveStatus(agent._id, true); + await setUserActiveStatus(agent._id, false); const latestAgent = await getUserByUsername(agent.username); From 9f20e0b97a33b975c89beb7f0b76939ab0a3b7c3 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 11 Mar 2024 12:41:41 -0600 Subject: [PATCH 06/10] should work --- apps/meteor/tests/data/livechat/department.ts | 20 ++++++++--- .../api/livechat/19-business-hours.ts | 36 ++++++++----------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/apps/meteor/tests/data/livechat/department.ts b/apps/meteor/tests/data/livechat/department.ts index 8aba28addfcf7..6c19ca231d641 100644 --- a/apps/meteor/tests/data/livechat/department.ts +++ b/apps/meteor/tests/data/livechat/department.ts @@ -57,11 +57,23 @@ new Promise((resolve, reject) => { }); }); -export const createDepartmentWithAnOnlineAgent = async (): Promise<{department: ILivechatDepartment, agent: { - credentials: IUserCredentialsHeader; +type OnlineAgent = { user: WithRequiredProperty; -}}> => { - const { user, credentials } = await createAnOnlineAgent(); + credentials: IUserCredentialsHeader; +}; + +export const createDepartmentWithAnOnlineAgent = async (overrideUser?: OnlineAgent): Promise<{department: ILivechatDepartment, agent: OnlineAgent }> => { + let user: OnlineAgent['user']; + let credentials: OnlineAgent['credentials']; + + if (!overrideUser) { + const agent = await createAnOnlineAgent(); + user = agent.user; + credentials = agent.credentials; + } else { + user = overrideUser.user; + credentials = overrideUser.credentials; + } const department = await createDepartmentWithMethod() as ILivechatDepartment; diff --git a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts index ba8ff99a44c33..44962ae531cb2 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts @@ -321,6 +321,21 @@ describe('LIVECHAT - business hours', function () { expect(latestAgent.openBusinessHours).to.be.an('array').of.length(0); expect(latestAgent.statusLivechat).to.be.equal(ILivechatAgentStatus.NOT_AVAILABLE); }); + + it('should create a custom business hour which is closed by default, but a bot agent shouldnt be affected', async () => { + const bot = await createUser({ roles: ['bot', 'livechat-agent'] }); + const creds = await login(bot.username, password); + await makeAgentAvailable(creds); + + const { department } = await createDepartmentWithAnOnlineAgent({ user: bot, credentials: creds }); + + await createCustomBusinessHour([department._id], false); + + const latestAgent: ILivechatAgent = await getMe(creds); + expect(latestAgent).to.be.an('object'); + expect(latestAgent.openBusinessHours).to.be.an('array').of.length(0); + expect(latestAgent.statusLivechat).to.be.equal(ILivechatAgentStatus.AVAILABLE); + }); }); // Scenario: Assume we have a BH linked to a department, and we archive the department @@ -793,27 +808,6 @@ describe('LIVECHAT - business hours', function () { await deleteUser(newUser); }); - it('should add a bot agent but shouldn change its status', async () => { - const bot = await createUser({ roles: ['bot', 'livechat-agent'] }); - const newUserCredentials = await login(bot.username, password); - await request - .post(api('livechat/agent.status')) - .set(credentials) - .send({ - status: 'available', - agentId: bot._id, - }) - .expect(200); - - const latestAgent: ILivechatAgent = await getMe(newUserCredentials); - expect(latestAgent).to.be.an('object'); - expect(latestAgent.openBusinessHours).to.be.undefined; - expect(latestAgent.statusLivechat).to.be.equal(ILivechatAgentStatus.AVAILABLE); - - // cleanup - await deleteUser(bot); - }); - it('should verify if agent is assigned to BH when it is opened', async () => { // first verify if agent is not assigned to any BH let latestAgent: ILivechatAgent = await getMe(agentCredentials as any); From 114867762dd6f17510b6e4c2e59ceaecf72946b0 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 11 Mar 2024 14:08:01 -0600 Subject: [PATCH 07/10] should work --- apps/meteor/server/models/raw/Users.js | 16 ++++++++++++---- .../end-to-end/api/livechat/19-business-hours.ts | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/meteor/server/models/raw/Users.js b/apps/meteor/server/models/raw/Users.js index 37c76436b5ce8..a4b7bfe9a397a 100644 --- a/apps/meteor/server/models/raw/Users.js +++ b/apps/meteor/server/models/raw/Users.js @@ -1075,10 +1075,18 @@ export class UsersRaw extends BaseRaw { async isAgentWithinBusinessHours(agentId) { const query = { _id: agentId, - openBusinessHours: { - $exists: true, - $not: { $size: 0 }, - }, + $or: [ + { + openBusinessHours: { + $exists: true, + $not: { $size: 0 }, + }, + }, + { + // Bots can ignore Business Hours and be always available + roles: 'bot', + }, + ], }; return (await this.col.countDocuments(query)) > 0; } diff --git a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts index 44962ae531cb2..efcf9dc877aa1 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts @@ -308,7 +308,7 @@ describe('LIVECHAT - business hours', function () { defaultBusinessHour = await getDefaultBusinessHour(); // close default business hour - await openOrCloseBusinessHour(defaultBusinessHour, true); + await openOrCloseBusinessHour(defaultBusinessHour, false); }); it('should create a custom business hour which is closed by default', async () => { From c6efdbae4f35f8f4ab515ab632d5d531e7f8910d Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 12 Mar 2024 07:20:06 -0600 Subject: [PATCH 08/10] Update apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts --- apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts index efcf9dc877aa1..44962ae531cb2 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts @@ -308,7 +308,7 @@ describe('LIVECHAT - business hours', function () { defaultBusinessHour = await getDefaultBusinessHour(); // close default business hour - await openOrCloseBusinessHour(defaultBusinessHour, false); + await openOrCloseBusinessHour(defaultBusinessHour, true); }); it('should create a custom business hour which is closed by default', async () => { From d7db2466ce71380c612ab5360d73ddea20370bab Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 12 Mar 2024 13:23:52 -0600 Subject: [PATCH 09/10] Update apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts --- apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts index 44962ae531cb2..01f04c65984b3 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts @@ -887,8 +887,8 @@ describe('LIVECHAT - business hours', function () { it('should verify if agent becomes unavailable to take chats when user is activated, if business hour is inactive', async () => { await openOrCloseBusinessHour(defaultBH, false); - await setUserActiveStatus(agent._id, true); await setUserActiveStatus(agent._id, false); + await setUserActiveStatus(agent._id, true); const latestAgent = await getUserByUsername(agent.username); From 5dd2d163a2407993b8f5f4f6a1434f469e6586e2 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 12 Mar 2024 13:41:14 -0600 Subject: [PATCH 10/10] wth --- apps/meteor/tests/data/livechat/department.ts | 31 +++++++++++-------- .../api/livechat/19-business-hours.ts | 3 +- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/meteor/tests/data/livechat/department.ts b/apps/meteor/tests/data/livechat/department.ts index 6c19ca231d641..3d18f9c394b99 100644 --- a/apps/meteor/tests/data/livechat/department.ts +++ b/apps/meteor/tests/data/livechat/department.ts @@ -62,22 +62,12 @@ type OnlineAgent = { credentials: IUserCredentialsHeader; }; -export const createDepartmentWithAnOnlineAgent = async (overrideUser?: OnlineAgent): Promise<{department: ILivechatDepartment, agent: OnlineAgent }> => { - let user: OnlineAgent['user']; - let credentials: OnlineAgent['credentials']; - - if (!overrideUser) { - const agent = await createAnOnlineAgent(); - user = agent.user; - credentials = agent.credentials; - } else { - user = overrideUser.user; - credentials = overrideUser.credentials; - } +export const createDepartmentWithAnOnlineAgent = async (): Promise<{department: ILivechatDepartment, agent: OnlineAgent }> => { + const { user, credentials } = await createAnOnlineAgent(); const department = await createDepartmentWithMethod() as ILivechatDepartment; - await addOrRemoveAgentFromDepartment(department._id, {agentId: user._id, username: user.username}, true); + await addOrRemoveAgentFromDepartment(department._id, { agentId: user._id, username: user.username }, true); return { department, @@ -88,6 +78,21 @@ export const createDepartmentWithAnOnlineAgent = async (overrideUser?: OnlineAge }; }; +export const createDepartmentWithAgent = async (agent: OnlineAgent): Promise<{ department: ILivechatDepartment; agent: OnlineAgent }> => { + const { user, credentials } = agent; + const department = await createDepartmentWithMethod() as ILivechatDepartment; + + await addOrRemoveAgentFromDepartment(department._id, { agentId: user._id, username: user.username }, true); + + return { + department, + agent: { + credentials, + user, + } + }; +} + export const addOrRemoveAgentFromDepartment = async (departmentId: string, agent: { agentId: string; username: string; count?: number; order?: number }, add: boolean) => { const response = await request.post(api('livechat/department/' + departmentId + '/agents')).set(credentials).send({ ...add ? { upsert: [agent], remove: [] } : { remove: [agent], upsert: [] }, diff --git a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts index 01f04c65984b3..8b6dc224377f9 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts @@ -18,6 +18,7 @@ import { addOrRemoveAgentFromDepartment, archiveDepartment, createDepartmentWithAnOnlineAgent, + createDepartmentWithAgent, disableDepartment, getDepartmentById, deleteDepartment, @@ -327,7 +328,7 @@ describe('LIVECHAT - business hours', function () { const creds = await login(bot.username, password); await makeAgentAvailable(creds); - const { department } = await createDepartmentWithAnOnlineAgent({ user: bot, credentials: creds }); + const { department } = await createDepartmentWithAgent({ user: bot, credentials: creds }); await createCustomBusinessHour([department._id], false);