Skip to content

Commit

Permalink
Merge branch 'develop' into feat/contacts-check-existence-endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Dec 19, 2024
2 parents 454cbf8 + 82e667f commit c7af3ca
Show file tree
Hide file tree
Showing 97 changed files with 875 additions and 417 deletions.
5 changes: 5 additions & 0 deletions .changeset/lovely-beers-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Fixes messages not being processed for all slack servers
5 changes: 5 additions & 0 deletions .changeset/slow-readers-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Fixes an issue where the update banner wasn't showing the new version number
6 changes: 6 additions & 0 deletions .changeset/violet-pets-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/ui-client': patch
'@rocket.chat/meteor': patch
---

Fixed the data structure of the features preview
5 changes: 5 additions & 0 deletions .changeset/wet-chicken-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Fixes contact update failing in case a custom field is removed from the workspace
7 changes: 7 additions & 0 deletions .changeset/wicked-socks-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@rocket.chat/meteor": minor
"@rocket.chat/core-typings": minor
"@rocket.chat/rest-typings": minor
---

Adds a new callout in the subscription page to inform users of subscription upgrade eligibility when applicable.
5 changes: 5 additions & 0 deletions .changeset/wise-queens-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixes an issue where the notification sound was playing randomly
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Cloud, Serialized } from '@rocket.chat/core-typings';
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
import { v, compile } from 'suretype';

import { CloudWorkspaceConnectionError } from '../../../../../lib/errors/CloudWorkspaceConnectionError';
import { settings } from '../../../../settings/server';

const workspaceSyncPayloadSchema = v.object({
workspaceId: v.string().required(),
publicKey: v.string(),
license: v.string().required(),
});

const assertWorkspaceSyncPayload = compile(workspaceSyncPayloadSchema);

export async function fetchWorkspaceSyncPayload({
token,
data,
}: {
token: string;
data: Cloud.WorkspaceSyncRequestPayload;
}): Promise<Serialized<Cloud.WorkspaceSyncResponse>> {
const workspaceRegistrationClientUri = settings.get<string>('Cloud_Workspace_Registration_Client_Uri');
const response = await fetch(`${workspaceRegistrationClientUri}/sync`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
body: data,
});

if (!response.ok) {
const { error } = await response.json();
throw new CloudWorkspaceConnectionError(`Failed to connect to Rocket.Chat Cloud: ${error}`);
}

const payload = await response.json();

assertWorkspaceSyncPayload(payload);

return payload;
}
Original file line number Diff line number Diff line change
@@ -1,57 +1,14 @@
import type { Cloud, Serialized } from '@rocket.chat/core-typings';
import { DuplicatedLicenseError } from '@rocket.chat/license';
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
import { v, compile } from 'suretype';
import { Settings } from '@rocket.chat/models';

import { callbacks } from '../../../../../lib/callbacks';
import { CloudWorkspaceAccessError } from '../../../../../lib/errors/CloudWorkspaceAccessError';
import { CloudWorkspaceConnectionError } from '../../../../../lib/errors/CloudWorkspaceConnectionError';
import { CloudWorkspaceRegistrationError } from '../../../../../lib/errors/CloudWorkspaceRegistrationError';
import { SystemLogger } from '../../../../../server/lib/logger/system';
import { settings } from '../../../../settings/server';
import { buildWorkspaceRegistrationData } from '../buildRegistrationData';
import { CloudWorkspaceAccessTokenEmptyError, getWorkspaceAccessToken } from '../getWorkspaceAccessToken';
import { retrieveRegistrationStatus } from '../retrieveRegistrationStatus';

const workspaceSyncPayloadSchema = v.object({
workspaceId: v.string().required(),
publicKey: v.string(),
license: v.string().required(),
});

const assertWorkspaceSyncPayload = compile(workspaceSyncPayloadSchema);

const fetchWorkspaceSyncPayload = async ({
token,
data,
}: {
token: string;
data: Cloud.WorkspaceSyncRequestPayload;
}): Promise<Serialized<Cloud.WorkspaceSyncResponse>> => {
const workspaceRegistrationClientUri = settings.get<string>('Cloud_Workspace_Registration_Client_Uri');
const response = await fetch(`${workspaceRegistrationClientUri}/sync`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
body: data,
});

