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

feat: Single Contact Identification #32727

Merged
merged 207 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
207 commits
Select commit Hold shift + click to select a range
e0a350c
feat: Current Chats deprecation warning (#32675)
dougfabris Jul 2, 2024
c67fdd5
Merge branch 'develop' into feat/single-contact-id
dougfabris Jul 3, 2024
9f7654f
feat: improve contact center routing (#32718)
dougfabris Jul 4, 2024
40c9162
feat: New contact details tab (#32725)
dougfabris Jul 10, 2024
9bc0675
Merge branch 'develop' into feat/single-contact-id
dougfabris Jul 18, 2024
9397779
feat: Displays chat history on chats contextual bar (#32845)
dougfabris Jul 24, 2024
81c9ea0
feat: Add contact identification settings (#32893)
Gustrb Jul 25, 2024
56c685c
Merge branch 'develop' into feat/single-contact-id
dougfabris Aug 20, 2024
d667dee
feat: Omnichannel's security and privacy settings page (#32988)
dougfabris Aug 21, 2024
115b19c
Merge branch 'develop' into feat/single-contact-id
dougfabris Aug 28, 2024
8bdc3ae
chore: remove duplicated translation key
dougfabris Aug 23, 2024
2d84795
chore: Adds reactivity to contact history message list (#33505)
dougfabris Oct 9, 2024
f294348
Merge branch 'develop' into feat/single-contact-id
dougfabris Oct 15, 2024
61c8cec
feat: Omnichannel directory chats filters (#33016)
dougfabris Oct 14, 2024
094b155
chore: Get livechat rooms rooms properly on chats table (#33568)
dougfabris Oct 14, 2024
047b31d
feat: Add support for Omnichannel Contacts on the Importer system (#3…
pierre-lehnen-rc Oct 15, 2024
f74d578
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Oct 15, 2024
1025723
feat(sci): on demand migration of Visitors to Contacts (#33594)
pierre-lehnen-rc Oct 16, 2024
febf7d2
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Oct 15, 2024
9ea30e1
feat: get contact by phone or email (#33595)
tapiarafael Oct 15, 2024
761c2a6
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Oct 15, 2024
26d878e
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Oct 16, 2024
865f3bb
fix: contacts.get endpoint returning a successful response even if th…
pierre-lehnen-rc Oct 16, 2024
91381b3
feat: Search, create and edit contacts (#33591)
dougfabris Oct 16, 2024
2d0958a
feat: last chat on channels (#33608)
tapiarafael Oct 16, 2024
c0c7966
chore: add license to LicenseModule list
Gustrb Oct 16, 2024
a69fa44
Merge pull request #33613 from RocketChat/chore/add-single-contact-li…
tapiarafael Oct 16, 2024
64bc5e6
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Oct 16, 2024
47bafeb
chore: fix CI tests (#33617)
pierre-lehnen-rc Oct 16, 2024
dcda853
chore: enable single contact id (#33610)
tapiarafael Oct 17, 2024
7616660
Merge remote-tracking branch 'origin/develop' into feat/single-contac…
dougfabris Oct 17, 2024
8ef5eee
chore: contact history fields (#33618)
tapiarafael Oct 17, 2024
8e83b07
Merge branch 'develop' into feat/single-contact-id
tapiarafael Oct 17, 2024
bdaf64f
feat: Contacts verification and merging (#33491)
tapiarafael Oct 17, 2024
b923f2d
feat: Contact channels and history tab (#32595)
dougfabris Oct 17, 2024
e8444c0
Merge branch 'develop' into feat/single-contact-id
tapiarafael Oct 18, 2024
b47fb3c
feat: block contact channel (#33590)
tapiarafael Oct 18, 2024
5ec7af1
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Oct 18, 2024
10e0d3c
chore: fix failing CI tests (#33637)
pierre-lehnen-rc Oct 18, 2024
c03d221
feat: contact importer data conversion (#33597)
pierre-lehnen-rc Oct 18, 2024
90a7e92
feat: use Single contact Id settings in routing manager (#33490)
Gustrb Oct 18, 2024
89ddf51
feat: add property to erase conflicts (#33638)
tapiarafael Oct 18, 2024
cc6e628
feat: add contact bridge (#33500)
Gustrb Oct 18, 2024
956f3a5
feat: Omnichannel contact verification status (#33550)
dougfabris Oct 18, 2024
3c62701
chore: remove unused property (#33641)
tapiarafael Oct 18, 2024
0b78e2d
chore: enable contact importer only after enabling the SCI feature (#…
pierre-lehnen-rc Oct 18, 2024
69323f6
feat: Omnichannel block channels (#33642)
dougfabris Oct 18, 2024
3a421db
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Oct 18, 2024
3cbd505
test: mock imports
tapiarafael Oct 18, 2024
95c47f2
Merge branch 'develop' into feat/single-contact-id
tapiarafael Oct 18, 2024
0fa8991
chore: fix lint
matheusbsilva137 Oct 18, 2024
ca59012
feat: create SCI settings regardless of license status (#33658)
pierre-lehnen-rc Oct 18, 2024
3eb5a1d
fix: Missing new settings description (#33660)
dougfabris Oct 18, 2024
f9647c4
chore: Render new security settings even not being EE (#33662)
dougfabris Oct 18, 2024
9ae2742
fix: typeerror (#33655)
Gustrb Oct 18, 2024
504e084
Merge branch 'develop' into feat/single-contact-id
dougfabris Oct 18, 2024
c87748d
fix: imported contacts being flagged as unknown (#33663)
pierre-lehnen-rc Oct 18, 2024
3505c76
feat: Add block action in unknown contact callout (#33659)
dougfabris Oct 18, 2024
bb2a324
fix: Contact email and phone validation not working properly (#33653)
dougfabris Oct 18, 2024
e6b4f09
fix: contact history type
tapiarafael Oct 18, 2024
193b3aa
chore: change method call to get by visitor (#33664)
Gustrb Oct 18, 2024
855da16
chore: Missing text truncation in contact info (#33669)
dougfabris Oct 18, 2024
894ba41
chore: Missing history item verified icon (#33667)
dougfabris Oct 18, 2024
64d3dd3
feat: Omnichannel contacts conflicts (#33640)
dougfabris Oct 18, 2024
bdb7d54
chore: merge changesets
dougfabris Oct 18, 2024
60ae975
Update apps/meteor/app/importer/server/classes/converters/ConverterCa…
pierre-lehnen-rc Oct 18, 2024
00c1c96
chore: set to verified false the contact when picking the conversatio…
Gustrb Oct 18, 2024
485ded3
Update apps/meteor/app/livechat/server/lib/RoutingManager.ts
pierre-lehnen-rc Oct 18, 2024
37573c0
Update apps/meteor/ee/server/patches/mergeContacts.ts
pierre-lehnen-rc Oct 18, 2024
2944724
Merge branch 'develop' into feat/single-contact-id
dougfabris Oct 18, 2024
6629729
fix: remove appId from visitor search (#33654)
tapiarafael Oct 18, 2024
62e616d
chore: `usePagination` in PrepareContacts
dougfabris Oct 18, 2024
b511b7c
chore: change default value for verification (#33668)
tapiarafael Oct 18, 2024
e1705f4
Merge develop into feat/single-contact-id
pierre-lehnen-rc Oct 18, 2024
8ccf59a
chore: remove old `ContactHistory`
dougfabris Oct 18, 2024
4ec7937
fix: review
dougfabris Oct 18, 2024
1325fe1
fix: when updating a visitor information, the updated data is not ref…
pierre-lehnen-rc Oct 18, 2024
9948a57
feat: migrate visitor data when any of their rooms is read (#33661)
pierre-lehnen-rc Oct 18, 2024
99b6e5e
apply changes requested
matheusbsilva137 Oct 18, 2024
6f4f196
remove limit from findOne
matheusbsilva137 Oct 18, 2024
0c5b628
Merge branch 'develop' into feat/single-contact-id
dougfabris Oct 18, 2024
c5cf996
apply more omnichannel requested changes
matheusbsilva137 Oct 18, 2024
19e7166
fix unit tests
matheusbsilva137 Oct 18, 2024
01b5db6
test: fix unblock tests (#33644)
tapiarafael Oct 18, 2024
5dffaf7
chore: missing verification icon tooltip
dougfabris Oct 18, 2024
dbc7363
feat: improve SCI settings clarity (#33672)
pierre-lehnen-rc Oct 18, 2024
7f4ec12
chore: update block state in `ComposerOmnichannelCallout`
dougfabris Oct 18, 2024
0ae0f31
remove outdated translations
matheusbsilva137 Oct 18, 2024
8f66997
change new setting value on existing EE tests to match old behavior
pierre-lehnen-rc Oct 21, 2024
c2ca48f
Merge remote-tracking branch 'origin' into feat/single-contact-id
dougfabris Oct 21, 2024
885db1d
test: fix omnichannel-chat-history
dougfabris Oct 21, 2024
441f14e
test: ignore require contact verification
dougfabris Oct 22, 2024
9bf6089
fix merge of array fields
pierre-lehnen-rc Oct 22, 2024
e285a43
chore: split Contacts.ts file and its tests into separate files for e…
pierre-lehnen-rc Oct 22, 2024
7b61b49
chore: settings revision (#33703)
Gustrb Oct 22, 2024
593ad15
Merge remote-tracking branch 'origin/develop' into feat/single-contac…
dougfabris Oct 22, 2024
1e443d1
fix: undefined error message (#33702)
Gustrb Oct 23, 2024
9c76b28
Merge branch 'develop' into feat/single-contact-id
matheusbsilva137 Oct 23, 2024
10d4117
fix: Clear filters button not being active after submit (#33699)
dougfabris Oct 23, 2024
80bdb6a
fix: Tag's `Chip` not being displayed correctly (#33731)
dougfabris Oct 24, 2024
6627076
Merge branch 'develop' into feat/single-contact-id
dougfabris Oct 24, 2024
3fb0dd9
feat(sci): Restrict livechat visitors to their source type scope (#33…
matheusbsilva137 Oct 18, 2024
a7b5b31
fix: `ContactHistoryMessagesList` calling endpoint exhaustively (#33761)
dougfabris Oct 24, 2024
041c7aa
chore: Move focus to text input when removing filter (#33762)
dougfabris Oct 24, 2024
efbb0cb
fix: return only closed chats on history (#33763)
tapiarafael Oct 24, 2024
756b005
fix: Add multiple fields validation (#33771)
dougfabris Oct 24, 2024
5af9581
chore: Missing closing chat message (#33775)
dougfabris Oct 25, 2024
5c57717
chore: query not being debounced in contact info history
dougfabris Oct 28, 2024
8f19747
fix: contact not merging for same email (#33811)
tapiarafael Oct 28, 2024
5af4368
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Oct 29, 2024
dd0e9ff
issues with last merge
pierre-lehnen-rc Oct 29, 2024
f63bd0b
new lint rules
pierre-lehnen-rc Oct 29, 2024
bff5623
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Oct 29, 2024
dce6d3d
chore: `useOmnichannelSourceName`
dougfabris Oct 30, 2024
bd8e04c
fix: normalize `ContactInfoChannelsItem` [SCI-115]
dougfabris Oct 30, 2024
9fe70a5
fix: normalize `ContactInfoHistoryItem` [SCI-138]
dougfabris Oct 30, 2024
8da99de
fix: display only available source types in history filter [SCI-131]
dougfabris Oct 30, 2024
0300995
chore: missing history filter validation for CE [SCI-131]
dougfabris Oct 30, 2024
13582cd
feat: remove visitor source restrictions (#33824)
pierre-lehnen-rc Oct 31, 2024
5ba43bd
fix: contact channels not being migrated (#33845)
tapiarafael Oct 31, 2024
869db19
Merge branch 'develop' into feat/single-contact-id
dougfabris Oct 31, 2024
3f55e4d
Merge branch 'develop' into feat/single-contact-id
tapiarafael Oct 31, 2024
ab38198
fix: verify badge in header condition [SCI-124]
dougfabris Oct 31, 2024
0de31c1
fix: update contacts rooms (#33859)
tapiarafael Oct 31, 2024
27dd0c3
Merge branch 'develop' into feat/single-contact-id
tapiarafael Nov 1, 2024
f64b75f
feat: add channels and verified column in chats table [SCI-139]
dougfabris Nov 1, 2024
ed753b7
chore: change contact info icon [SCI-148]
dougfabris Nov 1, 2024
8999e31
feat: filter unknown contacts (#33860)
tapiarafael Nov 4, 2024
85dc32b
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Nov 4, 2024
6c2ae1e
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Nov 4, 2024
0afc107
chore: add pt-BR translations [SCI-127]
dougfabris Nov 4, 2024
24f1e0b
chore: disable history filter when no history results
dougfabris Nov 4, 2024
96aed2f
chore: use secondary button in `Callout` block action
dougfabris Nov 4, 2024
b9fdcac
feat: add new contact channels endpoint (#33867)
tapiarafael Nov 4, 2024
f44fdd3
fix: sort history by closed date
tapiarafael Nov 4, 2024
01a0f63
Merge branch 'develop' into feat/single-contact-id
tapiarafael Nov 4, 2024
0cfd567
chore: history filter label issue
dougfabris Nov 4, 2024
0c281a5
chore: get contact channels from new endpoint [SCI-142]
dougfabris Nov 4, 2024
33f955c
fix: dont update the unknown status (#33886)
tapiarafael Nov 5, 2024
7f46d97
fix: Invalid association between visitors and contacts. (#33868)
pierre-lehnen-rc Nov 5, 2024
5620f93
return manager information on contacts.search
pierre-lehnen-rc Nov 6, 2024
0668978
fix: apps-engine room converter dropping contactId attribute (#33894)
dougfabris Nov 6, 2024
0977ef1
eslint
pierre-lehnen-rc Nov 6, 2024
51a0f12
chore: add last channel column in contacts table [SCI-130]
dougfabris Nov 6, 2024
d20732a
chore: `OmnichannelVerificationTag` margin
dougfabris Nov 6, 2024
082908b
fix: omnichannel directory tables loading state
dougfabris Nov 6, 2024
118232e
feat: use contact's name on as omnichannel rooms' display name (#33893)
pierre-lehnen-rc Nov 6, 2024
2cc9eef
removed old changeset
pierre-lehnen-rc Nov 7, 2024
9ec14fd
chore: avoid refactor in `RemoveChatButton`
dougfabris Nov 7, 2024
e25a686
split mapLivechatContactConflicts into a new file
pierre-lehnen-rc Nov 7, 2024
c21c00c
fix: check queue settings to take inquiry (#33782)
Gustrb Nov 7, 2024
74795f2
chore: apply suggested fixes
Gustrb Nov 7, 2024
99b5969
chore: handle contact error properly
dougfabris Nov 7, 2024
ed96363
chore: split customFields query into hooks
dougfabris Nov 7, 2024
d21c0b0
fix: check if the current channel is blocked (#33915)
tapiarafael Nov 8, 2024
47faef2
fix: `makeQueryForVisitor` method
tapiarafael Nov 8, 2024
d43cc13
chore: missing useCallback in useBlockChannel
dougfabris Nov 8, 2024
436cb46
Merge branch 'develop' into feat/single-contact-id
tapiarafael Nov 11, 2024
350cc1f
chore: add more logs to verification and merging (#33923)
tapiarafael Nov 11, 2024
785aeac
fix: check if room is blocked sooner
tapiarafael Nov 11, 2024
7150c75
refactor: return contact or undefined
tapiarafael Nov 11, 2024
4f53032
chore: create logger for contacts
tapiarafael Nov 11, 2024
0ea5e0f
refactor: move addEmail to model method
tapiarafael Nov 11, 2024
09b0531
chore: reduce ChatsProvider complexity
dougfabris Nov 11, 2024
507ef2d
fix: conflicting fields not being memoized
dougfabris Nov 11, 2024
68ef2c7
chore: `ContactInfoChannels` conditional render
dougfabris Nov 11, 2024
35c5f19
chore: improve `ContactInfo` typing and props
dougfabris Nov 12, 2024
77b2ab2
chore: block query when not allowed instead of forcing initial value …
dougfabris Nov 11, 2024
28df04a
chore: check error and loading conditions in `ContactManagerInfo`
dougfabris Nov 11, 2024
ecde5b2
chore: `ContactInfo` error verification order
dougfabris Nov 11, 2024
5b2e1f3
addeed clarification comment
pierre-lehnen-rc Nov 12, 2024
55f3b10
moved test files
pierre-lehnen-rc Nov 12, 2024
cbaf871
chore: remove redundancy in contact info history
dougfabris Nov 12, 2024
88a760f
chore: create and edit contact mutations
dougfabris Nov 12, 2024
2074105
chore: conflict fields type
dougfabris Nov 12, 2024
6c7d771
fix: update `ComposerOmnichannelCallout` content [SCI-150]
dougfabris Nov 12, 2024
90079c8
source filter on contact history
pierre-lehnen-rc Nov 12, 2024
89249b9
types and logs
pierre-lehnen-rc Nov 12, 2024
ae2b2f0
map before toArray
matheusbsilva137 Nov 12, 2024
8fbd73e
feat: add transactional flow to verification (#33922)
Gustrb Nov 13, 2024
4249b0f
do not attempt to migrate room data when contactId is being left out …
pierre-lehnen-rc Nov 13, 2024
c7d3a10
removed invalid reference to non-existing attribute
pierre-lehnen-rc Nov 13, 2024
7fb9743
fixed some query filters
pierre-lehnen-rc Nov 13, 2024
3100b60
Move room.v.contactId to room.contactId
pierre-lehnen-rc Nov 13, 2024
5a71d08
skip broken tests
pierre-lehnen-rc Nov 13, 2024
00f8e3f
fix invalid type definition
pierre-lehnen-rc Nov 13, 2024
dfcedcd
chore: remove contact verification app setting (#33951)
Gustrb Nov 13, 2024
8176817
chore: lint fix
Gustrb Nov 13, 2024
86567db
fix: api tests
Gustrb Nov 13, 2024
c67d4a2
change inquiry status
pierre-lehnen-rc Nov 13, 2024
6f64d78
Merge branch 'develop' into feat/single-contact-id
dougfabris Nov 13, 2024
6721a6f
remove unneeded mongo operations
pierre-lehnen-rc Nov 13, 2024
f49e5da
fix tests
pierre-lehnen-rc Nov 13, 2024
0d0eee4
chore: missing `contactId` in publishFields
dougfabris Nov 14, 2024
f4304e9
fixed some tests still using old data schema
pierre-lehnen-rc Nov 14, 2024
8e3dad8
create the room as verified if the contact is already verified and do…
pierre-lehnen-rc Nov 14, 2024
a8e1583
Merge branch 'develop' into feat/single-contact-id
pierre-lehnen-rc Nov 14, 2024
1c76c43
chore: import `useTranslation` from react-i18next
dougfabris Nov 14, 2024
dcab8bd
changes from PR review
pierre-lehnen-rc Nov 18, 2024
ec6c1dd
missing lint
pierre-lehnen-rc Nov 18, 2024
7638d07
type fix
pierre-lehnen-rc Nov 18, 2024
6a1b7c8
fix: custom fields are being removed when resolving conflicts
matheusbsilva137 Nov 18, 2024
3466a03
apply changes requested
matheusbsilva137 Nov 18, 2024
d504306
make channels field required in contacts
matheusbsilva137 Nov 18, 2024
e0ac2c9
fix typecheck
matheusbsilva137 Nov 18, 2024
f15ca39
chore: replace upsell modal img
dougfabris Nov 19, 2024
283eae4
remove not needed comment
matheusbsilva137 Nov 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
17 changes: 17 additions & 0 deletions .changeset/popular-queens-brake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@rocket.chat/model-typings': minor
'@rocket.chat/core-typings': minor
'@rocket.chat/rest-typings': minor
'@rocket.chat/apps-engine': minor
'@rocket.chat/i18n': minor
'@rocket.chat/meteor': minor
---

These changes aims to add:
- A brand-new omnichannel contact profile
- The ability to communicate with known contacts only
- Communicate with verified contacts only
- Merge verified contacts across different channels
- Block contact channels
- Resolve conflicting contact information when registered via different channels
- An advanced contact center filters
1 change: 1 addition & 0 deletions apps/meteor/.mocharc.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ module.exports = {
'tests/unit/lib/**/*.spec.ts',
'tests/unit/server/**/*.tests.ts',
'tests/unit/server/**/*.spec.ts',
'app/api/**/*.spec.ts',
],
};
3 changes: 2 additions & 1 deletion apps/meteor/app/api/server/lib/getServerInfo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ const { getServerInfo } = proxyquire.noCallThru().load('./getServerInfo', {
settings: new Map(),
},
});
describe('#getServerInfo()', () => {
// #ToDo: Fix those tests in a separate PR
matheusbsilva137 marked this conversation as resolved.
Show resolved Hide resolved
describe.skip('#getServerInfo()', () => {
beforeEach(() => {
hasAllPermissionAsyncMock.reset();
getCachedSupportedVersionsTokenMock.reset();
Expand Down
36 changes: 36 additions & 0 deletions apps/meteor/app/api/server/lib/maybeMigrateLivechatRoom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { isOmnichannelRoom, type IRoom } from '@rocket.chat/core-typings';
import { Rooms } from '@rocket.chat/models';
import type { FindOptions } from 'mongodb';

import { projectionAllowsAttribute } from './projectionAllowsAttribute';
import { migrateVisitorIfMissingContact } from '../../../livechat/server/lib/contacts/migrateVisitorIfMissingContact';

/**
* If the room is a livechat room and it doesn't yet have a contact, trigger the migration for its visitor and source
* The migration will create/use a contact and assign it to every room that matches this visitorId and source.
**/
export async function maybeMigrateLivechatRoom(room: IRoom | null, options: FindOptions<IRoom> = {}): Promise<IRoom | null> {
pierre-lehnen-rc marked this conversation as resolved.
Show resolved Hide resolved
if (!room || !isOmnichannelRoom(room)) {
return room;
}

// Already migrated
if (room.contactId) {
return room;
}

// If the query options specify that contactId is not needed, then do not trigger the migration
if (!projectionAllowsAttribute('contactId', options)) {
return room;
}

const contactId = await migrateVisitorIfMissingContact(room.v._id, room.source);

// Did not migrate
if (!contactId) {
return room;
}

// Load the room again with the same options so it can be reloaded with the contactId in place
return Rooms.findOneById(room._id, options);
}
29 changes: 29 additions & 0 deletions apps/meteor/app/api/server/lib/projectionAllowsAttribute.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { expect } from 'chai';

import { projectionAllowsAttribute } from './projectionAllowsAttribute';

describe('projectionAllowsAttribute', () => {
it('should return true if there are no options', () => {
expect(projectionAllowsAttribute('attributeName')).to.be.equal(true);
});

it('should return true if there is no projection', () => {
expect(projectionAllowsAttribute('attributeName', {})).to.be.equal(true);
});

it('should return true if the field is projected', () => {
expect(projectionAllowsAttribute('attributeName', { projection: { attributeName: 1 } })).to.be.equal(true);
});

it('should return false if the field is disallowed by projection', () => {
expect(projectionAllowsAttribute('attributeName', { projection: { attributeName: 0 } })).to.be.equal(false);
});

it('should return false if the field is not projected and others are', () => {
expect(projectionAllowsAttribute('attributeName', { projection: { anotherAttribute: 1 } })).to.be.equal(false);
});

it('should return true if the field is not projected and others are disallowed', () => {
expect(projectionAllowsAttribute('attributeName', { projection: { anotherAttribute: 0 } })).to.be.equal(true);
});
});
19 changes: 19 additions & 0 deletions apps/meteor/app/api/server/lib/projectionAllowsAttribute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { IRocketChatRecord } from '@rocket.chat/core-typings';
import type { FindOptions } from 'mongodb';

export function projectionAllowsAttribute(attributeName: string, options?: FindOptions<IRocketChatRecord>): boolean {
if (!options?.projection) {
return true;
}

if (attributeName in options.projection) {
return Boolean(options.projection[attributeName]);
}

const projectingAllowedFields = Object.values(options.projection).some((value) => Boolean(value));

// If the attribute is not on the projection list, return the opposite of the values in the projection. aka:
// if the projection is specifying blocked fields, then this field is allowed;
// if the projection is specifying allowed fields, then this field is blocked;
return !projectingAllowedFields;
}
5 changes: 4 additions & 1 deletion apps/meteor/app/api/server/v1/rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { composeRoomWithLastMessage } from '../helpers/composeRoomWithLastMessag
import { getPaginationItems } from '../helpers/getPaginationItems';
import { getUserFromParams } from '../helpers/getUserFromParams';
import { getUploadFormData } from '../lib/getUploadFormData';
import { maybeMigrateLivechatRoom } from '../lib/maybeMigrateLivechatRoom';
import {
findAdminRoom,
findAdminRooms,
Expand Down Expand Up @@ -433,8 +434,10 @@ API.v1.addRoute(
const { team, parentRoom } = await Team.getRoomInfo(room);
const parent = discussionParent || parentRoom;

const options = { projection: fields };

return API.v1.success({
room: (await Rooms.findOneByIdOrName(room._id, { projection: fields })) ?? undefined,
room: (await maybeMigrateLivechatRoom(await Rooms.findOneByIdOrName(room._id, options), options)) ?? undefined,
...(team && { team }),
...(parent && { parent }),
});
Expand Down
6 changes: 6 additions & 0 deletions apps/meteor/app/apps/server/bridges/bridges.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { AppActivationBridge } from './activation';
import { AppApisBridge } from './api';
import { AppCloudBridge } from './cloud';
import { AppCommandsBridge } from './commands';
import { AppContactBridge } from './contact';
import { AppDetailChangesBridge } from './details';
import { AppEmailBridge } from './email';
import { AppEnvironmentalVariableBridge } from './environmental';
Expand Down Expand Up @@ -55,6 +56,7 @@ export class RealAppBridges extends AppBridges {
this._threadBridge = new AppThreadBridge(orch);
this._roleBridge = new AppRoleBridge(orch);
this._emailBridge = new AppEmailBridge(orch);
this._contactBridge = new AppContactBridge(orch);
}

getCommandBridge() {
Expand Down Expand Up @@ -156,4 +158,8 @@ export class RealAppBridges extends AppBridges {
getEmailBridge() {
return this._emailBridge;
}

getContactBridge() {
return this._contactBridge;
}
}
39 changes: 39 additions & 0 deletions apps/meteor/app/apps/server/bridges/contact.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { IAppServerOrchestrator } from '@rocket.chat/apps';
import type { ILivechatContact } from '@rocket.chat/apps-engine/definition/livechat';
import { ContactBridge } from '@rocket.chat/apps-engine/server/bridges';

import { addContactEmail } from '../../../livechat/server/lib/contacts/addContactEmail';
import { verifyContactChannel } from '../../../livechat/server/lib/contacts/verifyContactChannel';

export class AppContactBridge extends ContactBridge {
constructor(private readonly orch: IAppServerOrchestrator) {
super();
}

async getById(contactId: ILivechatContact['_id'], appId: string): Promise<ILivechatContact | undefined> {
this.orch.debugLog(`The app ${appId} is fetching a contact`);
return this.orch.getConverters().get('contacts').convertById(contactId);
}

async verifyContact(
verifyContactChannelParams: {
contactId: string;
field: string;
value: string;
visitorId: string;
roomId: string;
},
appId: string,
): Promise<void> {
this.orch.debugLog(`The app ${appId} is verifing a contact`);
// Note: If there is more than one app installed, whe should validate the app that called this method to be same one
matheusbsilva137 marked this conversation as resolved.
Show resolved Hide resolved
// selected in the setting.
await verifyContactChannel(verifyContactChannelParams);
}

protected async addContactEmail(contactId: ILivechatContact['_id'], email: string, appId: string): Promise<ILivechatContact> {
this.orch.debugLog(`The app ${appId} is adding a new email to the contact`);
const contact = await addContactEmail(contactId, email);
return this.orch.getConverters().get('contacts').convertContact(contact);
}
}
125 changes: 125 additions & 0 deletions apps/meteor/app/apps/server/converters/contacts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import type { IAppContactsConverter, IAppsLivechatContact } from '@rocket.chat/apps';
import type { ILivechatContact } from '@rocket.chat/core-typings';
import { LivechatContacts } from '@rocket.chat/models';

import { transformMappedData } from './transformMappedData';

export class AppContactsConverter implements IAppContactsConverter {
async convertById(contactId: ILivechatContact['_id']): Promise<IAppsLivechatContact | undefined> {
const contact = await LivechatContacts.findOneById(contactId);
if (!contact) {
return;
}

return this.convertContact(contact);
}

async convertContact(contact: undefined | null): Promise<undefined>;

async convertContact(contact: ILivechatContact): Promise<IAppsLivechatContact>;

async convertContact(contact: ILivechatContact | undefined | null): Promise<IAppsLivechatContact | undefined> {
if (!contact) {
return;
}

return structuredClone(contact);
}

convertAppContact(contact: undefined | null): Promise<undefined>;

convertAppContact(contact: IAppsLivechatContact): Promise<ILivechatContact>;

async convertAppContact(contact: IAppsLivechatContact | undefined | null): Promise<ILivechatContact | undefined> {
if (!contact) {
return;
}

// Map every attribute individually to ensure there are no extra data coming from the app and leaking into anything else.
const map = {
_id: '_id',
_updatedAt: '_updatedAt',
name: 'name',
phones: {
from: 'phones',
list: true,
map: {
phoneNumber: 'phoneNumber',
},
},
emails: {
from: 'emails',
list: true,
map: {
address: 'address',
},
},
contactManager: 'contactManager',
unknown: 'unknown',
conflictingFields: {
from: 'conflictingFields',
list: true,
map: {
field: 'field',
value: 'value',
},
},
customFields: 'customFields',
channels: {
from: 'channels',
list: true,
map: {
name: 'name',
verified: 'verified',
visitor: {
from: 'visitor',
map: {
visitorId: 'visitorId',
source: {
from: 'source',
map: {
type: 'type',
id: 'id',
},
},
},
},
blocked: 'blocked',
field: 'field',
value: 'value',
verifiedAt: 'verifiedAt',
details: {
from: 'details',
map: {
type: 'type',
id: 'id',
alias: 'alias',
label: 'label',
sidebarIcon: 'sidebarIcon',
defaultIcon: 'defaultIcon',
destination: 'destination',
},
},
lastChat: {
from: 'lastChat',
map: {
_id: '_id',
ts: 'ts',
},
},
},
},
createdAt: 'createdAt',
lastChat: {
from: 'lastChat',
map: {
_id: '_id',
ts: 'ts',
},
},
importIds: 'importIds',
};

return transformMappedData(contact, map);
}
}
2 changes: 2 additions & 0 deletions apps/meteor/app/apps/server/converters/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AppContactsConverter } from './contacts';
import { AppDepartmentsConverter } from './departments';
import { AppMessagesConverter } from './messages';
import { AppRolesConverter } from './roles';
Expand All @@ -9,6 +10,7 @@ import { AppVideoConferencesConverter } from './videoConferences';
import { AppVisitorsConverter } from './visitors';

export {
AppContactsConverter,
AppMessagesConverter,
AppRoomsConverter,
AppSettingsConverter,
Expand Down
18 changes: 17 additions & 1 deletion apps/meteor/app/apps/server/converters/rooms.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RoomType } from '@rocket.chat/apps-engine/definition/rooms';
import { LivechatVisitors, Rooms, LivechatDepartment, Users } from '@rocket.chat/models';
import { LivechatVisitors, Rooms, LivechatDepartment, Users, LivechatContacts } from '@rocket.chat/models';

import { transformMappedData } from './transformMappedData';

Expand Down Expand Up @@ -75,6 +75,12 @@ export class AppRoomsConverter {
};
}

let contactId;
if (room.contact?._id) {
const contact = await LivechatContacts.findOneById(room.contact._id, { projection: { _id: 1 } });
contactId = contact._id;
}

ggazzo marked this conversation as resolved.
Show resolved Hide resolved
const newRoom = {
...(room.id && { _id: room.id }),
fname: room.displayName,
Expand All @@ -100,6 +106,7 @@ export class AppRoomsConverter {
customFields: room.customFields,
livechatData: room.livechatData,
prid: typeof room.parentRoom === 'undefined' ? undefined : room.parentRoom.id,
contactId,
...(room._USERNAMES && { _USERNAMES: room._USERNAMES }),
...(room.source && {
source: {
Expand Down Expand Up @@ -180,6 +187,15 @@ export class AppRoomsConverter {

return this.orch.getConverters().get('visitors').convertById(v._id);
},
contact: (room) => {
const { contactId } = room;

if (!contactId) {
return undefined;
}

return this.orch.getConverters().get('contacts').convertById(contactId);
},
// Note: room.v is not just visitor, it also contains channel related visitor data
// so we need to pass this data to the converter
// So suppose you have a contact whom we're contacting using SMS via 2 phone no's,
Expand Down
Loading
Loading