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: create contact endpoint #32693

Merged
merged 55 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
40312b9
feat: create contact entity
tapiarafael Jun 27, 2024
668d934
feat: add create contact endpoint
tapiarafael Jun 27, 2024
de25810
add deprecation message to old endpoint
tapiarafael Jun 27, 2024
74c9ed8
remove unused file
tapiarafael Jun 27, 2024
ae70c00
fix: typo in prop
tapiarafael Jun 27, 2024
20c3892
test: implement contact tests
tapiarafael Jun 27, 2024
7e8dfa3
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jun 27, 2024
da25a9c
Create sixty-spoons-own.md
tapiarafael Jun 27, 2024
b7e0bf7
Update sixty-spoons-own.md
tapiarafael Jun 28, 2024
675bb12
Update .changeset/sixty-spoons-own.md
tapiarafael Jul 2, 2024
c59c4c2
test: include custom fields validations
tapiarafael Jul 2, 2024
e13f736
test: ensure body is being validated
tapiarafael Jul 2, 2024
e329740
test: ensure error message is equal the expected
tapiarafael Jul 2, 2024
4b74679
test: ensure that it is possible to create contact with contact manag…
tapiarafael Jul 2, 2024
8b1a303
feat: create new permission
tapiarafael Jul 2, 2024
3d26650
fix: replace MeteorError to Error
tapiarafael Jul 3, 2024
36b5021
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 3, 2024
9fe155c
refactor: deprecate old endpoint
tapiarafael Jul 3, 2024
8e7da69
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 3, 2024
35bc941
fix: remove migration
tapiarafael Jul 4, 2024
e7b6048
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 5, 2024
6c908af
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 9, 2024
b4c2686
test: additional fields
tapiarafael Jul 9, 2024
af05b31
test: create agent to test
tapiarafael Jul 9, 2024
06a656e
test: restore setting to the original value
tapiarafael Jul 9, 2024
d61e15e
fix: set `phones` as required property
tapiarafael Jul 9, 2024
167da1a
refactor: breaks `validateCustomFields` into two functions
tapiarafael Jul 9, 2024
3a08e05
test: ensure that custom fields are properly validated
tapiarafael Jul 9, 2024
716162c
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 9, 2024
37bdda6
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 9, 2024
438c697
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 9, 2024
8c3a68f
Update .changeset/sixty-spoons-own.md
tapiarafael Jul 10, 2024
80172f9
Update apps/meteor/app/livechat/server/lib/Contacts.ts
tapiarafael Jul 10, 2024
0d0d016
fix: use correct method to deprecation
tapiarafael Jul 10, 2024
3bba59f
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 10, 2024
2cb7fcd
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 12, 2024
8ebf18a
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 15, 2024
ef56b06
fix: find only agents
tapiarafael Jul 16, 2024
307661a
Update apps/meteor/app/livechat/server/api/v1/contact.ts
tapiarafael Jul 16, 2024
51b9d0b
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 16, 2024
98b50bc
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 16, 2024
e07090a
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 16, 2024
c1633e6
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 17, 2024
39fffda
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Jul 29, 2024
a5483d5
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Aug 8, 2024
2311681
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Aug 8, 2024
618b204
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Aug 14, 2024
3964420
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Aug 15, 2024
7e55b47
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Aug 16, 2024
5e5fa1d
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Aug 22, 2024
55d68af
fix: remove deprecation
tapiarafael Aug 22, 2024
e32f916
fix: check if app is running on test mode
tapiarafael Aug 22, 2024
917ebff
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Aug 22, 2024
1f3d928
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Aug 22, 2024
c79fe52
Merge branch 'develop' into feat/create-contact-endpoint
tapiarafael Aug 23, 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
9 changes: 9 additions & 0 deletions .changeset/sixty-spoons-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@rocket.chat/meteor": minor
"@rocket.chat/core-typings": minor
"@rocket.chat/model-typings": minor
"@rocket.chat/models": minor
"@rocket.chat/rest-typings": minor
---

Introduced "create contacts" endpoint to the omnichannel
tapiarafael marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions apps/meteor/app/authorization/server/constant/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ export const permissions = [
_id: 'view-l-room',
roles: ['livechat-manager', 'livechat-monitor', 'livechat-agent', 'admin'],
},
{
_id: 'create-livechat-contact',
roles: ['livechat-manager', 'livechat-monitor', 'livechat-agent', 'admin'],
},
{ _id: 'view-livechat-manager', roles: ['livechat-manager', 'livechat-monitor', 'admin'] },
{
_id: 'view-omnichannel-contact-center',
Expand Down
18 changes: 17 additions & 1 deletion apps/meteor/app/livechat/server/api/v1/contact.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { LivechatCustomField, LivechatVisitors } from '@rocket.chat/models';
import { isPOSTOmnichannelContactsProps } from '@rocket.chat/rest-typings';
import { escapeRegExp } from '@rocket.chat/string-helpers';
import { Match, check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

import { API } from '../../../../api/server';
import { Contacts } from '../../lib/Contacts';
import { Contacts, createContact } from '../../lib/Contacts';

/**
* @deprecated to create a contact, use the omnichannel/contacts endpoint
tapiarafael marked this conversation as resolved.
Show resolved Hide resolved
*/
API.v1.addRoute(
'omnichannel/contact',
{ authRequired: true, permissionsRequired: ['view-l-room'] },
Expand Down Expand Up @@ -82,3 +86,15 @@ API.v1.addRoute(
},
},
);

API.v1.addRoute(
'omnichannel/contacts',
{ authRequired: true, permissionsRequired: ['create-livechat-contact'], validateParams: isPOSTOmnichannelContactsProps },
{
async post() {
const contactId = await createContact({ ...this.bodyParams, unknown: false });
MarcosSpessatto marked this conversation as resolved.
Show resolved Hide resolved

return API.v1.success({ contactId });
},
},
);
91 changes: 89 additions & 2 deletions apps/meteor/app/livechat/server/lib/Contacts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import type { ILivechatCustomField, ILivechatVisitor, IOmnichannelRoom } from '@rocket.chat/core-typings';
import { LivechatVisitors, Users, LivechatRooms, LivechatCustomField, LivechatInquiry, Rooms, Subscriptions } from '@rocket.chat/models';
import type { ILivechatContactChannel, ILivechatCustomField, ILivechatVisitor, IOmnichannelRoom } from '@rocket.chat/core-typings';
import {
LivechatVisitors,
Users,
LivechatRooms,
LivechatCustomField,
LivechatInquiry,
Rooms,
Subscriptions,
LivechatContacts,
} from '@rocket.chat/models';
import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
import type { MatchKeysAndValues, OnlyFieldsOfType } from 'mongodb';
Expand All @@ -22,6 +31,16 @@ type RegisterContactProps = {
};
};