if (!response.ok) {
try {
const { error } = await response.json();
throw new CloudWorkspaceConnectionError(`Failed to connect to Rocket.Chat Cloud: ${error}`);
} catch (error) {
throw new CloudWorkspaceConnectionError(`Failed to connect to Rocket.Chat Cloud: ${response.statusText}`);
}
}

const payload = await response.json();

assertWorkspaceSyncPayload(payload);

return payload;
};
import { fetchWorkspaceSyncPayload } from './fetchWorkspaceSyncPayload';

export async function syncCloudData() {
try {
Expand All @@ -67,11 +24,17 @@ export async function syncCloudData() {

const workspaceRegistrationData = await buildWorkspaceRegistrationData(undefined);

const { license, removeLicense = false } = await fetchWorkspaceSyncPayload({
const {
license,
removeLicense = false,
cloudSyncAnnouncement,
} = await fetchWorkspaceSyncPayload({
token,
data: workspaceRegistrationData,
});

await Settings.updateValueById('Cloud_Sync_Announcement_Payload', JSON.stringify(cloudSyncAnnouncement ?? null));

if (removeLicense) {
await callbacks.run('workspaceLicenseRemoved');
} else {
Expand Down
4 changes: 2 additions & 2 deletions apps/meteor/app/lib/server/methods/createChannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const createChannelMethod = async (
name: string,
members: string[],
readOnly = false,
customFields: Record<string, any> = {},
customFields?: Record<string, any>,
extraData: Record<string, any> = {},
excludeSelf = false,
) => {
Expand Down Expand Up @@ -53,7 +53,7 @@ export const createChannelMethod = async (
}

return createRoom('c', name, user, members, excludeSelf, readOnly, {
customFields,
...(customFields && Object.keys(customFields).length && { customFields }),
...extraData,
});
};
Expand Down
4 changes: 2 additions & 2 deletions apps/meteor/app/lib/server/methods/createPrivateGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const createPrivateGroupMethod = async (
name: string,
members: string[],
readOnly = false,
customFields: Record<string, any> = {},
customFields?: Record<string, any>,
extraData: Record<string, any> = {},
excludeSelf = false,
): Promise<
Expand All @@ -51,7 +51,7 @@ export const createPrivateGroupMethod = async (
}

return createRoom('p', name, user, members, excludeSelf, readOnly, {
customFields,
...(customFields && Object.keys(customFields).length && { customFields }),
...extraData,
});
};
Expand Down
28 changes: 24 additions & 4 deletions apps/meteor/app/livechat/server/lib/contacts/updateContact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export type UpdateContactParams = {
export async function updateContact(params: UpdateContactParams): Promise<ILivechatContact> {
const { contactId, name, emails, phones, customFields: receivedCustomFields, contactManager, channels, wipeConflicts } = params;

const contact = await LivechatContacts.findOneById<Pick<ILivechatContact, '_id' | 'name'>>(contactId, {
projection: { _id: 1, name: 1 },
const contact = await LivechatContacts.findOneById<Pick<ILivechatContact, '_id' | 'name' | 'customFields'>>(contactId, {
projection: { _id: 1, name: 1, customFields: 1 },
});

if (!contact) {
Expand All @@ -36,15 +36,35 @@ export async function updateContact(params: UpdateContactParams): Promise<ILivec
await validateContactManager(contactManager);
}

const customFields = receivedCustomFields && validateCustomFields(await getAllowedCustomFields(), receivedCustomFields);
const workspaceAllowedCustomFields = await getAllowedCustomFields();
const workspaceAllowedCustomFieldsIds = workspaceAllowedCustomFields.map((customField) => customField._id);
const currentCustomFieldsIds = Object.keys(contact.customFields || {});
const notRegisteredCustomFields = currentCustomFieldsIds
.filter((customFieldId) => !workspaceAllowedCustomFieldsIds.includes(customFieldId))
.map((customFieldId) => ({ _id: customFieldId }));

const customFieldsToUpdate =
receivedCustomFields &&
validateCustomFields(workspaceAllowedCustomFields, receivedCustomFields, {
ignoreAdditionalFields: !!notRegisteredCustomFields.length,
});

if (receivedCustomFields && customFieldsToUpdate && notRegisteredCustomFields.length) {
const allowedCustomFields = [...workspaceAllowedCustomFields, ...notRegisteredCustomFields];
validateCustomFields(allowedCustomFields, receivedCustomFields);

notRegisteredCustomFields.forEach((notRegisteredCustomField) => {
customFieldsToUpdate[notRegisteredCustomField._id] = contact.customFields?.[notRegisteredCustomField._id] as string;
});
}

const updatedContact = await LivechatContacts.updateContact(contactId, {
name,
emails: emails?.map((address) => ({ address })),
phones: phones?.map((phoneNumber) => ({ phoneNumber })),
contactManager,
channels,
customFields,
customFields: customFieldsToUpdate,
...(wipeConflicts && { conflictingFields: [] }),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { trim } from '../../../../../lib/utils/stringUtils';
import { i18n } from '../../../../utils/lib/i18n';

export function validateCustomFields(
allowedCustomFields: AtLeast<ILivechatCustomField, '_id' | 'label' | 'regexp' | 'required'>[],
allowedCustomFields: AtLeast<ILivechatCustomField, '_id'>[],
customFields: Record<string, string | unknown>,
{
ignoreAdditionalFields = false,
Expand All @@ -16,15 +16,15 @@ export function validateCustomFields(
for (const cf of allowedCustomFields) {
if (!customFields.hasOwnProperty(cf._id)) {
if (cf.required && !ignoreValidationErrors) {
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label }));
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label || cf._id }));
}
continue;
}
const cfValue: string = trim(customFields[cf._id]);

if (!cfValue || typeof cfValue !== 'string') {
if (cf.required && !ignoreValidationErrors) {
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label }));
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label || cf._id }));
}
continue;
}
Expand All @@ -36,7 +36,7 @@ export function validateCustomFields(
continue;
}

throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label }));
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label || cf._id }));
}
}

