Skip to content

Commit

Permalink
chore: use updater in Livechat Contacts' updateContactChannel (#33980)
Browse files Browse the repository at this point in the history
  • Loading branch information
matheusbsilva137 authored Dec 17, 2024
1 parent f623260 commit e1bb39d
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 59 deletions.
2 changes: 1 addition & 1 deletion apps/meteor/app/livechat/server/lib/Helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const createLivechatRoom = async (
const source = extraRoomInfo.source || roomInfo.source;

if (settings.get<string>('Livechat_Require_Contact_Verification') === 'always') {
await LivechatContacts.updateContactChannel({ visitorId: _id, source }, { verified: false });
await LivechatContacts.setChannelVerifiedStatus({ visitorId: _id, source }, false);
}

const contactId = await migrateVisitorIfMissingContact(_id, source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Livechat } from '../../../../../../app/livechat/server/lib/LivechatType
import { i18n } from '../../../../../../server/lib/i18n';

export async function changeContactBlockStatus({ block, visitor }: { visitor: ILivechatContactVisitorAssociation; block: boolean }) {
const result = await LivechatContacts.updateContactChannel(visitor, { blocked: block });
const result = await LivechatContacts.setChannelBlockStatus(visitor, block);

if (!result.modifiedCount) {
throw new Error('error-contact-not-found');
Expand Down
18 changes: 4 additions & 14 deletions apps/meteor/ee/server/patches/verifyContactChannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,10 @@ async function _verifyContactChannel(
session.startTransaction();
logger.debug({ msg: 'Start verifying contact channel', contactId, visitorId, roomId });

await LivechatContacts.updateContactChannel(
{
visitorId,
source: room.source,
},
{
verified: true,
verifiedAt: new Date(),
field,
value: value.toLowerCase(),
},
{},
{ session },
);
const updater = LivechatContacts.getUpdater();
LivechatContacts.setVerifiedUpdateQuery(true, updater);
LivechatContacts.setFieldAndValueUpdateQuery(field, value.toLowerCase(), updater);
await LivechatContacts.updateFromUpdaterByAssociation({ visitorId, source: room.source }, updater, { session });

await LivechatRooms.update({ _id: roomId }, { $set: { verified: true } }, { session });
logger.debug({ msg: 'Merging contacts', contactId, visitorId, roomId });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import sinon from 'sinon';

const modelsMock = {
LivechatContacts: {
updateContactChannel: sinon.stub(),
getUpdater: sinon.stub(),
setVerifiedUpdateQuery: sinon.stub(),
setFieldAndValueUpdateQuery: sinon.stub(),
updateFromUpdaterByAssociation: sinon.stub(),
},
LivechatRooms: {
update: sinon.stub(),
Expand Down Expand Up @@ -44,7 +47,10 @@ const { runVerifyContactChannel } = proxyquire.noCallThru().load('../../../../..

describe('verifyContactChannel', () => {
beforeEach(() => {
modelsMock.LivechatContacts.updateContactChannel.reset();
modelsMock.LivechatContacts.getUpdater.reset();
modelsMock.LivechatContacts.setVerifiedUpdateQuery.reset();
modelsMock.LivechatContacts.setFieldAndValueUpdateQuery.reset();
modelsMock.LivechatContacts.updateFromUpdaterByAssociation.reset();
modelsMock.LivechatRooms.update.reset();
modelsMock.LivechatInquiry.findOneByRoomId.reset();
modelsMock.LivechatRooms.findOneById.reset();
Expand All @@ -55,6 +61,8 @@ describe('verifyContactChannel', () => {
mergeContactsStub.reset();
queueManager.processNewInquiry.reset();
queueManager.verifyInquiry.reset();

modelsMock.LivechatContacts.getUpdater.returns({});
});

afterEach(() => {
Expand All @@ -68,24 +76,23 @@ describe('verifyContactChannel', () => {
await runVerifyContactChannel(() => undefined, {
contactId: 'contactId',
field: 'field',
value: 'value',
value: 'Value',
visitorId: 'visitorId',
roomId: 'roomId',
});

expect(modelsMock.LivechatContacts.getUpdater.calledOnce).to.be.true;
expect(modelsMock.LivechatContacts.setVerifiedUpdateQuery.calledOnceWith(true, {})).to.be.true;
expect(modelsMock.LivechatContacts.setFieldAndValueUpdateQuery.calledOnceWith('field', 'value', {})).to.be.true;
expect(
modelsMock.LivechatContacts.updateContactChannel.calledOnceWith(
modelsMock.LivechatContacts.updateFromUpdaterByAssociation.calledOnceWith(
sinon.match({
visitorId: 'visitorId',
source: sinon.match({
type: 'sms',
}),
}),
sinon.match({
verified: true,
field: 'field',
value: 'value',
}),
{},
),
).to.be.true;
expect(modelsMock.LivechatRooms.update.calledOnceWith({ _id: 'roomId' }, { $set: { verified: true } })).to.be.true;
Expand Down Expand Up @@ -116,21 +123,21 @@ describe('verifyContactChannel', () => {
roomId: 'roomId',
});

expect(modelsMock.LivechatContacts.getUpdater.calledOnce).to.be.true;
expect(modelsMock.LivechatContacts.setVerifiedUpdateQuery.calledOnceWith(true, {})).to.be.true;
expect(modelsMock.LivechatContacts.setFieldAndValueUpdateQuery.calledOnceWith('field', 'value', {})).to.be.true;
expect(
modelsMock.LivechatContacts.updateContactChannel.calledOnceWith(
modelsMock.LivechatContacts.updateFromUpdaterByAssociation.calledOnceWith(
sinon.match({
visitorId: 'visitorId',
source: sinon.match({
type: 'sms',
}),
}),
sinon.match({
verified: true,
field: 'field',
value: 'value',
}),
{},
),
).to.be.true;

expect(modelsMock.LivechatRooms.update.calledOnceWith({ _id: 'roomId' }, { $set: { verified: true } })).to.be.true;
expect(
mergeContactsStub.calledOnceWith(
Expand Down Expand Up @@ -160,7 +167,11 @@ describe('verifyContactChannel', () => {
}),
).to.be.rejectedWith('error-invalid-room');

expect(modelsMock.LivechatContacts.updateContactChannel.notCalled).to.be.true;
expect(modelsMock.LivechatContacts.getUpdater.notCalled).to.be.true;
expect(modelsMock.LivechatContacts.setVerifiedUpdateQuery.notCalled).to.be.true;
expect(modelsMock.LivechatContacts.setFieldAndValueUpdateQuery.notCalled).to.be.true;
expect(modelsMock.LivechatContacts.updateFromUpdaterByAssociation.notCalled).to.be.true;

expect(modelsMock.LivechatRooms.update.notCalled).to.be.true;
expect(mergeContactsStub.notCalled).to.be.true;
expect(queueManager.verifyInquiry.notCalled).to.be.true;
Expand All @@ -180,21 +191,21 @@ describe('verifyContactChannel', () => {
}),
).to.be.rejectedWith('error-invalid-inquiry');

expect(modelsMock.LivechatContacts.getUpdater.calledOnce).to.be.true;
expect(modelsMock.LivechatContacts.setVerifiedUpdateQuery.calledOnceWith(true, {})).to.be.true;
expect(modelsMock.LivechatContacts.setFieldAndValueUpdateQuery.calledOnceWith('field', 'value', {})).to.be.true;
expect(
modelsMock.LivechatContacts.updateContactChannel.calledOnceWith(
modelsMock.LivechatContacts.updateFromUpdaterByAssociation.calledOnceWith(
sinon.match({
visitorId: 'visitorId',
source: sinon.match({
type: 'sms',
}),
}),
sinon.match({
verified: true,
field: 'field',
value: 'value',
}),
{},
),
).to.be.true;

expect(modelsMock.LivechatRooms.update.calledOnceWith({ _id: 'roomId' }, { $set: { verified: true } })).to.be.true;
expect(
mergeContactsStub.calledOnceWith(
Expand Down
4 changes: 2 additions & 2 deletions apps/meteor/server/models/raw/BaseRaw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ export abstract class BaseRaw<
return new UpdaterImpl<T>();
}

public updateFromUpdater(query: Filter<T>, updater: Updater<T>): Promise<UpdateResult> {
public updateFromUpdater(query: Filter<T>, updater: Updater<T>, options: UpdateOptions = {}): Promise<UpdateResult> {
const updateFilter = updater.getUpdateFilter();
return this.updateOne(query, updateFilter).catch((e) => {
return this.updateOne(query, updateFilter, options).catch((e) => {
console.warn(e, updateFilter);
return Promise.reject(e);
});
Expand Down
45 changes: 29 additions & 16 deletions apps/meteor/server/models/raw/LivechatContacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {
ILivechatVisitor,
RocketChatRecordDeleted,
} from '@rocket.chat/core-typings';
import type { FindPaginated, ILivechatContactsModel, InsertionModel } from '@rocket.chat/model-typings';
import type { FindPaginated, ILivechatContactsModel, InsertionModel, Updater } from '@rocket.chat/model-typings';
import { escapeRegExp } from '@rocket.chat/string-helpers';
import type {
Document,
Expand Down Expand Up @@ -198,24 +198,37 @@ export class LivechatContactsRaw extends BaseRaw<ILivechatContact> implements IL
return Boolean(await this.findOne(this.makeQueryForVisitor(visitor, { blocked: true }), { projection: { _id: 1 } }));
}

async updateContactChannel(
setChannelBlockStatus(visitor: ILivechatContactVisitorAssociation, blocked: boolean): Promise<UpdateResult> {
return this.updateOne(this.makeQueryForVisitor(visitor), { $set: { 'channels.$.blocked': blocked } });
}

setChannelVerifiedStatus(visitor: ILivechatContactVisitorAssociation, verified: boolean): Promise<UpdateResult> {
return this.updateOne(this.makeQueryForVisitor(visitor), {
$set: {
'channels.$.verified': verified,
...(verified && { 'channels.$.verifiedAt': new Date() }),
},
});
}

setVerifiedUpdateQuery(verified: boolean, contactUpdater: Updater<ILivechatContact>): Updater<ILivechatContact> {
if (verified) {
contactUpdater.set('channels.$.verifiedAt', new Date());
}
return contactUpdater.set('channels.$.verified', verified);
}

setFieldAndValueUpdateQuery(field: string, value: string, contactUpdater: Updater<ILivechatContact>): Updater<ILivechatContact> {
contactUpdater.set('channels.$.field', field);
return contactUpdater.set('channels.$.value', value);
}

updateFromUpdaterByAssociation(
visitor: ILivechatContactVisitorAssociation,
data: Partial<ILivechatContactChannel>,
contactData?: Partial<Omit<ILivechatContact, 'channels'>>,
contactUpdater: Updater<ILivechatContact>,
options: UpdateOptions = {},
): Promise<UpdateResult> {
return this.updateOne(
this.makeQueryForVisitor(visitor),
{
$set: {
...contactData,
...(Object.fromEntries(
Object.keys(data).map((key) => [`channels.$.${key}`, data[key as keyof ILivechatContactChannel]]),
) as UpdateFilter<ILivechatContact>['$set']),
},
},
options,
);
return this.updateFromUpdater(this.makeQueryForVisitor(visitor), contactUpdater, options);
}

async findSimilarVerifiedContacts(
Expand Down
10 changes: 7 additions & 3 deletions packages/model-typings/src/models/ILivechatContactsModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
} from '@rocket.chat/core-typings';
import type { Document, FindCursor, FindOneAndUpdateOptions, FindOptions, UpdateFilter, UpdateOptions, UpdateResult } from 'mongodb';

import type { Updater } from '../updater';
import type { FindPaginated, IBaseModel, InsertionModel } from './IBaseModel';

export interface ILivechatContactsModel extends IBaseModel<ILivechatContact> {
Expand All @@ -31,10 +32,9 @@ export interface ILivechatContactsModel extends IBaseModel<ILivechatContact> {
options?: FindOptions<ILivechatContact>,
): Promise<T | null>;
isChannelBlocked(visitor: ILivechatContactVisitorAssociation): Promise<boolean>;
updateContactChannel(
updateFromUpdaterByAssociation(
visitor: ILivechatContactVisitorAssociation,
data: Partial<ILivechatContactChannel>,
contactData?: Partial<Omit<ILivechatContact, 'channels'>>,
contactUpdater: Updater<ILivechatContact>,
options?: UpdateOptions,
): Promise<UpdateResult>;
findSimilarVerifiedContacts(
Expand All @@ -44,4 +44,8 @@ export interface ILivechatContactsModel extends IBaseModel<ILivechatContact> {
): Promise<ILivechatContact[]>;
findAllByVisitorId(visitorId: string): FindCursor<ILivechatContact>;
addEmail(contactId: string, email: string): Promise<ILivechatContact | null>;
setChannelBlockStatus(visitor: ILivechatContactVisitorAssociation, blocked: boolean): Promise<UpdateResult>;
setChannelVerifiedStatus(visitor: ILivechatContactVisitorAssociation, verified: boolean): Promise<UpdateResult>;
setVerifiedUpdateQuery(verified: boolean, contactUpdater: Updater<ILivechatContact>): Updater<ILivechatContact>;
setFieldAndValueUpdateQuery(field: string, value: string, contactUpdater: Updater<ILivechatContact>): Updater<ILivechatContact>;
}

0 comments on commit e1bb39d

Please sign in to comment.