type CreateContactParams = {
name: string;
emails: string[];
phones: string[];
unknown: boolean;
customFields?: Record<string, string | unknown>;
contactManager?: string;
channels?: ILivechatContactChannel[];
};

export const Contacts = {
async registerContact({
token,
Expand Down Expand Up @@ -152,3 +171,71 @@ export const Contacts = {
return contactId;
},
};

export async function createContact(params: CreateContactParams): Promise<string> {
const { name, emails, phones, customFields = {}, contactManager, channels, unknown } = params;

if (contactManager) {
const contactManagerUser = await Users.findOneById(contactManager);
if (!contactManagerUser) {
tapiarafael marked this conversation as resolved.
Show resolved Hide resolved
throw new Meteor.Error('error-contact-manager-not-found', `No user found with id ${contactManager}`);
}
tapiarafael marked this conversation as resolved.
Show resolved Hide resolved
if (!contactManagerUser.roles || !Array.isArray(contactManagerUser.roles) || !contactManagerUser.roles.includes('livechat-agent')) {
throw new Meteor.Error('error-invalid-contact-manager', 'The contact manager must have the role "livechat-agent"');
}
tapiarafael marked this conversation as resolved.
Show resolved Hide resolved
}

await validateCustomFields(customFields);

const { insertedId } = await LivechatContacts.insertOne({
name,
tapiarafael marked this conversation as resolved.
Show resolved Hide resolved
emails,
phones,
contactManager,
channels,
customFields,
unknown,
});

return insertedId;
}

async function validateCustomFields(customFields: Record<string, string | unknown>) {
const allowedCustomFields = LivechatCustomField.findByScope<
tapiarafael marked this conversation as resolved.
Show resolved Hide resolved
Pick<ILivechatCustomField, '_id' | 'label' | 'regexp' | 'required' | 'visibility'>
>(
'visitor',
{
projection: { _id: 1, label: 1, regexp: 1, required: 1 },
},
false,
);

const livechatData: Record<string, string> = {};

for await (const cf of allowedCustomFields) {
if (!customFields.hasOwnProperty(cf._id)) {
if (cf.required) {
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label }));
}
continue;
}
const cfValue: string = trim(customFields[cf._id]);

if (!cfValue || typeof cfValue !== 'string') {
if (cf.required) {
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label }));
}
continue;
}

if (cf.regexp) {
const regex = new RegExp(cf.regexp);
if (!regex.test(cfValue)) {
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label }));
}
}

livechatData[cf._id] = cfValue;
}
}
6 changes: 6 additions & 0 deletions apps/meteor/server/models/LivechatContacts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { registerModel } from '@rocket.chat/models';

import { db } from '../database/utils';
import { LivechatContactsRaw } from './raw/LivechatContacts';

registerModel('ILivechatContactsModel', new LivechatContactsRaw(db));
11 changes: 11 additions & 0 deletions apps/meteor/server/models/raw/LivechatContacts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { ILivechatContact, RocketChatRecordDeleted } from '@rocket.chat/core-typings';
import type { ILivechatContactsModel } from '@rocket.chat/model-typings';
import type { Collection, Db } from 'mongodb';

import { BaseRaw } from './BaseRaw';

export class LivechatContactsRaw extends BaseRaw<ILivechatContact> implements ILivechatContactsModel {
constructor(db: Db, trash?: Collection<RocketChatRecordDeleted<ILivechatContact>>) {
super(db, 'livechat_contact', trash);
}
}
1 change: 1 addition & 0 deletions apps/meteor/server/models/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import './Integrations';
import './Invites';
import './LivechatAgentActivity';
import './LivechatBusinessHours';
import './LivechatContacts';
import './LivechatCustomField';
import './LivechatDepartment';
import './LivechatDepartmentAgents';
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/server/startup/migrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ import './v300';
import './v301';
import './v303';
import './v304';
import './v305';

export * from './xrun';
9 changes: 9 additions & 0 deletions apps/meteor/server/startup/migrations/v305.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { upsertPermissions } from '../../../app/authorization/server/functions/upsertPermissions';
import { addMigration } from '../../lib/migrations';

addMigration({
version: 305,
async up() {
await upsertPermissions();
},
});
Loading
Loading