Skip to content

Commit

Permalink
Merge branch 'develop' into fix/new-version-banner
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Dec 19, 2024
2 parents f64e567 + 5c423d7 commit a4b4c30
Show file tree
Hide file tree
Showing 152 changed files with 1,812 additions and 827 deletions.
6 changes: 6 additions & 0 deletions .changeset/empty-pans-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/i18n": patch
---

Fixes the incorrect registration status shown on admin users page for federated remote users.
6 changes: 6 additions & 0 deletions .changeset/fair-carrots-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/model-typings": patch
---

Fixes "Average first response time" and "Best first response time" metrics being associated with the last agent who served the room (instead of the first one)
5 changes: 5 additions & 0 deletions .changeset/fifty-parrots-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixes an issue preventing the creation of normal direct message rooms due to an invalid federation configuration, allowing proper room creation under standard settings.
5 changes: 5 additions & 0 deletions .changeset/fuzzy-coins-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixes missing images in Twitter article links to ensure proper display by relying on meta tags.
5 changes: 5 additions & 0 deletions .changeset/giant-nails-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/apps-engine': patch
---

Adds simple app subprocess metrics report
5 changes: 5 additions & 0 deletions .changeset/honest-kings-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/apps-engine': patch
---

Attempts to restart an app subprocess if the spawn command fails
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/nervous-fireants-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Allows default avatars to be generated with more than one inital (limited to first 3) when setting `Use Full Name Initials to Generate Default Avatar` is true.
5 changes: 5 additions & 0 deletions .changeset/quiet-radios-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/apps-engine': patch
---

Fixes an issue while collecting the error message from a failed restart attempt of an app subprocess
5 changes: 5 additions & 0 deletions .changeset/seven-owls-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Fixed an issue that added potencially infinite callbacks to the same event, degrading performance over time.
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
5 changes: 5 additions & 0 deletions .changeset/young-dots-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/apps-engine': patch
---

Prevents app:getStatus requests from timing out in some cases
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
6 changes: 4 additions & 2 deletions apps/meteor/app/lib/server/functions/addUserToRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ export const addUserToRoom = async function (
{
skipSystemMessage,
skipAlertSound,
createAsHidden = false,
}: {
skipSystemMessage?: boolean;
skipAlertSound?: boolean;
createAsHidden?: boolean;
} = {},
): Promise<boolean | undefined> {
const now = new Date();
Expand Down Expand Up @@ -84,8 +86,8 @@ export const addUserToRoom = async function (

const { insertedId } = await Subscriptions.createWithRoomAndUser(room, userToBeAdded as IUser, {
ts: now,
open: true,
alert: !skipAlertSound,
open: !createAsHidden,
alert: createAsHidden ? false : !skipAlertSound,
unread: 1,
userMentions: 1,
groupMentions: 0,
Expand Down
4 changes: 1 addition & 3 deletions apps/meteor/app/lib/server/functions/createRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ async function createUsersSubscriptions({

memberIds.push(member._id);

const extra: Partial<ISubscriptionExtraData> = options?.subscriptionExtra || {};

extra.open = true;
const extra: Partial<ISubscriptionExtraData> = { open: true, ...options?.subscriptionExtra };

if (room.prid) {
extra.prid = room.prid;
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
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
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
Loading

0 comments on commit a4b4c30

Please sign in to comment.