Expand Down
23 changes: 11 additions & 12 deletions apps/meteor/app/slackbridge/server/RocketAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ export default class RocketAdapter {
try {
if (!slack.getSlackChannel(rocketMessageDeleted.rid)) {
// This is on a channel that the rocket bot is not subscribed on this slack server
return;
continue;
}

rocketLogger.debug('onRocketMessageDelete', rocketMessageDeleted);
await slack.postDeleteMessage(rocketMessageDeleted);
} catch (err) {
Expand Down Expand Up @@ -134,22 +135,23 @@ export default class RocketAdapter {
try {
if (!slack.getSlackChannel(rocketMessage.rid)) {
// This is on a channel that the rocket bot is not subscribed
return;
continue;
}
rocketLogger.debug('onRocketMessage', rocketMessage);

if (rocketMessage.editedAt) {
// This is an Edit Event
await this.processMessageChanged(rocketMessage, slack);
return rocketMessage;
continue;
}
// Ignore messages originating from Slack
if (rocketMessage._id.indexOf('slack-') === 0) {
return rocketMessage;
continue;
}

if (rocketMessage.file) {
return this.processFileShare(rocketMessage, slack);
await this.processFileShare(rocketMessage, slack);
continue;
}

// A new message from Rocket.Chat
Expand Down Expand Up @@ -206,10 +208,7 @@ export default class RocketAdapter {
}
}

const message = `${text} ${fileName}`;

rocketMessage.msg = message;
await slack.postMessage(slack.getSlackChannel(rocketMessage.rid), rocketMessage);
await slack.postMessage(slack.getSlackChannel(rocketMessage.rid), { ...rocketMessage, msg: `${text} ${fileName}` });
}
}

Expand Down Expand Up @@ -266,15 +265,15 @@ export default class RocketAdapter {

for await (const slack of this.slackAdapters) {
if (addedRoom) {
return;
continue;
}

const slackChannel = await slack.slackAPI.getRoomInfo(slackChannelID);
if (slackChannel) {
const members = await slack.slackAPI.getMembers(slackChannelID);
if (!members) {
rocketLogger.error('Could not fetch room members');
return;
continue;
}

const rocketRoom = await Rooms.findOneByName(slackChannel.name);
Expand All @@ -288,7 +287,7 @@ export default class RocketAdapter {

if (!rocketUserCreator) {
rocketLogger.error({ msg: 'Could not fetch room creator information', creator: slackChannel.creator });
return;
continue;
}

try {
Expand Down
Loading

0 comments on commit c7af3ca

Please sign in to comment.