From 811f3165cc302850de65628ffb4e52ad35714359 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 11 Jun 2024 07:29:11 -0600 Subject: [PATCH 01/94] fix: OTR conversation closes automatically when any of the peers goes offline (#32430) --- apps/meteor/app/otr/client/OTR.ts | 10 ++++++ apps/meteor/app/otr/client/OTRRoom.ts | 45 ++++++++++++++++++++++++++ apps/meteor/app/otr/client/events.ts | 7 ++++ apps/meteor/app/otr/client/index.ts | 1 + packages/i18n/src/locales/en.i18n.json | 1 + 5 files changed, 64 insertions(+) create mode 100644 apps/meteor/app/otr/client/events.ts diff --git a/apps/meteor/app/otr/client/OTR.ts b/apps/meteor/app/otr/client/OTR.ts index a855381bd9c0..9f3eea155384 100644 --- a/apps/meteor/app/otr/client/OTR.ts +++ b/apps/meteor/app/otr/client/OTR.ts @@ -24,6 +24,16 @@ class OTR implements IOTR { this.instancesByRoomId[rid] = otrRoom; return this.instancesByRoomId[rid]; } + + closeAllInstances(): void { + // Resets state, but doesnt emit events + // Other party should receive event and fire events + Object.values(this.instancesByRoomId).forEach((instance) => { + instance.softReset(); + }); + + this.instancesByRoomId = {}; + } } export default new OTR(); diff --git a/apps/meteor/app/otr/client/OTRRoom.ts b/apps/meteor/app/otr/client/OTRRoom.ts index 8899de13b190..ea5dc86b8319 100644 --- a/apps/meteor/app/otr/client/OTRRoom.ts +++ b/apps/meteor/app/otr/client/OTRRoom.ts @@ -1,4 +1,5 @@ import type { IRoom, IMessage, IUser } from '@rocket.chat/core-typings'; +import { UserStatus } from '@rocket.chat/core-typings'; import { Random } from '@rocket.chat/random'; import EJSON from 'ejson'; import { Meteor } from 'meteor/meteor'; @@ -7,6 +8,7 @@ import { Tracker } from 'meteor/tracker'; import GenericModal from '../../../client/components/GenericModal'; import { imperativeModal } from '../../../client/lib/imperativeModal'; +import type { UserPresence } from '../../../client/lib/presence'; import { Presence } from '../../../client/lib/presence'; import { dispatchToastMessage } from '../../../client/lib/toast'; import { getUidDirectMessage } from '../../../client/lib/utils/getUidDirectMessage'; @@ -47,6 +49,8 @@ export class OTRRoom implements IOTRRoom { private isFirstOTR: boolean; + private onPresenceEventHook: (event: UserPresence | undefined) => void; + protected constructor(uid: IUser['_id'], rid: IRoom['_id'], peerId: IUser['_id']) { this._userId = uid; this._roomId = rid; @@ -54,6 +58,7 @@ export class OTRRoom implements IOTRRoom { this._sessionKey = null; this.peerId = peerId; this.isFirstOTR = true; + this.onPresenceEventHook = this.onPresenceEvent.bind(this); } public static create(uid: IUser['_id'], rid: IRoom['_id']): OTRRoom | undefined { @@ -110,6 +115,35 @@ export class OTRRoom implements IOTRRoom { } } + onPresenceEvent(event: UserPresence | undefined): void { + if (!event) { + return; + } + if (event.status !== UserStatus.OFFLINE) { + return; + } + console.warn(`OTR Room ${this._roomId} ended because ${this.peerId} went offline`); + this.end(); + + imperativeModal.open({ + component: GenericModal, + props: { + variant: 'warning', + title: t('OTR'), + children: t('OTR_Session_ended_other_user_went_offline', { username: event.username }), + confirmText: t('Ok'), + onClose: imperativeModal.close, + onConfirm: imperativeModal.close, + }, + }); + } + + // Starts listening to other user's status changes and end OTR if any of the Users goes offline + // this should be called in 2 places: on acknowledge (meaning user accepted OTR) or on establish (meaning user initiated OTR) + listenToUserStatus(): void { + Presence.listen(this.peerId, this.onPresenceEventHook); + } + acknowledge(): void { void sdk.rest.post('/v1/statistics.telemetry', { params: [{ eventName: 'otrStats', timestamp: Date.now(), rid: this._roomId }] }); @@ -137,10 +171,19 @@ export class OTRRoom implements IOTRRoom { ]); } + softReset(): void { + this.isFirstOTR = true; + this.setState(OtrRoomState.NOT_STARTED); + this._keyPair = null; + this._exportedPublicKey = {}; + this._sessionKey = null; + } + end(): void { this.isFirstOTR = true; this.reset(); this.setState(OtrRoomState.NOT_STARTED); + Presence.stop(this.peerId, this.onPresenceEventHook); sdk.publish('notify-user', [ `${this.peerId}/otr`, 'end', @@ -285,6 +328,7 @@ export class OTRRoom implements IOTRRoom { setTimeout(async () => { this.setState(OtrRoomState.ESTABLISHED); this.acknowledge(); + this.listenToUserStatus(); if (data.refresh) { await sdk.rest.post('/v1/chat.otr', { @@ -362,6 +406,7 @@ export class OTRRoom implements IOTRRoom { this.setState(OtrRoomState.ESTABLISHED); if (this.isFirstOTR) { + this.listenToUserStatus(); await sdk.rest.post('/v1/chat.otr', { roomId: this._roomId, type: otrSystemMessages.USER_JOINED_OTR, diff --git a/apps/meteor/app/otr/client/events.ts b/apps/meteor/app/otr/client/events.ts new file mode 100644 index 000000000000..9ff84c465157 --- /dev/null +++ b/apps/meteor/app/otr/client/events.ts @@ -0,0 +1,7 @@ +import { Accounts } from 'meteor/accounts-base'; + +import OTR from './OTR'; + +Accounts.onLogout(() => { + OTR.closeAllInstances(); +}); diff --git a/apps/meteor/app/otr/client/index.ts b/apps/meteor/app/otr/client/index.ts index 74fea3c003e8..fac7407f54fa 100644 --- a/apps/meteor/app/otr/client/index.ts +++ b/apps/meteor/app/otr/client/index.ts @@ -1,3 +1,4 @@ import './OTRRoom'; import './OTR'; import './messageTypes'; +import './events'; diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index b022a4bbe808..9c90020d94d0 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -4070,6 +4070,7 @@ "OTR_Enable_Description": "Enable option to use off-the-record (OTR) messages in direct messages between 2 users. OTR messages are not recorded on the server and exchanged directly and encrypted between the 2 users.", "OTR_message": "OTR Message", "OTR_is_only_available_when_both_users_are_online": "OTR is only available when both users are online", + "OTR_Session_ended_other_user_went_offline": "OTR Session has ended. User {{username}} went offline", "outbound-voip-calls": "Outbound Voip Calls", "outbound-voip-calls_description": "Permission to outbound voip calls", "Out_of_seats": "Out of Seats", From 209ea9f2c151ea1ffb5ab4d4c14bb78521cd9b4b Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Tue, 11 Jun 2024 12:27:25 -0300 Subject: [PATCH 02/94] regression: Disable animation on image gallery pagination transition (#32581) --- apps/meteor/client/components/ImageGallery/ImageGallery.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/client/components/ImageGallery/ImageGallery.tsx b/apps/meteor/client/components/ImageGallery/ImageGallery.tsx index 0fb31c5a2560..8dd69ab8fc25 100644 --- a/apps/meteor/client/components/ImageGallery/ImageGallery.tsx +++ b/apps/meteor/client/components/ImageGallery/ImageGallery.tsx @@ -176,7 +176,7 @@ export const ImageGallery = ({ images, onClose, loadMore }: { images: IUpload[]; modules={[Navigation, Zoom, Keyboard, A11y]} onInit={(swiper) => setSwiperInst(swiper)} onSlidesGridLengthChange={(swiper) => { - swiper.slideTo(images.length - gridSize, 2000); + swiper.slideTo(images.length - gridSize, 0); setGridSize(images.length); }} onReachBeginning={loadMore} From 108ec7f1a72ee344b0db61d52f61b9d8c0fa3563 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Tue, 11 Jun 2024 15:05:39 -0300 Subject: [PATCH 03/94] fix(Omnichannel): nonstop sound on current chats using continuous notifications (#32572) --- .changeset/thin-suns-invent.md | 5 +++++ .../client/views/room/body/hooks/useUnreadMessages.ts | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .changeset/thin-suns-invent.md diff --git a/.changeset/thin-suns-invent.md b/.changeset/thin-suns-invent.md new file mode 100644 index 000000000000..945f44420797 --- /dev/null +++ b/.changeset/thin-suns-invent.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes issues causing nonstop sound notification when taking a chat from the `Current Chats` view diff --git a/apps/meteor/client/views/room/body/hooks/useUnreadMessages.ts b/apps/meteor/client/views/room/body/hooks/useUnreadMessages.ts index 5e74164b7882..343b9cb88a98 100644 --- a/apps/meteor/client/views/room/body/hooks/useUnreadMessages.ts +++ b/apps/meteor/client/views/room/body/hooks/useUnreadMessages.ts @@ -93,9 +93,11 @@ export const useHandleUnread = ( const debouncedReadMessageRead = useMemo( () => withDebouncing({ wait: 500 })(() => { - chat.readStateManager.attemptMarkAsRead(); + if (subscribed) { + chat.readStateManager.attemptMarkAsRead(); + } }), - [chat.readStateManager], + [chat.readStateManager, subscribed], ); useEffect( From c4e59b9f5853478f9fa7bbd16b8c1b8b3487f2c4 Mon Sep 17 00:00:00 2001 From: csuadev <72958726+csuadev@users.noreply.github.com> Date: Tue, 11 Jun 2024 22:18:53 +0200 Subject: [PATCH 04/94] test: Add Omnichannel Business Hours E2E tests (#32303) --- .../omnichannel-business-hours.spec.ts | 139 ++++++++++++++++++ apps/meteor/tests/e2e/page-objects/index.ts | 1 + .../omnichannel-business-hours.ts | 67 +++++++++ .../e2e/utils/omnichannel/businessHours.ts | 47 ++++++ 4 files changed, 254 insertions(+) create mode 100644 apps/meteor/tests/e2e/omnichannel/omnichannel-business-hours.spec.ts create mode 100644 apps/meteor/tests/e2e/page-objects/omnichannel-business-hours.ts create mode 100644 apps/meteor/tests/e2e/utils/omnichannel/businessHours.ts diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-business-hours.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-business-hours.spec.ts new file mode 100644 index 000000000000..2c5dc162e509 --- /dev/null +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-business-hours.spec.ts @@ -0,0 +1,139 @@ +import { faker } from '@faker-js/faker'; +import type { Page } from '@playwright/test'; + +import { IS_EE } from '../config/constants'; +import { Users } from '../fixtures/userStates'; +import { OmnichannelBusinessHours } from '../page-objects'; +import { createAgent } from '../utils/omnichannel/agents'; +import { createBusinessHour } from '../utils/omnichannel/businessHours'; +import { createDepartment } from '../utils/omnichannel/departments'; +import { test, expect } from '../utils/test'; + +test.use({ storageState: Users.admin.state }); + +test.describe('OC - Business Hours', () => { + test.skip(!IS_EE, 'OC - Manage Business Hours > Enterprise Edition Only'); + + let poOmnichannelBusinessHours: OmnichannelBusinessHours; + let department: Awaited>; + let department2: Awaited>; + let agent: Awaited>; + + test.beforeAll(async ({ api }) => { + department = await createDepartment(api); + department2 = await createDepartment(api); + agent = await createAgent(api, 'user2'); + await api.post('/settings/Livechat_enable_business_hours', { value: true }).then((res) => expect(res.status()).toBe(200)); + await api.post('/settings/Livechat_business_hour_type', { value: 'Multiple' }).then((res) => expect(res.status()).toBe(200)); + }); + + test.afterAll(async ({ api }) => { + await department.delete(); + await department2.delete(); + await agent.delete(); + await api.post('/settings/Livechat_enable_business_hours', { value: false }).then((res) => expect(res.status()).toBe(200)); + await api.post('/settings/Livechat_business_hour_type', { value: 'Single' }).then((res) => expect(res.status()).toBe(200)); + }); + + test.beforeEach(async ({ page }: { page: Page }) => { + poOmnichannelBusinessHours = new OmnichannelBusinessHours(page); + }); + + test('OC - Manage Business Hours - Create Business Hours', async ({ page }) => { + const BHName = faker.string.uuid(); + + await page.goto('/omnichannel'); + await poOmnichannelBusinessHours.sidenav.linkBusinessHours.click(); + + await test.step('expect correct form default state', async () => { + await poOmnichannelBusinessHours.btnCreateBusinessHour.click(); + await poOmnichannelBusinessHours.btnBack.click(); + await expect(poOmnichannelBusinessHours.inputSearch).toBeVisible(); + }); + + await test.step('expect to create a new business hours', async () => { + await poOmnichannelBusinessHours.btnCreateBusinessHour.click(); + await poOmnichannelBusinessHours.inputName.fill(BHName); + await poOmnichannelBusinessHours.selectDepartment(department.data); + await poOmnichannelBusinessHours.btnSave.click(); + + await test.step('expect business hours to have been created', async () => { + await poOmnichannelBusinessHours.search(BHName); + await expect(poOmnichannelBusinessHours.findRowByName(BHName)).toBeVisible(); + }); + }); + + await test.step('expect to be able to delete business hours', async () => { + await test.step('expect to be able to cancel delete', async () => { + await poOmnichannelBusinessHours.btnDeleteByName(BHName).click(); + await expect(poOmnichannelBusinessHours.confirmDeleteModal).toBeVisible(); + await poOmnichannelBusinessHours.btnCancelDeleteModal.click(); + await expect(poOmnichannelBusinessHours.confirmDeleteModal).not.toBeVisible(); + }); + + await test.step('expect to confirm delete', async () => { + await poOmnichannelBusinessHours.btnDeleteByName(BHName).click(); + await expect(poOmnichannelBusinessHours.confirmDeleteModal).toBeVisible(); + await poOmnichannelBusinessHours.btnConfirmDeleteModal.click(); + await expect(poOmnichannelBusinessHours.confirmDeleteModal).not.toBeVisible(); + }); + }); + + await test.step('expect business hours to have been deleted', async () => { + await poOmnichannelBusinessHours.search(BHName); + await expect(poOmnichannelBusinessHours.findRowByName(BHName)).not.toBeVisible(); + }); + }); + + test('OC - Business hours - Edit BH departments', async ({ api, page }) => { + const BHName = faker.string.uuid(); + + await test.step('expect to create new businessHours', async () => { + const createBH = await createBusinessHour(api, { + id: '33', + name: BHName, + departments: [department.data._id], + }); + + expect(createBH.status()).toBe(200); + }); + + await page.goto('/omnichannel'); + await poOmnichannelBusinessHours.sidenav.linkBusinessHours.click(); + + await test.step('expect to add business hours departments', async () => { + await poOmnichannelBusinessHours.search(BHName); + await poOmnichannelBusinessHours.findRowByName(BHName).click(); + await poOmnichannelBusinessHours.selectDepartment({ name: department2.data.name, _id: department2.data._id }); + await poOmnichannelBusinessHours.btnSave.click(); + }); + + await test.step('expect department to be in the chosen departments list', async () => { + await poOmnichannelBusinessHours.search(BHName); + await poOmnichannelBusinessHours.findRowByName(BHName).click(); + await expect(page.getByRole('option', { name: department2.data.name })).toBeVisible(); + await poOmnichannelBusinessHours.btnBack.click(); + }); + + await test.step('expect to remove business hours departments', async () => { + await poOmnichannelBusinessHours.search(BHName); + await poOmnichannelBusinessHours.findRowByName(BHName).click(); + await poOmnichannelBusinessHours.selectDepartment({ name: department2.data.name, _id: department2.data._id }); + await poOmnichannelBusinessHours.btnSave.click(); + }); + + await test.step('expect department to not be in the chosen departments list', async () => { + await poOmnichannelBusinessHours.search(BHName); + await poOmnichannelBusinessHours.findRowByName(BHName).click(); + await expect(page.getByRole('option', { name: department2.data.name })).toBeHidden(); + await poOmnichannelBusinessHours.btnBack.click(); + }); + + await test.step('expect delete business hours', async () => { + await poOmnichannelBusinessHours.btnDeleteByName(BHName).click(); + await expect(poOmnichannelBusinessHours.confirmDeleteModal).toBeVisible(); + await poOmnichannelBusinessHours.btnConfirmDeleteModal.click(); + await expect(poOmnichannelBusinessHours.confirmDeleteModal).not.toBeVisible(); + }); + }); +}); diff --git a/apps/meteor/tests/e2e/page-objects/index.ts b/apps/meteor/tests/e2e/page-objects/index.ts index 5d8284fb420b..64126e4daed4 100644 --- a/apps/meteor/tests/e2e/page-objects/index.ts +++ b/apps/meteor/tests/e2e/page-objects/index.ts @@ -16,5 +16,6 @@ export * from './omnichannel-units'; export * from './home-omnichannel'; export * from './omnichannel-monitors'; export * from './omnichannel-settings'; +export * from './omnichannel-business-hours'; export * from './omnichannel-tags'; export * from './utils'; diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-business-hours.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-business-hours.ts new file mode 100644 index 000000000000..19e93cefb307 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-business-hours.ts @@ -0,0 +1,67 @@ +import type { Locator } from '@playwright/test'; + +import { OmnichannelAdministration } from './omnichannel-administration'; + +export class OmnichannelBusinessHours extends OmnichannelAdministration { + get btnCreateBusinessHour(): Locator { + return this.page.locator('header').locator('role=button[name="New"]'); + } + + get btnSave(): Locator { + return this.page.locator('role=button[name="Save"]'); + } + + get btnCancel(): Locator { + return this.page.locator('role=button[name="Cancel"]'); + } + + get btnBack(): Locator { + return this.page.locator('role=button[name="Back"]'); + } + + get inputSearch(): Locator { + return this.page.locator('[placeholder="Search"]'); + } + + get inputName(): Locator { + return this.page.locator('[name="name"]'); + } + + get inputDepartments(): Locator { + return this.page.locator('input[placeholder="Select an option"]'); + } + + findRowByName(name: string): Locator { + return this.page.locator(`tr:has-text("${name}")`); + } + + btnDeleteByName(name: string): Locator { + return this.page.locator(`tr:has-text("${name}") button[title="Remove"]`); + } + + get confirmDeleteModal(): Locator { + return this.page.locator('dialog:has(h2:has-text("Are you sure?"))'); + } + + get btnCancelDeleteModal(): Locator { + return this.confirmDeleteModal.locator('role=button[name="Cancel"]'); + } + + get btnConfirmDeleteModal(): Locator { + return this.confirmDeleteModal.locator('role=button[name="Delete"]'); + } + + private selectOption(name: string): Locator { + return this.page.locator(`[role=option][value="${name}"]`); + } + + async selectDepartment({ name, _id }: { name: string; _id: string }) { + await this.inputDepartments.click(); + await this.inputDepartments.fill(name); + await this.selectOption(_id).click(); + } + + async search(text: string) { + await this.inputSearch.fill(text); + } +} diff --git a/apps/meteor/tests/e2e/utils/omnichannel/businessHours.ts b/apps/meteor/tests/e2e/utils/omnichannel/businessHours.ts new file mode 100644 index 000000000000..7d4aced1e36c --- /dev/null +++ b/apps/meteor/tests/e2e/utils/omnichannel/businessHours.ts @@ -0,0 +1,47 @@ +import type { BaseTest } from '../test'; + +type CreateBusinessHoursParams = { + id?: string | null; + name?: string; + description?: string; + departments?: { departmentId: string }[]; +}; + +export const createBusinessHour = async (api: BaseTest['api'], { id = null, name, departments = [] }: CreateBusinessHoursParams = {}) => { + const departmentIds = departments.join(','); + + const response = await api.post('/method.call/livechat:saveBusinessHour', { + message: JSON.stringify({ + msg: 'method', + id: id || '33', + method: 'livechat:saveBusinessHour', + params: [ + { + name, + timezoneName: 'America/Sao_Paulo', + daysOpen: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], + daysTime: [ + { day: 'Monday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + { day: 'Tuesday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + { day: 'Wednesday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + { day: 'Thursday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + { day: 'Friday', start: { time: '08:00' }, finish: { time: '18:00' }, open: true }, + ], + departmentsToApplyBusinessHour: departmentIds, + active: true, + type: 'custom', + timezone: 'America/Sao_Paulo', + workHours: [ + { day: 'Monday', start: '08:00', finish: '18:00', open: true }, + { day: 'Tuesday', start: '08:00', finish: '18:00', open: true }, + { day: 'Wednesday', start: '08:00', finish: '18:00', open: true }, + { day: 'Thursday', start: '08:00', finish: '18:00', open: true }, + { day: 'Friday', start: '08:00', finish: '18:00', open: true }, + ], + }, + ], + }), + }); + + return response; +}; From 972ba42f43c2591df64ad9e40f3bd11d993c446a Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Wed, 12 Jun 2024 08:53:48 -0300 Subject: [PATCH 05/94] fix: Run QueryClient.clear() on logout (#32587) --- .changeset/fuzzy-readers-bake.md | 5 +++ .../providers/UserProvider/UserProvider.tsx | 7 +++-- ...mnichannel-enterprise-menus-logout.spec.ts | 31 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 .changeset/fuzzy-readers-bake.md create mode 100644 apps/meteor/tests/e2e/omnichannel/omnichannel-enterprise-menus-logout.spec.ts diff --git a/.changeset/fuzzy-readers-bake.md b/.changeset/fuzzy-readers-bake.md new file mode 100644 index 000000000000..a487096a312e --- /dev/null +++ b/.changeset/fuzzy-readers-bake.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes issues with loading license modules when loading the page while logged out diff --git a/apps/meteor/client/providers/UserProvider/UserProvider.tsx b/apps/meteor/client/providers/UserProvider/UserProvider.tsx index 27c540928e86..27bba21eae95 100644 --- a/apps/meteor/client/providers/UserProvider/UserProvider.tsx +++ b/apps/meteor/client/providers/UserProvider/UserProvider.tsx @@ -4,7 +4,7 @@ import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts'; import { UserContext, useEndpoint } from '@rocket.chat/ui-contexts'; import { Meteor } from 'meteor/meteor'; import type { ContextType, ReactElement, ReactNode } from 'react'; -import React, { useEffect, useMemo } from 'react'; +import React, { useEffect, useMemo, useRef } from 'react'; import { Subscriptions, ChatRoom } from '../../../app/models/client'; import { getUserPreference } from '../../../app/utils/client'; @@ -43,6 +43,7 @@ type UserProviderProps = { const UserProvider = ({ children }: UserProviderProps): ReactElement => { const userId = useReactiveValue(getUserId); + const previousUserId = useRef(userId); const user = useReactiveValue(getUser); const [userLanguage, setUserLanguage] = useLocalStorage('userLanguage', ''); const [preferedLanguage, setPreferedLanguage] = useLocalStorage('preferedLanguage', ''); @@ -94,9 +95,11 @@ const UserProvider = ({ children }: UserProviderProps): ReactElement => { }, [preferedLanguage, setPreferedLanguage, setUserLanguage, user?.language, userLanguage, userId, setUserPreferences]); useEffect(() => { - if (!userId) { + if (previousUserId.current && previousUserId.current !== userId) { queryClient.clear(); } + + previousUserId.current = userId; }, [userId]); return ; diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-enterprise-menus-logout.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-enterprise-menus-logout.spec.ts new file mode 100644 index 000000000000..057dd8bd73dc --- /dev/null +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-enterprise-menus-logout.spec.ts @@ -0,0 +1,31 @@ +import type { Page } from '@playwright/test'; + +import { ADMIN_CREDENTIALS, IS_EE } from '../config/constants'; +import injectInitialData from '../fixtures/inject-initial-data'; +import { test, expect } from '../utils/test'; + +test.describe('OC - Enterprise Menu Items After Relogin', () => { + // Create page object and redirect to home + test.beforeEach(async ({ page }: { page: Page }) => { + await page.goto('/omnichannel/current'); + + await page.locator('role=textbox[name=/username/i]').waitFor({ state: 'visible' }); + await page.locator('role=textbox[name=/username/i]').fill(ADMIN_CREDENTIALS.email); + await page.locator('[name=password]').fill(ADMIN_CREDENTIALS.password); + await page.locator('role=button[name="Login"]').click(); + + await page.locator('.main-content').waitFor(); + }); + + // Delete all data + test.afterAll(async () => { + await injectInitialData(); + }); + + test('OC - Enterprise Menu Items - Logout & Login', async ({ page }) => { + test.skip(!IS_EE); + await test.step('expect EE menu items to be visible', async () => { + await expect(page.locator('a[href="/omnichannel/tags"]')).toBeVisible(); + }); + }); +}); From 16b67aa0ff4f0d88be9208098e2a66cfe87b537c Mon Sep 17 00:00:00 2001 From: Gustavo Reis Bauer Date: Wed, 12 Jun 2024 11:10:26 -0300 Subject: [PATCH 06/94] feat: Limit of members that can be added using the autojoin feature in a team's channel to the value of the API_Users_Limit setting (#31859) Co-authored-by: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> --- .changeset/clean-moose-cover.md | 6 ++ .../channels/TeamsChannelItem.tsx | 5 +- .../channels/TeamsChannelItemMenu.tsx | 4 +- .../contextualBar/channels/TeamsChannels.tsx | 6 +- .../channels/TeamsChannelsWithData.tsx | 1 + .../channels/hooks/useToggleAutoJoin.tsx | 31 +++++++- apps/meteor/server/services/team/service.ts | 17 +++- apps/meteor/tests/data/teams.helper.ts | 13 ++- apps/meteor/tests/end-to-end/api/25-teams.js | 79 ++++++++++++++++++- packages/i18n/src/locales/en.i18n.json | 2 + 10 files changed, 148 insertions(+), 16 deletions(-) create mode 100644 .changeset/clean-moose-cover.md diff --git a/.changeset/clean-moose-cover.md b/.changeset/clean-moose-cover.md new file mode 100644 index 000000000000..39e6204ce9b4 --- /dev/null +++ b/.changeset/clean-moose-cover.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/i18n": minor +--- + +Introduced the use of the `API_User_Limit` setting to limit amount of members to simultaneously auto-join a room in a team diff --git a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.tsx b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.tsx index 981c65630d0a..01f92d38488c 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.tsx +++ b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.tsx @@ -22,11 +22,12 @@ import TeamsChannelItemMenu from './TeamsChannelItemMenu'; type TeamsChannelItemProps = { room: IRoom; + mainRoom: IRoom; onClickView: (room: IRoom) => void; reload: () => void; }; -const TeamsChannelItem = ({ room, onClickView, reload }: TeamsChannelItemProps) => { +const TeamsChannelItem = ({ room, mainRoom, onClickView, reload }: TeamsChannelItemProps) => { const t = useTranslation(); const rid = room._id; const type = room.t; @@ -68,7 +69,7 @@ const TeamsChannelItem = ({ room, onClickView, reload }: TeamsChannelItemProps) {(canRemoveTeamChannel || canEditTeamChannel || canDeleteTeamChannel) && ( - {showButton ? : } + {showButton ? : } )} diff --git a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItemMenu.tsx b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItemMenu.tsx index 54ee216eaaa0..97b1bdceb670 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItemMenu.tsx +++ b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItemMenu.tsx @@ -9,12 +9,12 @@ import { useDeleteRoom } from '../../../hooks/roomActions/useDeleteRoom'; import { useRemoveRoomFromTeam } from './hooks/useRemoveRoomFromTeam'; import { useToggleAutoJoin } from './hooks/useToggleAutoJoin'; -const TeamsChannelItemMenu = ({ room, reload }: { room: IRoom; reload?: () => void }) => { +const TeamsChannelItemMenu = ({ room, mainRoom, reload }: { room: IRoom; mainRoom: IRoom; reload?: () => void }) => { const t = useTranslation(); const { handleRemoveRoom, canRemoveTeamChannel } = useRemoveRoomFromTeam(room, { reload }); const { handleDelete, canDeleteRoom } = useDeleteRoom(room, { reload }); - const { handleToggleAutoJoin, canEditTeamChannel } = useToggleAutoJoin(room, { reload }); + const { handleToggleAutoJoin, canEditTeamChannel } = useToggleAutoJoin(room, { reload, mainRoom }); const toggleAutoJoin = { id: 'toggleAutoJoin', diff --git a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx index 6d0bfddd8610..d82dd19b1af8 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx +++ b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.tsx @@ -23,6 +23,7 @@ import TeamsChannelItem from './TeamsChannelItem'; type TeamsChannelsProps = { loading: boolean; channels: IRoom[]; + mainRoom: IRoom; text: string; type: 'all' | 'autoJoin'; setType: Dispatch>; @@ -39,6 +40,7 @@ type TeamsChannelsProps = { const TeamsChannels = ({ loading, channels = [], + mainRoom, text, type, setText, @@ -123,7 +125,9 @@ const TeamsChannels = ({ data={channels} // eslint-disable-next-line react/no-multi-comp components={{ Scroller: VirtuosoScrollbars, Footer: () => }} - itemContent={(index, data) => } + itemContent={(index, data) => ( + + )} /> diff --git a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelsWithData.tsx b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelsWithData.tsx index 965414400ee5..a886479b535b 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelsWithData.tsx +++ b/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelsWithData.tsx @@ -54,6 +54,7 @@ const TeamsChannelsWithData = () => { return ( void }) => { +import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator'; + +export const useToggleAutoJoin = (room: IRoom, { reload, mainRoom }: { reload?: () => void; mainRoom: IRoom }) => { const dispatchToastMessage = useToastMessageDispatch(); const updateRoomEndpoint = useEndpoint('POST', '/v1/teams.updateRoom'); const canEditTeamChannel = usePermission('edit-team-channel', room._id); + const maxNumberOfAutoJoinMembers = useSetting('API_User_Limit'); const handleToggleAutoJoin = async () => { + // Sanity check, the setting has a default value, therefore it should always be defined + if (!maxNumberOfAutoJoinMembers) { + return; + } + try { - await updateRoomEndpoint({ + const { room: updatedRoom } = await updateRoomEndpoint({ roomId: room._id, isDefault: !room.teamDefault, }); - dispatchToastMessage({ type: 'success', message: room.teamDefault ? 'channel set as non autojoin' : 'channel set as autojoin' }); + if (updatedRoom.teamDefault) { + // If the number of members in the mainRoom (the team) is greater than the limit, show an info message + // informing that not all members will be auto-joined to the channel + const messageType = mainRoom.usersCount > maxNumberOfAutoJoinMembers ? 'info' : 'success'; + const message = mainRoom.usersCount > maxNumberOfAutoJoinMembers ? 'Team_Auto-join_exceeded_user_limit' : 'Team_Auto-join_updated'; + + dispatchToastMessage({ + type: messageType, + message: t(message, { + channelName: roomCoordinator.getRoomName(room.t, room), + numberOfMembers: updatedRoom.usersCount, + limit: maxNumberOfAutoJoinMembers, + }), + }); + } reload?.(); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); diff --git a/apps/meteor/server/services/team/service.ts b/apps/meteor/server/services/team/service.ts index 71d403fd84b5..f81b21d7fa01 100644 --- a/apps/meteor/server/services/team/service.ts +++ b/apps/meteor/server/services/team/service.ts @@ -32,6 +32,7 @@ import { addUserToRoom } from '../../../app/lib/server/functions/addUserToRoom'; import { checkUsernameAvailability } from '../../../app/lib/server/functions/checkUsernameAvailability'; import { getSubscribedRoomsForUserWithDetails } from '../../../app/lib/server/functions/getRoomsWithSingleOwner'; import { removeUserFromRoom } from '../../../app/lib/server/functions/removeUserFromRoom'; +import { settings } from '../../../app/settings/server'; export class TeamService extends ServiceClassInternal implements ITeamService { protected name = 'team'; @@ -472,11 +473,21 @@ export class TeamService extends ServiceClassInternal implements ITeamService { room.teamDefault = isDefault; await Rooms.setTeamDefaultById(rid, isDefault); - if (room.teamDefault) { - const teamMembers = await this.members(uid, room.teamId, true, undefined, undefined); + if (isDefault) { + const maxNumberOfAutoJoinMembers = settings.get('API_User_Limit'); + const teamMembers = await this.members( + uid, + room.teamId, + true, + { offset: 0, count: maxNumberOfAutoJoinMembers }, + // We should not get the owner of the room, since he is already a member + { _id: { $ne: room.u._id } }, + ); for await (const m of teamMembers.records) { - await addUserToRoom(room._id, m.user, user); + if (await addUserToRoom(room._id, m.user, user)) { + room.usersCount++; + } } } diff --git a/apps/meteor/tests/data/teams.helper.ts b/apps/meteor/tests/data/teams.helper.ts index 308fc60f445e..62da06eea71a 100644 --- a/apps/meteor/tests/data/teams.helper.ts +++ b/apps/meteor/tests/data/teams.helper.ts @@ -1,5 +1,6 @@ import { ITeam, TEAM_TYPE } from "@rocket.chat/core-typings" import { api, request } from "./api-data" +import { IUser } from "@rocket.chat/apps-engine/definition/users"; export const createTeam = async (credentials: Record, teamName: string, type: TEAM_TYPE): Promise => { const response = await request.post(api('teams.create')).set(credentials).send({ @@ -14,4 +15,14 @@ export const deleteTeam = async (credentials: Record, teamName: str await request.post(api('teams.delete')).set(credentials).send({ teamName, }); -}; \ No newline at end of file +}; + +export const addMembers = async (credentials: Record, teamName: string, members: IUser['id'][]): Promise => { + await request + .post(api('teams.addMembers')) + .set(credentials) + .send({ + teamName: teamName, + members: members.map((userId) => ({ userId, roles: ['member'] })) + }); +}; diff --git a/apps/meteor/tests/end-to-end/api/25-teams.js b/apps/meteor/tests/end-to-end/api/25-teams.js index 34383e3aaa69..49a1d663aef2 100644 --- a/apps/meteor/tests/end-to-end/api/25-teams.js +++ b/apps/meteor/tests/end-to-end/api/25-teams.js @@ -1,11 +1,11 @@ import { TEAM_TYPE } from '@rocket.chat/core-typings'; import { expect } from 'chai'; -import { before, describe, it, after } from 'mocha'; +import { after, afterEach, before, beforeEach, describe, it } from 'mocha'; import { getCredentials, api, request, credentials, methodCall } from '../../data/api-data'; -import { updatePermission } from '../../data/permissions.helper'; +import { updatePermission, updateSetting } from '../../data/permissions.helper'; import { createRoom, deleteRoom } from '../../data/rooms.helper'; -import { createTeam, deleteTeam } from '../../data/teams.helper'; +import { addMembers, createTeam, deleteTeam } from '../../data/teams.helper'; import { adminUsername, password } from '../../data/user'; import { createUser, deleteUser, login } from '../../data/users.helper'; @@ -1594,6 +1594,79 @@ describe('[Teams]', () => { .end(done); }); }); + + describe('team auto-join', () => { + let testTeam; + let createdRoom; + let testUser1; + let testUser2; + + before(async () => { + const [testUserResult, testUser1Result] = await Promise.all([createUser(), createUser()]); + testUser1 = testUserResult; + testUser2 = testUser1Result; + }); + + beforeEach(async () => { + const createTeamPromise = createTeam(credentials, `test-team-name${Date.now()}`, 0); + const createRoomPromise = createRoom({ name: `test-room-name${Date.now()}`, type: 'c' }); + const [testTeamCreationResult, testRoomCreationResult] = await Promise.all([createTeamPromise, createRoomPromise]); + + testTeam = testTeamCreationResult; + createdRoom = testRoomCreationResult; + + await request + .post(api('teams.addRooms')) + .set(credentials) + .expect(200) + .send({ + rooms: [createdRoom.body.channel._id], + teamName: testTeam.name, + }); + }); + + afterEach(() => + Promise.all([deleteTeam(credentials, testTeam.name), deleteRoom({ roomId: createdRoom.body.channel._id, type: 'c' })]), + ); + + after(() => Promise.all([updateSetting('API_User_Limit', 500), deleteUser(testUser1), deleteUser(testUser2)])); + + it('should add members when the members count is less than or equal to the API_User_Limit setting', async () => { + await updateSetting('API_User_Limit', 2); + + await addMembers(credentials, testTeam.name, [testUser1._id, testUser2._id]); + await request + .post(api('teams.updateRoom')) + .set(credentials) + .send({ + roomId: createdRoom.body.channel._id, + isDefault: true, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('room.usersCount').and.to.be.equal(3); + }); + }); + + it('should not add all members when we update a team channel to be auto-join and the members count is greater than the API_User_Limit setting', async () => { + await updateSetting('API_User_Limit', 1); + + await addMembers(credentials, testTeam.name, [testUser1._id, testUser2._id]); + await request + .post(api('teams.updateRoom')) + .set(credentials) + .send({ + roomId: createdRoom.body.channel._id, + isDefault: true, + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.nested.property('room.usersCount').and.to.be.equal(2); + }); + }); + }); }); describe('/teams.removeRoom', () => { diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 9c90020d94d0..3a50e7d39df6 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -5127,6 +5127,8 @@ "Team_Add_existing_channels": "Add Existing Channels", "Team_Add_existing": "Add Existing", "Team_Auto-join": "Auto-join", + "Team_Auto-join_exceeded_user_limit": "Auto-join has a limit of {{limit}} members, #{{channelName}} now has {{numberOfMembers}} members", + "Team_Auto-join_updated": "#{{channelName}} now has {{numberOfMembers}} members", "Team_Channels": "Team Channels", "Team_Delete_Channel_modal_content_danger": "This can’t be undone.", "Team_Delete_Channel_modal_content": "Would you like to delete this Channel?", From 99de6d2ec4e98340971e39493b78e71b355fc7b1 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 12 Jun 2024 12:10:07 -0300 Subject: [PATCH 07/94] chore: disable db watchers on local envs (#32589) --- packages/core-services/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core-services/src/index.ts b/packages/core-services/src/index.ts index ccc936ad6ed5..ce51f4695aec 100644 --- a/packages/core-services/src/index.ts +++ b/packages/core-services/src/index.ts @@ -138,7 +138,8 @@ export { IUserService, }; -export const dbWatchersDisabled = ['yes', 'true'].includes(String(process.env.DISABLE_DB_WATCHERS).toLowerCase()); +export const dbWatchersDisabled = + ['yes', 'true'].includes(String(process.env.DISABLE_DB_WATCHERS).toLowerCase()) || process.env.NODE_ENV !== 'production'; // TODO think in a way to not have to pass the service name to proxify here as well export const Authorization = proxifyWithWait('authorization'); From bd9eb6ba84229e6dcf6429e36d939caf3f6d9b17 Mon Sep 17 00:00:00 2001 From: Gustavo Reis Bauer Date: Wed, 12 Jun 2024 14:14:27 -0300 Subject: [PATCH 08/94] chore: Add a way to remove an invalid token if sendFCM returns 404 (#32440) --- apps/meteor/app/push/server/fcm.ts | 38 ++++++++++++++++++------------ 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/meteor/app/push/server/fcm.ts b/apps/meteor/app/push/server/fcm.ts index 819e26e4f003..87ced6e130df 100644 --- a/apps/meteor/app/push/server/fcm.ts +++ b/apps/meteor/app/push/server/fcm.ts @@ -55,15 +55,17 @@ type FCMError = { }; /** - * Set at least a 10 second timeout on send requests before retrying. - * Most of FCM's internal Remote Procedure Calls use a 10 second timeout. + * Send a push notification using Firebase Cloud Messaging (FCM). + * implements the Firebase Cloud Messaging HTTP v1 API, and all of its retry logic, + * see: https://firebase.google.com/docs/reference/fcm/rest/v1/ErrorCode * * Errors: - * - For 400, 401, 403, 404 errors: abort, and do not retry. + * - For 400, 401, 403 errors: abort, and do not retry. + * - For 404 errors: remove the token from the database. * - For 429 errors: retry after waiting for the duration set in the retry-after header. If no retry-after header is set, default to 60 seconds. * - For 500 errors: retry with exponential backoff. */ -async function fetchWithRetry(url: string, options: RequestInit, retries = 0): Promise { +async function fetchWithRetry(url: string, _removeToken: () => void, options: RequestInit, retries = 0): Promise { const MAX_RETRIES = 5; const response = await fetch(url, options); @@ -79,15 +81,20 @@ async function fetchWithRetry(url: string, options: RequestInit, retries = 0): P const retryAfter = response.headers.get('retry-after'); const retryAfterSeconds = retryAfter ? parseInt(retryAfter, 10) : 60; + if (response.status === 404) { + _removeToken(); + return response; + } + if (response.status === 429) { await new Promise((resolve) => setTimeout(resolve, retryAfterSeconds * 1000)); - return fetchWithRetry(url, options, retries + 1); + return fetchWithRetry(url, _removeToken, options, retries + 1); } if (response.status >= 500 && response.status < 600) { const backoff = Math.pow(2, retries) * 10000; await new Promise((resolve) => setTimeout(resolve, backoff)); - return fetchWithRetry(url, options, retries + 1); + return fetchWithRetry(url, _removeToken, options, retries + 1); } const error: FCMError = await response.json(); @@ -145,12 +152,7 @@ function getFCMMessagesFromPushData(userTokens: string[], notification: PendingP return userTokens.map((token) => ({ message: { ...message, token } })); } -export const sendFCM = function ({ userTokens, notification, _replaceToken, _removeToken, options }: NativeNotificationParameters): void { - // We don't use these parameters, but we need to keep them to keep the function signature - // TODO: Remove them when we remove the old sendGCM function - _replaceToken; - _removeToken; - +export const sendFCM = function ({ userTokens, notification, _removeToken, options }: NativeNotificationParameters): void { const tokens = typeof userTokens === 'string' ? [userTokens] : userTokens; if (!tokens.length) { logger.log('sendFCM no push tokens found'); @@ -173,9 +175,15 @@ export const sendFCM = function ({ userTokens, notification, _replaceToken, _rem const url = `https://fcm.googleapis.com/v1/projects/${options.gcm.projectNumber}/messages:send`; - for (const message of messages) { - logger.debug('sendFCM message', message); - const response = fetchWithRetry(url, { method: 'POST', headers, body: JSON.stringify(message) }); + for (const fcmRequest of messages) { + logger.debug('sendFCM message', fcmRequest); + + const removeToken = () => { + const { token } = fcmRequest.message; + token && _removeToken({ gcm: token }); + }; + + const response = fetchWithRetry(url, removeToken, { method: 'POST', headers, body: JSON.stringify(fcmRequest) }); response.catch((err) => { logger.error('sendFCM error', err); From 9a27b427fe39d13bd003413ebef1e3e4a50f1952 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Wed, 12 Jun 2024 17:45:02 +0000 Subject: [PATCH 09/94] Bump 6.9.1 --- .changeset/bump-patch-1718214302828.md | 5 +++++ yarn.lock | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 .changeset/bump-patch-1718214302828.md diff --git a/.changeset/bump-patch-1718214302828.md b/.changeset/bump-patch-1718214302828.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1718214302828.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/yarn.lock b/yarn.lock index 8a3e588765df..2688eb2a0cf8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8795,10 +8795,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 3.0.0-rc.2 - "@rocket.chat/ui-contexts": 7.0.0-rc.2 - "@rocket.chat/ui-kit": 0.34.0-rc.0 - "@rocket.chat/ui-video-conf": 7.0.0-rc.2 + "@rocket.chat/ui-avatar": 3.0.0 + "@rocket.chat/ui-contexts": 7.0.0 + "@rocket.chat/ui-kit": 0.34.0 + "@rocket.chat/ui-video-conf": 7.0.0 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -8887,8 +8887,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 7.0.0-rc.2 - "@rocket.chat/ui-contexts": 7.0.0-rc.2 + "@rocket.chat/ui-client": 7.0.0 + "@rocket.chat/ui-contexts": 7.0.0 katex: "*" react: "*" languageName: unknown @@ -10106,7 +10106,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 7.0.0-rc.2 + "@rocket.chat/ui-contexts": 7.0.0 react: ~17.0.2 languageName: unknown linkType: soft @@ -10159,7 +10159,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 7.0.0-rc.2 + "@rocket.chat/ui-contexts": 7.0.0 react: ~17.0.2 languageName: unknown linkType: soft @@ -10335,8 +10335,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 3.0.0-rc.2 - "@rocket.chat/ui-contexts": 7.0.0-rc.2 + "@rocket.chat/ui-avatar": 3.0.0 + "@rocket.chat/ui-contexts": 7.0.0 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10426,7 +10426,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.1 - "@rocket.chat/ui-contexts": 7.0.0-rc.2 + "@rocket.chat/ui-contexts": 7.0.0 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 83635aa4f0038e647a4cf08e699562b5f0544256 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:13:01 +0000 Subject: [PATCH 10/94] fix: Run QueryClient.clear() on logout (#32591) Co-authored-by: Martin Schoeler <20868078+MartinSchoeler@users.noreply.github.com> --- .changeset/fuzzy-readers-bake.md | 5 +++ .../providers/UserProvider/UserProvider.tsx | 7 +++-- ...mnichannel-enterprise-menus-logout.spec.ts | 31 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 .changeset/fuzzy-readers-bake.md create mode 100644 apps/meteor/tests/e2e/omnichannel/omnichannel-enterprise-menus-logout.spec.ts diff --git a/.changeset/fuzzy-readers-bake.md b/.changeset/fuzzy-readers-bake.md new file mode 100644 index 000000000000..a487096a312e --- /dev/null +++ b/.changeset/fuzzy-readers-bake.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes issues with loading license modules when loading the page while logged out diff --git a/apps/meteor/client/providers/UserProvider/UserProvider.tsx b/apps/meteor/client/providers/UserProvider/UserProvider.tsx index 27c540928e86..27bba21eae95 100644 --- a/apps/meteor/client/providers/UserProvider/UserProvider.tsx +++ b/apps/meteor/client/providers/UserProvider/UserProvider.tsx @@ -4,7 +4,7 @@ import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts'; import { UserContext, useEndpoint } from '@rocket.chat/ui-contexts'; import { Meteor } from 'meteor/meteor'; import type { ContextType, ReactElement, ReactNode } from 'react'; -import React, { useEffect, useMemo } from 'react'; +import React, { useEffect, useMemo, useRef } from 'react'; import { Subscriptions, ChatRoom } from '../../../app/models/client'; import { getUserPreference } from '../../../app/utils/client'; @@ -43,6 +43,7 @@ type UserProviderProps = { const UserProvider = ({ children }: UserProviderProps): ReactElement => { const userId = useReactiveValue(getUserId); + const previousUserId = useRef(userId); const user = useReactiveValue(getUser); const [userLanguage, setUserLanguage] = useLocalStorage('userLanguage', ''); const [preferedLanguage, setPreferedLanguage] = useLocalStorage('preferedLanguage', ''); @@ -94,9 +95,11 @@ const UserProvider = ({ children }: UserProviderProps): ReactElement => { }, [preferedLanguage, setPreferedLanguage, setUserLanguage, user?.language, userLanguage, userId, setUserPreferences]); useEffect(() => { - if (!userId) { + if (previousUserId.current && previousUserId.current !== userId) { queryClient.clear(); } + + previousUserId.current = userId; }, [userId]); return ; diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-enterprise-menus-logout.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-enterprise-menus-logout.spec.ts new file mode 100644 index 000000000000..057dd8bd73dc --- /dev/null +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-enterprise-menus-logout.spec.ts @@ -0,0 +1,31 @@ +import type { Page } from '@playwright/test'; + +import { ADMIN_CREDENTIALS, IS_EE } from '../config/constants'; +import injectInitialData from '../fixtures/inject-initial-data'; +import { test, expect } from '../utils/test'; + +test.describe('OC - Enterprise Menu Items After Relogin', () => { + // Create page object and redirect to home + test.beforeEach(async ({ page }: { page: Page }) => { + await page.goto('/omnichannel/current'); + + await page.locator('role=textbox[name=/username/i]').waitFor({ state: 'visible' }); + await page.locator('role=textbox[name=/username/i]').fill(ADMIN_CREDENTIALS.email); + await page.locator('[name=password]').fill(ADMIN_CREDENTIALS.password); + await page.locator('role=button[name="Login"]').click(); + + await page.locator('.main-content').waitFor(); + }); + + // Delete all data + test.afterAll(async () => { + await injectInitialData(); + }); + + test('OC - Enterprise Menu Items - Logout & Login', async ({ page }) => { + test.skip(!IS_EE); + await test.step('expect EE menu items to be visible', async () => { + await expect(page.locator('a[href="/omnichannel/tags"]')).toBeVisible(); + }); + }); +}); From 4dd2e62c74f641b1a28cf25ef683c83f3d89919d Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:56:03 +0000 Subject: [PATCH 11/94] fix(Omnichannel): nonstop sound on current chats using continuous notifications (#32588) Co-authored-by: Martin Schoeler <20868078+MartinSchoeler@users.noreply.github.com> --- .changeset/thin-suns-invent.md | 5 +++++ .../client/views/room/body/hooks/useUnreadMessages.ts | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .changeset/thin-suns-invent.md diff --git a/.changeset/thin-suns-invent.md b/.changeset/thin-suns-invent.md new file mode 100644 index 000000000000..945f44420797 --- /dev/null +++ b/.changeset/thin-suns-invent.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes issues causing nonstop sound notification when taking a chat from the `Current Chats` view diff --git a/apps/meteor/client/views/room/body/hooks/useUnreadMessages.ts b/apps/meteor/client/views/room/body/hooks/useUnreadMessages.ts index 5e74164b7882..343b9cb88a98 100644 --- a/apps/meteor/client/views/room/body/hooks/useUnreadMessages.ts +++ b/apps/meteor/client/views/room/body/hooks/useUnreadMessages.ts @@ -93,9 +93,11 @@ export const useHandleUnread = ( const debouncedReadMessageRead = useMemo( () => withDebouncing({ wait: 500 })(() => { - chat.readStateManager.attemptMarkAsRead(); + if (subscribed) { + chat.readStateManager.attemptMarkAsRead(); + } }), - [chat.readStateManager], + [chat.readStateManager, subscribed], ); useEffect( From ce7282471e44bb581afcd5ca63c1788c926b4265 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Wed, 12 Jun 2024 19:25:38 +0000 Subject: [PATCH 12/94] Release 6.9.1 [no ci] --- .changeset/bump-patch-1718214302828.md | 5 --- .changeset/fuzzy-readers-bake.md | 5 --- .changeset/thin-suns-invent.md | 5 --- apps/meteor/CHANGELOG.md | 38 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 +++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 +++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 +++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 15 ++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 +++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 +++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 +++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 ++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/api-client/CHANGELOG.md | 10 +++++ ee/packages/api-client/package.json | 2 +- ee/packages/ddp-client/CHANGELOG.md | 10 +++++ ee/packages/ddp-client/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 +++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 +++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 +++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 ++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/apps/CHANGELOG.md | 10 +++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 ++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 + packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 +++++ packages/cron/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 +++++++ packages/fuselage-ui-kit/package.json | 10 ++--- packages/gazzodown/CHANGELOG.md | 11 ++++++ packages/gazzodown/package.json | 6 +-- packages/instance-status/CHANGELOG.md | 9 +++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 +++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 +++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 +++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 +++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 +++++ packages/ui-avatar/package.json | 4 +- packages/ui-client/CHANGELOG.md | 9 +++++ packages/ui-client/package.json | 4 +- packages/ui-contexts/CHANGELOG.md | 11 ++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 +++++ packages/ui-video-conf/package.json | 6 +-- packages/uikit-playground/CHANGELOG.md | 11 ++++++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 9 +++++ packages/web-ui-registration/package.json | 4 +- 69 files changed, 413 insertions(+), 60 deletions(-) delete mode 100644 .changeset/bump-patch-1718214302828.md delete mode 100644 .changeset/fuzzy-readers-bake.md delete mode 100644 .changeset/thin-suns-invent.md diff --git a/.changeset/bump-patch-1718214302828.md b/.changeset/bump-patch-1718214302828.md deleted file mode 100644 index e1eaa7980afb..000000000000 --- a/.changeset/bump-patch-1718214302828.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Bump @rocket.chat/meteor version. diff --git a/.changeset/fuzzy-readers-bake.md b/.changeset/fuzzy-readers-bake.md deleted file mode 100644 index a487096a312e..000000000000 --- a/.changeset/fuzzy-readers-bake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes issues with loading license modules when loading the page while logged out diff --git a/.changeset/thin-suns-invent.md b/.changeset/thin-suns-invent.md deleted file mode 100644 index 945f44420797..000000000000 --- a/.changeset/thin-suns-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes issues causing nonstop sound notification when taking a chat from the `Current Chats` view diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index 1f1b39852c7b..01f03feede53 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,43 @@ # @rocket.chat/meteor +## 6.9.1 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- Bump @rocket.chat/meteor version. + +- ([#32591](https://github.com/RocketChat/Rocket.Chat/pull/32591) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixes issues with loading license modules when loading the page while logged out + +- ([#32588](https://github.com/RocketChat/Rocket.Chat/pull/32588) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixes issues causing nonstop sound notification when taking a chat from the `Current Chats` view + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/rest-typings@6.9.1 + - @rocket.chat/api-client@0.1.34 + - @rocket.chat/license@0.1.16 + - @rocket.chat/omnichannel-services@0.1.16 + - @rocket.chat/pdf-worker@0.0.40 + - @rocket.chat/presence@0.1.16 + - @rocket.chat/apps@0.0.7 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/cron@0.0.36 + - @rocket.chat/fuselage-ui-kit@7.0.1 + - @rocket.chat/gazzodown@7.0.1 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/ui-contexts@7.0.1 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.0.40 + - @rocket.chat/ui-theming@0.1.2 + - @rocket.chat/ui-avatar@3.0.1 + - @rocket.chat/ui-client@7.0.1 + - @rocket.chat/ui-video-conf@7.0.1 + - @rocket.chat/web-ui-registration@7.0.1 + - @rocket.chat/instance-status@0.0.40 +
+ ## 6.9.0 ### Minor Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index 4665efe41ce2..0d691fdac398 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.9.0" + "version": "6.9.1" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 9436cdfd7f00..45f79ddff653 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.1.34 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/rest-typings@6.9.1 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/models@0.0.40 +
+ ## 1.1.33 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index c2119b1d3b24..d06f186c54d2 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.1.33", + "version": "1.1.34", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 77120b4c9a70..90fb64ffd9b2 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.9.0", + "version": "6.9.1", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 39eaf3f73387..280a3aa42d85 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.3.15 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/rest-typings@6.9.1 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/models@0.0.40 +
+ ## 0.3.14 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 6abc5aa783bc..4dfcfddf52f8 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.3.14", + "version": "0.3.15", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index fd73dae11270..154195b03b36 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.3.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/rest-typings@6.9.1 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/models@0.0.40 +
+ ## 0.3.15 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 61de30257359..fce4a93c8095 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.3.15", + "version": "0.3.16", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 75409b275c32..9d873f7c8c5d 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/ddp-streamer +## 0.2.15 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/rest-typings@6.9.1 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/ui-contexts@7.0.1 + - @rocket.chat/models@0.0.40 + - @rocket.chat/instance-status@0.0.40 +
+ ## 0.2.14 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index c1dd482d2e75..65f1c4c8771c 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.2.14", + "version": "0.2.15", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 1da1ca34fa23..134f9f227233 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.3.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/omnichannel-services@0.1.16 + - @rocket.chat/pdf-worker@0.0.40 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/models@0.0.40 +
+ ## 0.3.15 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 9705a4ca2e2c..ed1e72a2f255 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.3.15", + "version": "0.3.16", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index a90edcd821af..f7a1137542f3 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.3.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/presence@0.1.16 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/models@0.0.40 +
+ ## 0.3.15 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 129eae6f6f14..6bb46c544f57 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.3.15", + "version": "0.3.16", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 57508316acbf..d277d3c9b4cb 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.3.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/omnichannel-services@0.1.16 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/models@0.0.40 +
+ ## 0.3.15 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index d2f07cc5e312..8359965f43f8 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.3.15", + "version": "0.3.16", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 089b9c8fbd3c..bde0be97af7f 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.3.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/models@0.0.40 +
+ ## 0.3.15 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index a2ac2464c0aa..920f0ed1a18e 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.3.15", + "version": "0.3.16", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/api-client/CHANGELOG.md b/ee/packages/api-client/CHANGELOG.md index 62278200a94d..2d8287498da8 100644 --- a/ee/packages/api-client/CHANGELOG.md +++ b/ee/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.1.34 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/rest-typings@6.9.1 +
+ ## 0.1.33 ### Patch Changes diff --git a/ee/packages/api-client/package.json b/ee/packages/api-client/package.json index f4b22774490b..a31a69aed784 100644 --- a/ee/packages/api-client/package.json +++ b/ee/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.1.33", + "version": "0.1.34", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/ddp-client/CHANGELOG.md b/ee/packages/ddp-client/CHANGELOG.md index 8c64d0836416..38c87b8b935b 100644 --- a/ee/packages/ddp-client/CHANGELOG.md +++ b/ee/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ddp-client +## 0.2.25 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/rest-typings@6.9.1 + - @rocket.chat/api-client@0.1.34 +
+ ## 0.2.24 ### Patch Changes diff --git a/ee/packages/ddp-client/package.json b/ee/packages/ddp-client/package.json index cbf3bd20c52b..53a4e54e45bc 100644 --- a/ee/packages/ddp-client/package.json +++ b/ee/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.2.24", + "version": "0.2.25", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 80f539b4ed74..62511825e26d 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.1.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 +
+ ## 0.1.15 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 6dc46eea1cf8..d2e88d8baaf7 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.1.15", + "version": "0.1.16", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 15f0fb538132..1e632412860d 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.1.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/rest-typings@6.9.1 + - @rocket.chat/pdf-worker@0.0.40 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/model-typings@0.4.2 + - @rocket.chat/models@0.0.40 +
+ ## 0.1.15 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index bea077c18386..55abce301be6 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.1.15", + "version": "0.1.16", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index ee34d97dc362..6a48406ea25a 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.0.40 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 +
+ ## 0.0.39 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 71a94eee43b5..fdb192d4ada8 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.0.39", + "version": "0.0.40", "private": true, "devDependencies": { "@storybook/addon-essentials": "~6.5.16", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index e96a8365cd10..d3579b6166aa 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.1.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/core-services@0.3.16 + - @rocket.chat/models@0.0.40 +
+ ## 0.1.15 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 4e609c5d954b..2367b5968e0f 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.1.15", + "version": "0.1.16", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index b9e63ffa85af..c4e0e5f88083 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.9.0", + "version": "6.9.1", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index f58d8fbfe387..2d1d944b1ad2 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.0.7 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/model-typings@0.4.2 +
+ ## 0.0.6 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index ee99ba288fab..23103ffe2a28 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.0.6", + "version": "0.0.7", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index 779db0d7b4ca..929bc8b3147c 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.3.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/rest-typings@6.9.1 + - @rocket.chat/models@0.0.40 +
+ ## 0.3.15 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 6033814bf2fa..0d7dd248fa7e 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.3.15", + "version": "0.3.16", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index cb92dfed9f7f..fed7f005f13f 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.9.1 + ## 6.9.0 ### Minor Changes diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 492fb7be848b..0760888ba467 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.9.0", + "version": "6.9.1", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index b79a1aa46e9d..472bc38c0b03 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.0.36 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/models@0.0.40 +
+ ## 0.0.35 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index 1755e8a33a2b..4d6d7c999fd3 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.0.35", + "version": "0.0.36", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 21652a54903b..21714d28c544 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 7.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/gazzodown@7.0.1 + - @rocket.chat/ui-contexts@7.0.1 + - @rocket.chat/ui-avatar@3.0.1 + - @rocket.chat/ui-video-conf@7.0.1 +
+ ## 7.0.0 ### Minor Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 7a2fa548b145..87fd209fc567 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "7.0.0", + "version": "7.0.1", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "3.0.0", - "@rocket.chat/ui-contexts": "7.0.0", + "@rocket.chat/ui-avatar": "3.0.1", + "@rocket.chat/ui-contexts": "7.0.1", "@rocket.chat/ui-kit": "0.34.0", - "@rocket.chat/ui-video-conf": "7.0.0", + "@rocket.chat/ui-video-conf": "7.0.1", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" @@ -110,7 +110,7 @@ "typescript": "~5.3.3" }, "dependencies": { - "@rocket.chat/core-typings": "6.9.0", + "@rocket.chat/core-typings": "6.9.1", "@rocket.chat/gazzodown": "workspace:^", "@rocket.chat/ui-kit": "workspace:~", "tslib": "^2.5.3" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index 61620a5e7eb8..bba54175bf43 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 7.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/ui-contexts@7.0.1 + - @rocket.chat/ui-client@7.0.1 +
+ ## 7.0.0 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index fe7b6a0df3e2..023fa4975075 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "7.0.0", + "version": "7.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -71,8 +71,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "7.0.0", - "@rocket.chat/ui-contexts": "7.0.0", + "@rocket.chat/ui-client": "7.0.1", + "@rocket.chat/ui-contexts": "7.0.1", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index ef804a060a70..6b7d85d501e2 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.0.40 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.0.40 +
+ ## 0.0.39 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 1b9a81c6f432..d5a199a1b10c 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.0.39", + "version": "0.0.40", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index 05f50031910d..f7d7ed0299a9 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.17.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@7.0.1 +
+ ## 1.17.0 ### Minor Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index a47edd10bfce..123248dc3c17 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.17.0", + "version": "1.17.1", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index be6af1a7d7de..7c6fe4aebaa7 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.4.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 +
+ ## 0.4.1 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index dac38893963a..fdacc8878eff 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.4.1", + "version": "0.4.2", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 02e520ef1e9b..c572246539df 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.0.40 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.4.2 +
+ ## 0.0.39 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index 7280cb2e36d8..5d2eae9a49bc 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.0.39", + "version": "0.0.40", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index b2f584d33557..87ea17ff0985 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.9.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 +
+ ## 6.9.0 ### Minor Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 9f425ec9521d..864b4264b383 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.9.0", + "version": "6.9.1", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "@types/jest": "~29.5.7", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index 0d61eb6eb359..9617d88d5efa 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 3.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@7.0.1 +
+ ## 3.0.0 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 199129381457..bb0c167de8d9 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "3.0.0", + "version": "3.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "7.0.0", + "@rocket.chat/ui-contexts": "7.0.1", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 5f68202e7cb0..147cbf298895 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 7.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@7.0.1 +
+ ## 7.0.0 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 3e4dcac33f90..3c43d85aa0ef 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "7.0.0", + "version": "7.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -63,7 +63,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "7.0.0", + "@rocket.chat/ui-contexts": "7.0.1", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index 622a99d4d898..5d3fb186fb4d 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 7.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.1 + - @rocket.chat/rest-typings@6.9.1 + - @rocket.chat/ddp-client@0.2.25 +
+ ## 7.0.0 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 472d10708bfd..96d5d4bdf335 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "7.0.0", + "version": "7.0.1", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 50871b70ebd0..b56b9e522d6d 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 7.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@7.0.1 + - @rocket.chat/ui-avatar@3.0.1 +
+ ## 7.0.0 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 8f7b18f3ba2b..5398fe901457 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "7.0.0", + "version": "7.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -36,8 +36,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "3.0.0", - "@rocket.chat/ui-contexts": "7.0.0", + "@rocket.chat/ui-avatar": "3.0.1", + "@rocket.chat/ui-contexts": "7.0.1", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index 1de746cfaf6c..914f4a8c5941 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.2.24 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@7.0.1 + - @rocket.chat/ui-contexts@7.0.1 + - @rocket.chat/ui-avatar@3.0.1 +
+ ## 0.2.23 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index d12ece478b7c..3a63ac38a3ec 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.2.23", + "version": "0.2.24", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 16398fd01f1e..955775cb3873 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 7.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@7.0.1 +
+ ## 7.0.0 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 35bcc20bee17..837e150bbb0f 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "7.0.0", + "version": "7.0.1", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -51,7 +51,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.1", - "@rocket.chat/ui-contexts": "7.0.0", + "@rocket.chat/ui-contexts": "7.0.1", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From 65d16883dc606df032e5fc013644aac42a76e8d3 Mon Sep 17 00:00:00 2001 From: Gustavo Reis Bauer Date: Wed, 12 Jun 2024 17:55:12 -0300 Subject: [PATCH 13/94] test: Rewrote the rooms.helper file in typescript (#32556) --- apps/meteor/tests/data/rooms.helper.js | 118 ------------- apps/meteor/tests/data/rooms.helper.ts | 167 ++++++++++++++++++ apps/meteor/tests/data/uploads.helper.ts | 43 +++-- apps/meteor/tests/end-to-end/api/05-chat.js | 2 +- .../api/07-incoming-integrations.js | 2 +- .../tests/end-to-end/api/16-commands.js | 2 +- .../end-to-end/apps/05-video-conferences.ts | 4 +- 7 files changed, 197 insertions(+), 141 deletions(-) delete mode 100644 apps/meteor/tests/data/rooms.helper.js create mode 100644 apps/meteor/tests/data/rooms.helper.ts diff --git a/apps/meteor/tests/data/rooms.helper.js b/apps/meteor/tests/data/rooms.helper.js deleted file mode 100644 index 6e74509deab4..000000000000 --- a/apps/meteor/tests/data/rooms.helper.js +++ /dev/null @@ -1,118 +0,0 @@ -import { resolve } from 'path'; -import { api, credentials, request } from './api-data'; - -export const createRoom = ({ - name, - type, - username, - token, - agentId, - members, - credentials: customCredentials, - extraData, - voipCallDirection = 'inbound', -}) => { - if (!type) { - throw new Error('"type" is required in "createRoom.ts" test helper'); - } - if (type === 'v') { - /* Special handling for voip type of rooms. - * The endpoints below do not have a way to create - * a voip room. Hence creation of a voip room - * is handled separately here. - */ - return request - .get(api(`voip/room?token=${token}&agentId=${agentId}&direction=${voipCallDirection}`)) - .set(customCredentials || credentials) - .send(); - } - if (type === 'd' && !username) { - throw new Error('To be able to create DM Room, you must provide the username'); - } - const endpoints = { - c: 'channels.create', - p: 'groups.create', - d: 'im.create', - }; - const params = type === 'd' ? { username } : { name }; - - return request - .post(api(endpoints[type])) - .set(customCredentials || credentials) - .send({ - ...params, - ...(members && { members }), - ...(extraData && { extraData }), - }); -}; - -export const asyncCreateRoom = ({ name, type, username, members = [] }) => - new Promise((resolve) => { - createRoom({ name, type, username, members }).end(resolve); - }); - -function actionRoom({ action, type, roomId, overrideCredentials = credentials, extraData = {} }) { - if (!type) { - throw new Error(`"type" is required in "${action}Room" test helper`); - } - if (!roomId) { - throw new Error(`"roomId" is required in "${action}Room" test helper`); - } - const endpoints = { - c: 'channels', - p: 'groups', - d: 'im', - }; - return new Promise((resolve) => { - request - .post(api(`${endpoints[type]}.${action}`)) - .set(overrideCredentials) - .send({ - roomId, - ...extraData, - }) - .end(resolve); - }); -} - -export const deleteRoom = ({ type, roomId }) => actionRoom({ action: 'delete', type, roomId, overrideCredentials: credentials }); - -export const closeRoom = ({ type, roomId }) => actionRoom({ action: 'close', type, roomId }); - -export const joinChannel = ({ overrideCredentials = credentials, roomId }) => - request.post(api('channels.join')).set(overrideCredentials).send({ - roomId, - }); - -export const inviteToChannel = ({ overrideCredentials = credentials, roomId, userId }) => - request.post(api('channels.invite')).set(credentials).send({ - userId, - roomId, - }); - -export const addRoomOwner = ({ type, roomId, userId }) => actionRoom({ action: 'addOwner', type, roomId, extraData: { userId } }); - -export const removeRoomOwner = ({ type, roomId, userId }) => actionRoom({ action: 'removeOwner', type, roomId, extraData: { userId } }); - -export const getChannelRoles = async ({ roomId, overrideCredentials = credentials }) => - ( - await request.get(api('channels.roles')).set(overrideCredentials).query({ - roomId, - }) - ).body.roles; - -export const setRoomConfig = ({ roomId, favorite, isDefault }) => { - return request - .post(api('rooms.saveRoomSettings')) - .set(credentials) - .send({ - rid: roomId, - default: isDefault, - favorite: favorite - ? { - defaultValue: true, - favorite: false, - } - : undefined, - }); -}; diff --git a/apps/meteor/tests/data/rooms.helper.ts b/apps/meteor/tests/data/rooms.helper.ts new file mode 100644 index 000000000000..384ac5614e41 --- /dev/null +++ b/apps/meteor/tests/data/rooms.helper.ts @@ -0,0 +1,167 @@ +import type { IRoom } from '@rocket.chat/core-typings'; +import { api, credentials, request } from './api-data'; +import type { IUser } from '@rocket.chat/core-typings'; + +type Credentials = { 'X-Auth-Token'?: string; 'X-User-Id'?: string }; + +type CreateRoomParams = { + name?: IRoom['name']; + type: IRoom['t']; + username?: string; + token?: string; + agentId?: string; + members?: string[]; + credentials?: Credentials; + extraData?: Record; + voipCallDirection?: 'inbound' | 'outbound'; +}; + +export const createRoom = ({ + name, + type, + username, + token, + agentId, + members, + credentials: customCredentials, + extraData, + voipCallDirection = 'inbound', +}: CreateRoomParams) => { + if (!type) { + throw new Error('"type" is required in "createRoom.ts" test helper'); + } + + if (type === 'v') { + /* Special handling for voip type of rooms. + * The endpoints below do not have a way to create + * a voip room. Hence creation of a voip room + * is handled separately here. + */ + return request + .get(api(`voip/room?token=${token}&agentId=${agentId}&direction=${voipCallDirection}`)) + .set(customCredentials || credentials) + .send(); + } + + if (type === 'd' && !username) { + throw new Error('To be able to create DM Room, you must provide the username'); + } + + const endpoints = { + c: 'channels.create', + p: 'groups.create', + d: 'im.create', + }; + const params = type === 'd' ? { username } : { name }; + + // Safe assertion because we already checked the type is not 'v' + // which is the only case where type is not in the endpoints object + const roomType = endpoints[type as keyof typeof endpoints]; + + return request + .post(api(roomType)) + .set(customCredentials || credentials) + .send({ + ...params, + ...(members && { members }), + ...(extraData && { extraData }), + }); +}; + +export const asyncCreateRoom = ({ name, type, username, members = [] }: Pick) => + new Promise((resolve) => { + createRoom({ name, type, username, members }).end(resolve); + }); + +type ActionType = 'delete' | 'close' | 'addOwner' | 'removeOwner'; +type ActionRoomParams = { + action: ActionType; + type: Exclude; + roomId: IRoom['_id']; + overrideCredentials?: Credentials; + extraData?: Record; +}; + +function actionRoom({ action, type, roomId, overrideCredentials = credentials, extraData = {} }: ActionRoomParams) { + if (!type) { + throw new Error(`"type" is required in "${action}Room" test helper`); + } + if (!roomId) { + throw new Error(`"roomId" is required in "${action}Room" test helper`); + } + const endpoints = { + c: 'channels', + p: 'groups', + d: 'im', + }; + return new Promise((resolve) => { + request + .post(api(`${endpoints[type]}.${action}`)) + .set(overrideCredentials) + .send({ + roomId, + ...extraData, + }) + .end(resolve); + }); +} + +export const deleteRoom = ({ type, roomId }: { type: ActionRoomParams['type']; roomId: IRoom['_id'] }) => + actionRoom({ action: 'delete', type, roomId, overrideCredentials: credentials }); + +export const closeRoom = ({ type, roomId }: { type: ActionRoomParams['type']; roomId: IRoom['_id'] }) => + actionRoom({ action: 'close', type, roomId }); + +export const joinChannel = ({ overrideCredentials = credentials, roomId }: { overrideCredentials: Credentials; roomId: IRoom['_id'] }) => + request.post(api('channels.join')).set(overrideCredentials).send({ + roomId, + }); + +export const inviteToChannel = ({ + overrideCredentials = credentials, + roomId, + userId, +}: { + overrideCredentials: Credentials; + roomId: IRoom['_id']; + userId: IUser['_id']; +}) => + request.post(api('channels.invite')).set(overrideCredentials).send({ + userId, + roomId, + }); + +export const addRoomOwner = ({ type, roomId, userId }: { type: ActionRoomParams['type']; roomId: IRoom['_id']; userId: IUser['_id'] }) => + actionRoom({ action: 'addOwner', type, roomId, extraData: { userId } }); + +export const removeRoomOwner = ({ type, roomId, userId }: { type: ActionRoomParams['type']; roomId: IRoom['_id']; userId: IUser['_id'] }) => + actionRoom({ action: 'removeOwner', type, roomId, extraData: { userId } }); + +export const getChannelRoles = async ({ + roomId, + overrideCredentials = credentials, +}: { + roomId: IRoom['_id']; + overrideCredentials: Credentials; +}) => + ( + await request.get(api('channels.roles')).set(overrideCredentials).query({ + roomId, + }) + ).body.roles; + +export const setRoomConfig = ({ roomId, favorite, isDefault }: { roomId: IRoom['_id']; favorite: boolean; isDefault: boolean }) => { + return request + .post(api('rooms.saveRoomSettings')) + .set(credentials) + .send({ + rid: roomId, + default: isDefault, + favorite: favorite + ? { + defaultValue: true, + favorite: false, + } + : undefined, + }); +}; diff --git a/apps/meteor/tests/data/uploads.helper.ts b/apps/meteor/tests/data/uploads.helper.ts index eabd49e11a3b..5f6e4924d9ff 100644 --- a/apps/meteor/tests/data/uploads.helper.ts +++ b/apps/meteor/tests/data/uploads.helper.ts @@ -9,29 +9,38 @@ import { imgURL } from './interactions'; import { updateSetting } from './permissions.helper'; import { createRoom, deleteRoom } from './rooms.helper'; import { createVisitor } from './livechat/rooms'; - -export async function testFileUploads(filesEndpoint: 'channels.files' | 'groups.files' | 'im.files', roomType: 'c' | 'd' | 'p', invalidRoomError = 'error-room-not-found') { - let testRoom: Record; +import { IRoom } from '@rocket.chat/core-typings'; + +export async function testFileUploads( + filesEndpoint: 'channels.files' | 'groups.files' | 'im.files', + roomType: 'c' | 'd' | 'p', + invalidRoomError = 'error-room-not-found', +) { + let testRoom: IRoom; const propertyMap = { - 'c': 'channel', - 'p': 'group', - 'd': 'room', + c: 'channel', + p: 'group', + d: 'room', }; - before(async function () { - await updateSetting('VoIP_Enabled', true); - await updateSetting('Message_KeepHistory', true); + before(async () => { + await Promise.all([updateSetting('VoIP_Enabled', true), updateSetting('Message_KeepHistory', true)]); - testRoom = (await createRoom({ type: roomType, ...(roomType === 'd' ? { username: 'rocket.cat' } : { name: `channel-files-${Date.now()}` }) } as any)).body[propertyMap[roomType]]; + testRoom = ( + await createRoom({ + type: roomType, + ...(roomType === 'd' ? { username: 'rocket.cat' } : { name: `channel-files-${Date.now()}` }), + } as any) + ).body[propertyMap[roomType]]; }); - after(async function () { - await Promise.all([ - deleteRoom({ type: 'c', roomId: testRoom._id }), + after(() => + Promise.all([ + deleteRoom({ type: 'c' as const, roomId: testRoom._id }), updateSetting('VoIP_Enabled', false), updateSetting('Message_KeepHistory', false), - ]); - }); + ]), + ); const createVoipRoom = async function () { const testUser = await createUser({ roles: ['user', 'livechat-agent'] }); @@ -42,10 +51,6 @@ export async function testFileUploads(filesEndpoint: 'channels.files' | 'groups. type: 'v', agentId: testUser._id, credentials: testUserCredentials, - name: null, - username: null, - members: null, - extraData: null, }); return roomResponse.body.room; diff --git a/apps/meteor/tests/end-to-end/api/05-chat.js b/apps/meteor/tests/end-to-end/api/05-chat.js index fe02112c2811..96aa276e1a9c 100644 --- a/apps/meteor/tests/end-to-end/api/05-chat.js +++ b/apps/meteor/tests/end-to-end/api/05-chat.js @@ -5,7 +5,7 @@ import { getCredentials, api, request, credentials, message } from '../../data/a import { sendSimpleMessage, deleteMessage, pinMessage } from '../../data/chat.helper.js'; import { imgURL } from '../../data/interactions'; import { updatePermission, updateSetting } from '../../data/permissions.helper'; -import { createRoom, deleteRoom } from '../../data/rooms.helper.js'; +import { createRoom, deleteRoom } from '../../data/rooms.helper'; import { password } from '../../data/user'; import { createUser, deleteUser, login } from '../../data/users.helper'; diff --git a/apps/meteor/tests/end-to-end/api/07-incoming-integrations.js b/apps/meteor/tests/end-to-end/api/07-incoming-integrations.js index 37ce98ade6c5..7c325a9e3cd2 100644 --- a/apps/meteor/tests/end-to-end/api/07-incoming-integrations.js +++ b/apps/meteor/tests/end-to-end/api/07-incoming-integrations.js @@ -4,7 +4,7 @@ import { after, before, describe, it } from 'mocha'; import { getCredentials, api, request, credentials } from '../../data/api-data.js'; import { createIntegration, removeIntegration } from '../../data/integration.helper'; import { updatePermission } from '../../data/permissions.helper'; -import { createRoom, deleteRoom } from '../../data/rooms.helper.js'; +import { createRoom, deleteRoom } from '../../data/rooms.helper'; import { password } from '../../data/user'; import { createUser, deleteUser, login } from '../../data/users.helper'; diff --git a/apps/meteor/tests/end-to-end/api/16-commands.js b/apps/meteor/tests/end-to-end/api/16-commands.js index 74e9255524c4..c0781167b67f 100644 --- a/apps/meteor/tests/end-to-end/api/16-commands.js +++ b/apps/meteor/tests/end-to-end/api/16-commands.js @@ -3,7 +3,7 @@ import { before, describe, it, after } from 'mocha'; import { getCredentials, api, request, credentials } from '../../data/api-data.js'; import { sendSimpleMessage } from '../../data/chat.helper.js'; -import { createRoom, deleteRoom } from '../../data/rooms.helper.js'; +import { createRoom, deleteRoom } from '../../data/rooms.helper'; import { password } from '../../data/user'; import { createUser, deleteUser, login } from '../../data/users.helper.js'; diff --git a/apps/meteor/tests/end-to-end/apps/05-video-conferences.ts b/apps/meteor/tests/end-to-end/apps/05-video-conferences.ts index fb7f42ccdabd..d7772b7a233a 100644 --- a/apps/meteor/tests/end-to-end/apps/05-video-conferences.ts +++ b/apps/meteor/tests/end-to-end/apps/05-video-conferences.ts @@ -31,7 +31,9 @@ describe('Apps - Video Conferences', function () { roomId = res.body.group._id; }); - after(() => Promise.all([cleanupApps(), deleteRoom({ type: 'p', roomId }), updateSetting('VideoConf_Default_Provider', '')])); + after(() => + Promise.all([cleanupApps(), deleteRoom({ type: 'p', roomId: roomId as string }), updateSetting('VideoConf_Default_Provider', '')]), + ); describe('[With No App]', () => { before(async () => { From 4afd41cc604f97f1e19f70648dd4b8a66bee26b9 Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Thu, 13 Jun 2024 10:09:51 -0300 Subject: [PATCH 14/94] chore: change e2e password placeholder (#32569) --- apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx | 5 +++-- packages/i18n/src/locales/ar.i18n.json | 3 +-- packages/i18n/src/locales/ca.i18n.json | 3 +-- packages/i18n/src/locales/cs.i18n.json | 3 +-- packages/i18n/src/locales/da.i18n.json | 3 +-- packages/i18n/src/locales/de-IN.i18n.json | 3 +-- packages/i18n/src/locales/de.i18n.json | 3 +-- packages/i18n/src/locales/en.i18n.json | 7 ++++--- packages/i18n/src/locales/es.i18n.json | 3 +-- packages/i18n/src/locales/fi.i18n.json | 3 +-- packages/i18n/src/locales/fr.i18n.json | 3 +-- packages/i18n/src/locales/hr.i18n.json | 3 +-- packages/i18n/src/locales/hu.i18n.json | 3 +-- packages/i18n/src/locales/ja.i18n.json | 3 +-- packages/i18n/src/locales/ka-GE.i18n.json | 3 +-- packages/i18n/src/locales/km.i18n.json | 3 +-- packages/i18n/src/locales/ko.i18n.json | 3 +-- packages/i18n/src/locales/nl.i18n.json | 3 +-- packages/i18n/src/locales/pl.i18n.json | 3 +-- packages/i18n/src/locales/pt-BR.i18n.json | 7 ++++--- packages/i18n/src/locales/pt.i18n.json | 3 +-- packages/i18n/src/locales/ru.i18n.json | 3 +-- packages/i18n/src/locales/sv.i18n.json | 3 +-- packages/i18n/src/locales/tr.i18n.json | 3 +-- packages/i18n/src/locales/uk.i18n.json | 3 +-- packages/i18n/src/locales/zh-TW.i18n.json | 3 +-- packages/i18n/src/locales/zh.i18n.json | 3 +-- 27 files changed, 35 insertions(+), 56 deletions(-) diff --git a/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx b/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx index 161500da0cc3..711b5a6d21a1 100644 --- a/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx +++ b/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx @@ -42,8 +42,9 @@ const EnterE2EPasswordModal = ({ wrapperFunction={(props) => } variant='warning' title={t('Enter_E2E_password')} + icon='warning' cancelText={t('Do_It_Later')} - confirmText={t('Decode_Key')} + confirmText={t('Enable_encryption')} onClose={onClose} onCancel={onCancel} > @@ -51,7 +52,7 @@ const EnterE2EPasswordModal = ({ - + {passwordError} diff --git a/packages/i18n/src/locales/ar.i18n.json b/packages/i18n/src/locales/ar.i18n.json index 85dfe30a4839..5b011c5663e2 100644 --- a/packages/i18n/src/locales/ar.i18n.json +++ b/packages/i18n/src/locales/ar.i18n.json @@ -1331,7 +1331,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "الحد حسب المستخدم: الطلبات المسموح بها", "Deactivate": "إلغاء التنشيط", "Decline": "تراجع", - "Decode_Key": "مفتاح إلغاء التشفير", "Default": "افتراضي", "Default_value": "القيمة الافتراضية", "Delete": "حذف", @@ -4897,4 +4896,4 @@ "Enterprise": "مؤسسة", "UpgradeToGetMore_engagement-dashboard_Title": "التحليلات", "UpgradeToGetMore_auditing_Title": "تدقيق الرسائل" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/ca.i18n.json b/packages/i18n/src/locales/ca.i18n.json index 02908f809714..6c61025e16cf 100644 --- a/packages/i18n/src/locales/ca.i18n.json +++ b/packages/i18n/src/locales/ca.i18n.json @@ -1320,7 +1320,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Límit per usuari: peticions permeses", "Deactivate": "Desactivar", "Decline": "Rebutja", - "Decode_Key": "Clau de descodificació", "Default": "Per defecte", "Default_value": "Valor per defecte", "Delete": "Elimina", @@ -4696,4 +4695,4 @@ "Enterprise": "Empresa", "UpgradeToGetMore_engagement-dashboard_Title": "Analítiques", "UpgradeToGetMore_auditing_Title": "Auditoria de missatges" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/cs.i18n.json b/packages/i18n/src/locales/cs.i18n.json index a02152a66277..d122f1d89337 100644 --- a/packages/i18n/src/locales/cs.i18n.json +++ b/packages/i18n/src/locales/cs.i18n.json @@ -1131,7 +1131,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Limit podle uživatele: požadavky povoleny", "Deactivate": "Deaktivovat", "Decline": "Zamítnout", - "Decode_Key": "Dekódovat klíč", "Default": "Výchozí", "Default_value": "Výchozí hodnota", "Delete": "Smazat", @@ -3982,4 +3981,4 @@ "Enterprise": "Korporace", "UpgradeToGetMore_engagement-dashboard_Title": "Analytika", "UpgradeToGetMore_auditing_Title": "Audit zpráv" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/da.i18n.json b/packages/i18n/src/locales/da.i18n.json index 68f5b4a146d3..22183a5a0604 100644 --- a/packages/i18n/src/locales/da.i18n.json +++ b/packages/i18n/src/locales/da.i18n.json @@ -1210,7 +1210,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Begræns efter bruger: anmodninger tilladt", "Deactivate": "Deaktivér", "Decline": "Afslå", - "Decode_Key": "Afkodningsnøgle", "Default": "Standard", "Default_value": "Standardværdi", "Delete": "Slet", @@ -4097,4 +4096,4 @@ "Enterprise": "Firma", "UpgradeToGetMore_engagement-dashboard_Title": "Analyse", "UpgradeToGetMore_auditing_Title": "Meddelelsesovervågning" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/de-IN.i18n.json b/packages/i18n/src/locales/de-IN.i18n.json index 719cfe9da4fd..afb9dade56f5 100644 --- a/packages/i18n/src/locales/de-IN.i18n.json +++ b/packages/i18n/src/locales/de-IN.i18n.json @@ -931,7 +931,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Beschränkung durch Benutzer: Anforderungen zulässig", "Deactivate": "Deaktivieren", "Decline": "ablehnen", - "Decode_Key": "Entschlüsseln", "Default": "Voreinstellung", "Delete": "Löschen", "Delete_message": "Nachricht löschen", @@ -3099,4 +3098,4 @@ "Your_question": "Deine Frage", "Your_server_link": "Dein Server-Link", "Your_workspace_is_ready": "Dein Arbeitsbereich ist einsatzbereit 🎉" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/de.i18n.json b/packages/i18n/src/locales/de.i18n.json index ae2e193ec30e..b67d318f1176 100644 --- a/packages/i18n/src/locales/de.i18n.json +++ b/packages/i18n/src/locales/de.i18n.json @@ -1463,7 +1463,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Beschränkung durch Benutzer: Anforderungen zulässig", "Deactivate": "Deaktivieren", "Decline": "Ablehnen", - "Decode_Key": "Entschlüsseln", "default": "Standard", "Default": "Voreinstellung", "Default_provider": "Standardanbieter", @@ -5517,4 +5516,4 @@ "Enterprise": "Unternehmen", "UpgradeToGetMore_engagement-dashboard_Title": "Analytics", "UpgradeToGetMore_auditing_Title": "Nachrichtenüberprüfung" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 3a50e7d39df6..4e658735e130 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -1576,7 +1576,6 @@ "Deactivate": "Deactivate", "Deactivated": "Deactivated", "Decline": "Decline", - "Decode_Key": "Decode Key", "default": "default", "Default": "Default", "Default_provider": "Default provider", @@ -1798,7 +1797,7 @@ "E2E_Encryption_Password_Explanation": "You can now create encrypted private groups and direct messages. You may also change existing private groups or DMs to encrypted.

This is end-to-end encryption so the key to encode/decode your messages will not be saved on the server. For that reason you need to store your password somewhere safe. You will be required to enter it on other devices you wish to use e2e encryption on.", "E2E_key_reset_email": "E2E Key Reset Notification", "E2E_message_encrypted_placeholder": "This message is end-to-end encrypted. To view it, you must enter your encryption key in your account settings.", - "E2E_password_request_text": "To access your encrypted private groups and direct messages, enter your encryption password.
You need to enter this password to encode/decode your messages on every client you use, since the key is not stored on the server.", + "E2E_password_request_text": "To access your encrypted channels and direct messages, enter your encryption password. This is not stored on the server, so you’ll need to use it on every device.", "E2E_password_reveal_text": "Create secure private rooms and direct messages with end-to-end encryption. This password won’t be stored on the server. You can use it on all your devices.", "E2E_password_save_text": "This will only be displayed once, please save it now.", "E2E_Reset_Email_Content": "You've been automatically logged out. When you login again, Rocket.Chat will generate a new key and restore your access to any encrypted room that has one or more members online. Due to the nature of the E2E encryption, Rocket.Chat will not be able to restore access to any encrypted room that has no member online.", @@ -1925,6 +1924,7 @@ "Extra_CSP_Domains": "Extra CSP Domains", "Extra_CSP_Domains_Description": "Extra domains to add to the Content-Security-Policy", "Enable_Desktop_Notifications": "Enable Desktop Notifications", + "Enable_encryption" : "Enable encryption", "Enable_inquiry_fetch_by_stream": "Enable inquiry data fetch from server using a stream", "Enable_omnichannel_auto_close_abandoned_rooms": "Enable automatic closing of rooms abandoned by the visitor", "Enable_Password_History": "Enable Password History", @@ -1974,7 +1974,7 @@ "Enter_Behaviour": "Enter key Behaviour", "Enter_Behaviour_Description": "This changes if the enter key will send a message or do a line break", "Enter_code_here": "Enter code here", - "Enter_E2E_password": "Enter E2E password", + "Enter_E2E_password": "Enter E2EE password", "Enter_name_here": "Enter name here", "Enter_Normal": "Normal mode (send with Enter)", "Enter_the_code_we_just_emailed_you": "Enter the code we just emailed you.", @@ -4179,6 +4179,7 @@ "Please_enter_value_for_url": "Please enter a value for the url of your avatar.", "Please_enter_your_new_password_below": "Please enter your new password below:", "Please_enter_your_password": "Please enter your password", + "Please_enter_E2EE_password": "Please enter your E2EE password", "Please_fill_a_label": "Please fill a label", "Please_fill_a_name": "Please fill a name", "Please_fill_a_token_name": "Please fill a valid token name", diff --git a/packages/i18n/src/locales/es.i18n.json b/packages/i18n/src/locales/es.i18n.json index d79d3fa71cb1..bbaaff711afb 100644 --- a/packages/i18n/src/locales/es.i18n.json +++ b/packages/i18n/src/locales/es.i18n.json @@ -1336,7 +1336,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Limitar por usuario: solicitudes permitidas", "Deactivate": "Desactivar", "Decline": "Rechazar", - "Decode_Key": "Clave de decodificación", "Default": "Por defecto", "Default_value": "Valor por defecto", "Delete": "Eliminar", @@ -5095,4 +5094,4 @@ "Unlimited_seats": "Puestos ilimitados", "Unlimited_MACs": "Contactos Activos por Mes (MAC) ilimitados", "Unlimited_seats_MACs": "Puestos y Contactos Activos por Mes (MAC) ilimitados" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/fi.i18n.json b/packages/i18n/src/locales/fi.i18n.json index bfdc4b6f872c..a55af647ff04 100644 --- a/packages/i18n/src/locales/fi.i18n.json +++ b/packages/i18n/src/locales/fi.i18n.json @@ -1484,7 +1484,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Rajoitus käyttäjän mukaan: sallitut pyynnöt", "Deactivate": "Poista käytöstä", "Decline": "Hylkää", - "Decode_Key": "Purkuavain", "default": "oletus", "Default": "Oletus", "Default_provider": "Oletuspalveluntarjoaja", @@ -5755,4 +5754,4 @@ "Theme_Appearence": "Teeman ulkoasu", "Enterprise": "Yritys", "UpgradeToGetMore_engagement-dashboard_Title": "Analytics" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/fr.i18n.json b/packages/i18n/src/locales/fr.i18n.json index ff96989499f8..d5f92179372f 100644 --- a/packages/i18n/src/locales/fr.i18n.json +++ b/packages/i18n/src/locales/fr.i18n.json @@ -1333,7 +1333,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Limite par utilisateur : demandes autorisées", "Deactivate": "Désactiver", "Decline": "Refuser", - "Decode_Key": "Décoder la clé", "Default": "Défaut", "Default_value": "Valeur par défaut", "Delete": "Supprimer", @@ -4892,4 +4891,4 @@ "Enterprise": "Entreprise", "UpgradeToGetMore_engagement-dashboard_Title": "Analyses", "UpgradeToGetMore_auditing_Title": "Audit des messages" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/hr.i18n.json b/packages/i18n/src/locales/hr.i18n.json index 1228f11009fb..c1046fdac669 100644 --- a/packages/i18n/src/locales/hr.i18n.json +++ b/packages/i18n/src/locales/hr.i18n.json @@ -916,7 +916,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Ograniči po korisniku: dopušteni zahtjevi", "Deactivate": "Isključi", "Decline": "Odbij", - "Decode_Key": "Ključ za dekodiranje", "Default": "Zadano", "Delete": "Obriši", "Delete_message": "Obriši poruku", @@ -2904,4 +2903,4 @@ "registration.component.form.sendConfirmationEmail": "Pošalji potvrdni email", "Enterprise": "Poduzeće", "UpgradeToGetMore_engagement-dashboard_Title": "Analitika" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/hu.i18n.json b/packages/i18n/src/locales/hu.i18n.json index aebe30ba343d..74fa10105efd 100644 --- a/packages/i18n/src/locales/hu.i18n.json +++ b/packages/i18n/src/locales/hu.i18n.json @@ -1440,7 +1440,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Korlátozás felhasználó szerint: kérések engedélyezve", "Deactivate": "Inaktiválás", "Decline": "Elutasítás", - "Decode_Key": "Visszafejtő kulcs", "default": "alapértelmezett", "Default": "Alapértelmezett", "Default_value": "Alapértelmezett érték", @@ -5432,4 +5431,4 @@ "Enterprise": "Vállalati", "UpgradeToGetMore_engagement-dashboard_Title": "Analitika", "UpgradeToGetMore_auditing_Title": "Üzenet ellenőrzés" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/ja.i18n.json b/packages/i18n/src/locales/ja.i18n.json index 7000ad51998b..e976c9559a78 100644 --- a/packages/i18n/src/locales/ja.i18n.json +++ b/packages/i18n/src/locales/ja.i18n.json @@ -1314,7 +1314,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "ユーザーによる制限:許可された要求", "Deactivate": "無効にする", "Decline": "拒否", - "Decode_Key": "キーのデコード", "Default": "デフォルト", "Default_value": "デフォルト値", "Delete": "削除", @@ -4835,4 +4834,4 @@ "Enterprise": "エンタープライズ", "UpgradeToGetMore_engagement-dashboard_Title": "分析", "UpgradeToGetMore_auditing_Title": "メッセージ監査" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/ka-GE.i18n.json b/packages/i18n/src/locales/ka-GE.i18n.json index 7e28a9792559..ea1cde6e162e 100644 --- a/packages/i18n/src/locales/ka-GE.i18n.json +++ b/packages/i18n/src/locales/ka-GE.i18n.json @@ -1069,7 +1069,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "მომხმარებლის მიერ შეზღუდვა: მოთხოვნა დაშვებულია", "Deactivate": "გამორთვა", "Decline": "უარყოფა", - "Decode_Key": "დეკოდირების გასაღები", "Default": "ნაგულისხმევი (default)", "Default_value": "ნაგულისხმევი მნიშვნელობა", "Delete": "წაშლა", @@ -3683,4 +3682,4 @@ "onboarding.form.registerOfflineForm.title": "ხელით დარეგისტრირება", "UpgradeToGetMore_engagement-dashboard_Title": "ანალიტიკა", "UpgradeToGetMore_auditing_Title": "შეტყობინებების შემოწმება" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/km.i18n.json b/packages/i18n/src/locales/km.i18n.json index 6254254f89cf..cc6d2f815193 100644 --- a/packages/i18n/src/locales/km.i18n.json +++ b/packages/i18n/src/locales/km.i18n.json @@ -996,7 +996,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "កំណត់ដោយអ្នកប្រើ: ការស្នើសុំត្រូវបានអនុញ្ញាត", "Deactivate": "ធ្វើឲ្យមិនសកម្ម", "Decline": "បដិសេធ", - "Decode_Key": "សោរដោះលេខកូដ", "Default": "លំនាំដើម", "Default_value": "តម្លៃ​លំនាំដើម", "Delete": "លុប", @@ -3128,4 +3127,4 @@ "Enterprise": "សហគ្រាស", "UpgradeToGetMore_engagement-dashboard_Title": "វិភាគ", "UpgradeToGetMore_auditing_Title": "សវនកម្មសារ" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/ko.i18n.json b/packages/i18n/src/locales/ko.i18n.json index 49a542171868..b4b4ed006b47 100644 --- a/packages/i18n/src/locales/ko.i18n.json +++ b/packages/i18n/src/locales/ko.i18n.json @@ -1170,7 +1170,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "사용자 제한 : 요청 허용", "Deactivate": "비활성화", "Decline": "거절", - "Decode_Key": "복호화 키", "Default": "기본", "Default_value": "기본값", "Delete": "삭제", @@ -4040,4 +4039,4 @@ "Enterprise": "기업", "UpgradeToGetMore_engagement-dashboard_Title": "분석(에널리틱스)", "UpgradeToGetMore_auditing_Title": "메시지 감사" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/nl.i18n.json b/packages/i18n/src/locales/nl.i18n.json index 7665b7a4ea54..41052e0fe06e 100644 --- a/packages/i18n/src/locales/nl.i18n.json +++ b/packages/i18n/src/locales/nl.i18n.json @@ -1325,7 +1325,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Limiet per gebruiker: verzoeken toegestaan", "Deactivate": "Deactiveren", "Decline": "Weigeren", - "Decode_Key": "Decodeer sleutel", "Default": "Standaard", "Default_value": "Standaardwaarde", "Delete": "Verwijderen", @@ -4877,4 +4876,4 @@ "Enterprise": "Onderneming", "UpgradeToGetMore_engagement-dashboard_Title": "Analytics", "UpgradeToGetMore_auditing_Title": "Bericht auditing" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/pl.i18n.json b/packages/i18n/src/locales/pl.i18n.json index 0936ec845df1..27e8e712d978 100644 --- a/packages/i18n/src/locales/pl.i18n.json +++ b/packages/i18n/src/locales/pl.i18n.json @@ -1429,7 +1429,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Limit według użytkowników: dozwolone żądania", "Deactivate": "Dezaktywuj", "Decline": "Odrzuć", - "Decode_Key": "Klucz dekodowania", "default": "Domyślny", "Default": "Domyślny", "Default_value": "Domyślna wartość", @@ -5353,4 +5352,4 @@ "Enterprise": "Enterprise", "UpgradeToGetMore_engagement-dashboard_Title": "Analityka", "UpgradeToGetMore_auditing_Title": "Audyt wiadomości" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/pt-BR.i18n.json b/packages/i18n/src/locales/pt-BR.i18n.json index 0fecc1fa944a..2259e79d64d6 100644 --- a/packages/i18n/src/locales/pt-BR.i18n.json +++ b/packages/i18n/src/locales/pt-BR.i18n.json @@ -1372,7 +1372,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Limite por usuário: solicitações permitidas", "Deactivate": "Desativar", "Decline": "Recusar", - "Decode_Key": "Chave de decodificação", "Default": "Padrão", "Default_value": "Valor padrão", "Delete": "Excluir", @@ -1633,6 +1632,7 @@ "Enable_CSP": "Habilitar política de segurança de conteúdo", "Enable_CSP_Description": "Não desative esta opção a não ser que você tenha uma versão personalizada e esteja tendo problemas devido a scrips inline", "Enable_Desktop_Notifications": "Habilitar notificações da área de trabalho", + "Enable_encryption" : "Ativar criptografia", "Enable_inquiry_fetch_by_stream": "Habilitar carga de dados de novas pesquisas de omnichannel utilizando stream", "Enable_omnichannel_auto_close_abandoned_rooms": "Habilitar o fechamento automático de salas abandonadas pelo visitante", "Enable_Password_History": "Habilitar histórico de senha", @@ -1669,7 +1669,7 @@ "Enter_authentication_code": "Digite o código de autenticação", "Enter_Behaviour": "Insira o comportamento da tecla", "Enter_Behaviour_Description": "Muda se a tecla Enter enviará uma mensagem ou fará quebra de linha", - "Enter_E2E_password": "Entre com senha E2E", + "Enter_E2E_password": "Entre com senha E2EE", "Enter_name_here": "Insira o nome aqui", "Enter_Normal": "Modo normal (enviar com Enter)", "Enter_to": "Enter para", @@ -3380,6 +3380,7 @@ "Please_enter_value_for_url": "Insira um valor para o URL do seu avatar.", "Please_enter_your_new_password_below": "Digite sua nova senha abaixo:", "Please_enter_your_password": "Digite sua senha", + "Please_enter_E2EE_password": "Por favor, digite a senha de E2EE", "Please_fill_a_label": "Preencha um rótulo", "Please_fill_a_name": "Preencha um nome", "Please_fill_a_token_name": "Preencha um nome de token válido", @@ -5014,4 +5015,4 @@ "Enterprise": "Enterprise", "UpgradeToGetMore_engagement-dashboard_Title": "Analytics", "UpgradeToGetMore_auditing_Title": "Auditoria de mensagem" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/pt.i18n.json b/packages/i18n/src/locales/pt.i18n.json index 22dacb356003..3f9bfe543dcc 100644 --- a/packages/i18n/src/locales/pt.i18n.json +++ b/packages/i18n/src/locales/pt.i18n.json @@ -973,7 +973,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Limite por Usuário: Solicitações permitidas", "Deactivate": "Desactivar", "Decline": "Recusar", - "Decode_Key": "Chave de decodificação", "Default": "Padrão", "Delete": "Apagar", "Delete_message": "Apagar mensagem", @@ -3187,4 +3186,4 @@ "registration.component.form.sendConfirmationEmail": "Enviar email de confirmação", "Enterprise": "Empreendimento", "UpgradeToGetMore_engagement-dashboard_Title": "Analytics" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/ru.i18n.json b/packages/i18n/src/locales/ru.i18n.json index 9b4b31910ba4..3af2f4dfdf88 100644 --- a/packages/i18n/src/locales/ru.i18n.json +++ b/packages/i18n/src/locales/ru.i18n.json @@ -1444,7 +1444,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Ограничение по пользователю: запросы разрешены", "Deactivate": "Деактивировать", "Decline": "Отклонить", - "Decode_Key": "Код декодирования", "Default": "По умолчанию", "Default_value": "Значение по умолчанию", "Delete": "Удалить", @@ -5104,4 +5103,4 @@ "Enterprise": "Корпорация", "UpgradeToGetMore_engagement-dashboard_Title": "Аналитика", "UpgradeToGetMore_auditing_Title": "Аудит сообщений" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/sv.i18n.json b/packages/i18n/src/locales/sv.i18n.json index bea0ea1cb238..67f1912f25f0 100644 --- a/packages/i18n/src/locales/sv.i18n.json +++ b/packages/i18n/src/locales/sv.i18n.json @@ -1485,7 +1485,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Gräns per användare: förfrågningar tillåts", "Deactivate": "Inaktivera", "Decline": "Tacka nej", - "Decode_Key": "Avkodningsnyckel", "default": "standard", "Default": "Standard", "Default_provider": "Standardleverantör", @@ -5759,4 +5758,4 @@ "Theme_Appearence": "Utseende för tema", "Enterprise": "Enterprise", "UpgradeToGetMore_engagement-dashboard_Title": "Analytics" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/tr.i18n.json b/packages/i18n/src/locales/tr.i18n.json index 232b7eef4607..e8475e235715 100644 --- a/packages/i18n/src/locales/tr.i18n.json +++ b/packages/i18n/src/locales/tr.i18n.json @@ -976,7 +976,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Kullanıcı ile sınırlama: istekler izinli", "Deactivate": "Devre dışı bırak", "Decline": "Reddet", - "Decode_Key": "Kod Çözme Anahtarı", "Default": "Varsayılan", "Delete": "Sil", "Delete_all_closed_chats": "Tüm kapalı sohbetleri sil", @@ -3276,4 +3275,4 @@ "RegisterWorkspace_Features_Omnichannel_Title": "Çoklu Kanal", "Enterprise": "Kuruluş", "UpgradeToGetMore_engagement-dashboard_Title": "Mantıksal Analiz" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/uk.i18n.json b/packages/i18n/src/locales/uk.i18n.json index 7cf127f8c8bf..70dca33be576 100644 --- a/packages/i18n/src/locales/uk.i18n.json +++ b/packages/i18n/src/locales/uk.i18n.json @@ -1059,7 +1059,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "Обмеження по користувачу: запити дозволені", "Deactivate": "Деактивувати", "Decline": "Відхилити", - "Decode_Key": "Ключ декодування", "Default": "За замовчуванням", "Default_value": "Значення за замовчуванням", "Delete": "Видалити", @@ -3363,4 +3362,4 @@ "Enterprise": "Підприємство", "UpgradeToGetMore_engagement-dashboard_Title": "Аналітика", "UpgradeToGetMore_auditing_Title": "Аудит повідомлень" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/zh-TW.i18n.json b/packages/i18n/src/locales/zh-TW.i18n.json index dee0b0e801f4..93360b12c6b5 100644 --- a/packages/i18n/src/locales/zh-TW.i18n.json +++ b/packages/i18n/src/locales/zh-TW.i18n.json @@ -1312,7 +1312,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "限制使用者: 允許需求", "Deactivate": "停用", "Decline": "拒絕", - "Decode_Key": "解鎖金鑰", "Default": "預設", "Default_value": "預設值", "Delete": "刪除", @@ -4590,4 +4589,4 @@ "Enterprise": "企業", "UpgradeToGetMore_engagement-dashboard_Title": "分析", "UpgradeToGetMore_auditing_Title": "訊息稽核" -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/zh.i18n.json b/packages/i18n/src/locales/zh.i18n.json index 2c72cc0d4151..2445fd2b3b08 100644 --- a/packages/i18n/src/locales/zh.i18n.json +++ b/packages/i18n/src/locales/zh.i18n.json @@ -1191,7 +1191,6 @@ "DDP_Rate_Limit_User_Requests_Allowed": "用户限制: 允许请求", "Deactivate": "禁用", "Decline": "下降", - "Decode_Key": "解码密钥", "Default": "默认", "Default_value": "默认值", "Delete": "删除", @@ -4147,4 +4146,4 @@ "Enterprise": "企业", "UpgradeToGetMore_engagement-dashboard_Title": "分析", "UpgradeToGetMore_auditing_Title": "消息审计" -} \ No newline at end of file +} From 1056f220dfc2316cad7540f7f7f18d9b98b5b9cf Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Thu, 13 Jun 2024 10:50:51 -0300 Subject: [PATCH 15/94] fix: prevent OTR in E2EE (#32459) --- .changeset/famous-scissors-teach.md | 6 + .../roomActions/useE2EERoomAction.spec.ts | 122 ++++++++++++++++++ .../hooks/roomActions/useE2EERoomAction.ts | 13 +- apps/meteor/client/hooks/useOTR.spec.tsx | 70 ++++++++++ apps/meteor/client/hooks/useOTR.ts | 28 ++++ .../views/room/contextualBar/OTR/OTR.tsx | 22 +++- .../room/contextualBar/OTR/OTRWithData.tsx | 17 +-- apps/meteor/tests/e2e/e2e-encryption.spec.ts | 26 ++++ .../page-objects/fragments/home-flextab.ts | 4 + packages/i18n/src/locales/en.i18n.json | 3 + 10 files changed, 293 insertions(+), 18 deletions(-) create mode 100644 .changeset/famous-scissors-teach.md create mode 100644 apps/meteor/client/hooks/roomActions/useE2EERoomAction.spec.ts create mode 100644 apps/meteor/client/hooks/useOTR.spec.tsx create mode 100644 apps/meteor/client/hooks/useOTR.ts diff --git a/.changeset/famous-scissors-teach.md b/.changeset/famous-scissors-teach.md new file mode 100644 index 000000000000..05d4cbbf8ea5 --- /dev/null +++ b/.changeset/famous-scissors-teach.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/i18n": patch +--- + +Prevent usage of OTR messages with End-to-end Encryption, both feature shouldn't and can't work together. diff --git a/apps/meteor/client/hooks/roomActions/useE2EERoomAction.spec.ts b/apps/meteor/client/hooks/roomActions/useE2EERoomAction.spec.ts new file mode 100644 index 000000000000..eb0cbe5b24f4 --- /dev/null +++ b/apps/meteor/client/hooks/roomActions/useE2EERoomAction.spec.ts @@ -0,0 +1,122 @@ +import { useSetting, usePermission, useEndpoint } from '@rocket.chat/ui-contexts'; +import { act, renderHook } from '@testing-library/react-hooks'; + +import { E2EEState } from '../../../app/e2e/client/E2EEState'; +import { e2e } from '../../../app/e2e/client/rocketchat.e2e'; +import { OtrRoomState } from '../../../app/otr/lib/OtrRoomState'; +import { dispatchToastMessage } from '../../lib/toast'; +import { useRoom, useRoomSubscription } from '../../views/room/contexts/RoomContext'; +import { useE2EEState } from '../../views/room/hooks/useE2EEState'; +import { useOTR } from '../useOTR'; +import { useE2EERoomAction } from './useE2EERoomAction'; + +jest.mock('@rocket.chat/ui-contexts', () => ({ + useSetting: jest.fn(), + usePermission: jest.fn(), + useEndpoint: jest.fn(), +})); + +jest.mock('../../lib/toast', () => ({ + dispatchToastMessage: jest.fn(), +})); + +jest.mock('../../views/room/contexts/RoomContext', () => ({ + useRoom: jest.fn(), + useRoomSubscription: jest.fn(), +})); + +jest.mock('../useOTR', () => ({ + useOTR: jest.fn(), +})); + +jest.mock('../../../app/e2e/client/rocketchat.e2e', () => ({ + e2e: { + isReady: jest.fn(), + }, +})); + +jest.mock('../../views/room/hooks/useE2EEState', () => ({ + useE2EEState: jest.fn(), +})); + +jest.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key: string) => key, + }), +})); + +jest.mock('meteor/tracker', () => ({ + Tracker: { + autorun: jest.fn(), + }, +})); + +describe('useE2EERoomAction', () => { + const mockRoom = { _id: 'roomId', encrypted: false, t: 'd', name: 'Test Room' }; + const mockSubscription = { autoTranslate: false }; + + beforeEach(() => { + (useSetting as jest.Mock).mockReturnValue(true); + (useRoom as jest.Mock).mockReturnValue(mockRoom); + (useRoomSubscription as jest.Mock).mockReturnValue(mockSubscription); + (useE2EEState as jest.Mock).mockReturnValue(E2EEState.READY); + (usePermission as jest.Mock).mockReturnValue(true); + (useEndpoint as jest.Mock).mockReturnValue(jest.fn().mockResolvedValue({ success: true })); + (e2e.isReady as jest.Mock).mockReturnValue(true); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should dispatch error toast message when otrState is ESTABLISHED', async () => { + (useOTR as jest.Mock).mockReturnValue({ otrState: OtrRoomState.ESTABLISHED }); + + const { result } = renderHook(() => useE2EERoomAction()); + + await act(async () => { + await result?.current?.action?.(); + }); + + expect(dispatchToastMessage).toHaveBeenCalledWith({ type: 'error', message: 'E2EE_not_available_OTR' }); + }); + + it('should dispatch error toast message when otrState is ESTABLISHING', async () => { + (useOTR as jest.Mock).mockReturnValue({ otrState: OtrRoomState.ESTABLISHING }); + + const { result } = renderHook(() => useE2EERoomAction()); + + await act(async () => { + await result?.current?.action?.(); + }); + + expect(dispatchToastMessage).toHaveBeenCalledWith({ type: 'error', message: 'E2EE_not_available_OTR' }); + }); + + it('should dispatch error toast message when otrState is REQUESTED', async () => { + (useOTR as jest.Mock).mockReturnValue({ otrState: OtrRoomState.REQUESTED }); + + const { result } = renderHook(() => useE2EERoomAction()); + + await act(async () => { + await result?.current?.action?.(); + }); + + expect(dispatchToastMessage).toHaveBeenCalledWith({ type: 'error', message: 'E2EE_not_available_OTR' }); + }); + + it('should dispatch success toast message when encryption is enabled', async () => { + (useOTR as jest.Mock).mockReturnValue({ otrState: OtrRoomState.NOT_STARTED }); + + const { result } = renderHook(() => useE2EERoomAction()); + + await act(async () => { + await result?.current?.action?.(); + }); + + expect(dispatchToastMessage).toHaveBeenCalledWith({ + type: 'success', + message: 'E2E_Encryption_enabled_for_room', + }); + }); +}); diff --git a/apps/meteor/client/hooks/roomActions/useE2EERoomAction.ts b/apps/meteor/client/hooks/roomActions/useE2EERoomAction.ts index abc84f372594..bed73ab45c6b 100644 --- a/apps/meteor/client/hooks/roomActions/useE2EERoomAction.ts +++ b/apps/meteor/client/hooks/roomActions/useE2EERoomAction.ts @@ -1,14 +1,16 @@ import { isRoomFederated } from '@rocket.chat/core-typings'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useSetting, usePermission, useEndpoint } from '@rocket.chat/ui-contexts'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { E2EEState } from '../../../app/e2e/client/E2EEState'; +import { OtrRoomState } from '../../../app/otr/lib/OtrRoomState'; import { dispatchToastMessage } from '../../lib/toast'; import { useRoom, useRoomSubscription } from '../../views/room/contexts/RoomContext'; import type { RoomToolboxActionConfig } from '../../views/room/contexts/RoomToolboxContext'; import { useE2EEState } from '../../views/room/hooks/useE2EEState'; +import { useOTR } from '../useOTR'; export const useE2EERoomAction = () => { const enabled = useSetting('E2E_Enable', false); @@ -22,10 +24,17 @@ export const useE2EERoomAction = () => { const permitted = (room.t === 'd' || (permittedToEditRoom && permittedToToggleEncryption)) && readyToEncrypt; const federated = isRoomFederated(room); const { t } = useTranslation(); + const { otrState } = useOTR(); const toggleE2E = useEndpoint('POST', '/v1/rooms.saveRoomSettings'); - const action = useMutableCallback(async () => { + const action = useEffectEvent(async () => { + if (otrState === OtrRoomState.ESTABLISHED || otrState === OtrRoomState.ESTABLISHING || otrState === OtrRoomState.REQUESTED) { + dispatchToastMessage({ type: 'error', message: t('E2EE_not_available_OTR') }); + + return; + } + const { success } = await toggleE2E({ rid: room._id, encrypted: !room.encrypted }); if (!success) { return; diff --git a/apps/meteor/client/hooks/useOTR.spec.tsx b/apps/meteor/client/hooks/useOTR.spec.tsx new file mode 100644 index 000000000000..0206d96ca176 --- /dev/null +++ b/apps/meteor/client/hooks/useOTR.spec.tsx @@ -0,0 +1,70 @@ +import { useUserId } from '@rocket.chat/ui-contexts'; +import { renderHook } from '@testing-library/react-hooks'; + +import OTR from '../../app/otr/client/OTR'; +import { OtrRoomState } from '../../app/otr/lib/OtrRoomState'; +import { useRoom } from '../views/room/contexts/RoomContext'; +import { useOTR } from './useOTR'; + +jest.mock('@rocket.chat/ui-contexts', () => ({ + useUserId: jest.fn(), +})); + +jest.mock('../views/room/contexts/RoomContext', () => ({ + useRoom: jest.fn(), +})); + +jest.mock('../../app/otr/client/OTR', () => ({ + getInstanceByRoomId: jest.fn(), +})); + +jest.mock('./useReactiveValue', () => ({ + useReactiveValue: jest.fn((fn) => fn()), +})); + +describe('useOTR', () => { + it('should return error state when user ID is not available', () => { + (useUserId as jest.Mock).mockReturnValue(undefined); + (useRoom as jest.Mock).mockReturnValue({ _id: 'roomId' }); + + const { result } = renderHook(() => useOTR()); + + expect(result.current.otr).toBeUndefined(); + expect(result.current.otrState).toBe(OtrRoomState.ERROR); + }); + + it('should return error state when room ID is not available', () => { + (useUserId as jest.Mock).mockReturnValue('userId'); + (useRoom as jest.Mock).mockReturnValue(undefined); + + const { result } = renderHook(() => useOTR()); + + expect(result.current.otr).toBeUndefined(); + expect(result.current.otrState).toBe(OtrRoomState.ERROR); + }); + + it('should return error state when OTR instance is not available', () => { + (useUserId as jest.Mock).mockReturnValue('userId'); + (useRoom as jest.Mock).mockReturnValue({ _id: 'roomId' }); + (OTR.getInstanceByRoomId as jest.Mock).mockReturnValue(undefined); + + const { result } = renderHook(() => useOTR()); + + expect(result.current.otr).toBeUndefined(); + expect(result.current.otrState).toBe(OtrRoomState.ERROR); + }); + + it('should return the correct OTR instance and state when available', () => { + const mockOtrInstance = { + getState: jest.fn().mockReturnValue(OtrRoomState.NOT_STARTED), + }; + (useUserId as jest.Mock).mockReturnValue('userId'); + (useRoom as jest.Mock).mockReturnValue({ _id: 'roomId' }); + (OTR.getInstanceByRoomId as jest.Mock).mockReturnValue(mockOtrInstance); + + const { result } = renderHook(() => useOTR()); + + expect(result.current.otr).toBe(mockOtrInstance); + expect(result.current.otrState).toBe(OtrRoomState.NOT_STARTED); + }); +}); diff --git a/apps/meteor/client/hooks/useOTR.ts b/apps/meteor/client/hooks/useOTR.ts new file mode 100644 index 000000000000..65f9004cf323 --- /dev/null +++ b/apps/meteor/client/hooks/useOTR.ts @@ -0,0 +1,28 @@ +import { useUserId } from '@rocket.chat/ui-contexts'; +import { useMemo, useCallback } from 'react'; + +import OTR from '../../app/otr/client/OTR'; +import type { OTRRoom } from '../../app/otr/client/OTRRoom'; +import { OtrRoomState } from '../../app/otr/lib/OtrRoomState'; +import { useRoom } from '../views/room/contexts/RoomContext'; +import { useReactiveValue } from './useReactiveValue'; + +export const useOTR = (): { otr: OTRRoom | undefined; otrState: OtrRoomState } => { + const uid = useUserId(); + const room = useRoom(); + + const otr = useMemo(() => { + if (!uid || !room) { + return; + } + + return OTR.getInstanceByRoomId(uid, room._id); + }, [uid, room]); + + const otrState = useReactiveValue(useCallback(() => (otr ? otr.getState() : OtrRoomState.ERROR), [otr])); + + return { + otr, + otrState, + }; +}; diff --git a/apps/meteor/client/views/room/contextualBar/OTR/OTR.tsx b/apps/meteor/client/views/room/contextualBar/OTR/OTR.tsx index 6b980dfcc390..aaf119e703ff 100644 --- a/apps/meteor/client/views/room/contextualBar/OTR/OTR.tsx +++ b/apps/meteor/client/views/room/contextualBar/OTR/OTR.tsx @@ -1,5 +1,5 @@ import type { IUser } from '@rocket.chat/core-typings'; -import { Box, Button, Throbber } from '@rocket.chat/fuselage'; +import { Box, Button, Callout, Throbber } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { MouseEventHandler, ReactElement } from 'react'; import React from 'react'; @@ -12,6 +12,7 @@ import { ContextualbarClose, ContextualbarScrollableContent, } from '../../../../components/Contextualbar'; +import { useRoom } from '../../contexts/RoomContext'; import OTREstablished from './components/OTREstablished'; import OTRStates from './components/OTRStates'; @@ -27,6 +28,7 @@ type OTRProps = { const OTR = ({ isOnline, onClickClose, onClickStart, onClickEnd, onClickRefresh, otrState, peerUsername }: OTRProps): ReactElement => { const t = useTranslation(); + const room = useRoom(); const renderOTRState = (): ReactElement => { switch (otrState) { @@ -77,6 +79,22 @@ const OTR = ({ isOnline, onClickClose, onClickStart, onClickEnd, onClickRefresh, } }; + const renderOTRBody = (): ReactElement => { + if (room.encrypted) { + return ( + + {t('OTR_not_available_e2ee')} + + ); + } + + if (!isOnline) { + return {t('OTR_is_only_available_when_both_users_are_online')}; + } + + return renderOTRState(); + }; + return ( <> @@ -86,7 +104,7 @@ const OTR = ({ isOnline, onClickClose, onClickStart, onClickEnd, onClickRefresh, {t('Off_the_record_conversation')} - {isOnline ? renderOTRState() : {t('OTR_is_only_available_when_both_users_are_online')}} + {renderOTRBody()} ); diff --git a/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx b/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx index a4c642bdea64..c64d76892cb2 100644 --- a/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx +++ b/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx @@ -1,27 +1,16 @@ -import { useUserId } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; -import React, { useCallback, useEffect, useMemo } from 'react'; +import React, { useEffect } from 'react'; -import OTR from '../../../../../app/otr/client/OTR'; import { OtrRoomState } from '../../../../../app/otr/lib/OtrRoomState'; +import { useOTR } from '../../../../hooks/useOTR'; import { usePresence } from '../../../../hooks/usePresence'; -import { useReactiveValue } from '../../../../hooks/useReactiveValue'; -import { useRoom } from '../../contexts/RoomContext'; import { useRoomToolbox } from '../../contexts/RoomToolboxContext'; import OTRComponent from './OTR'; const OTRWithData = (): ReactElement => { - const uid = useUserId(); - const room = useRoom(); + const { otr, otrState } = useOTR(); const { closeTab } = useRoomToolbox(); - const otr = useMemo(() => { - if (!uid) { - return; - } - return OTR.getInstanceByRoomId(uid, room._id); - }, [uid, room._id]); - const otrState = useReactiveValue(useCallback(() => (otr ? otr.getState() : OtrRoomState.ERROR), [otr])); const peerUserPresence = usePresence(otr?.getPeerId()); const userStatus = peerUserPresence?.status; const peerUsername = peerUserPresence?.username; diff --git a/apps/meteor/tests/e2e/e2e-encryption.spec.ts b/apps/meteor/tests/e2e/e2e-encryption.spec.ts index b33365c5dce0..bb4d2f478219 100644 --- a/apps/meteor/tests/e2e/e2e-encryption.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption.spec.ts @@ -205,6 +205,32 @@ test.describe.serial('e2e-encryption', () => { await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); }); + test('expect create a Direct message, encrypt it and attempt to enable OTR', async ({ page }) => { + await poHomeChannel.sidenav.openNewByLabel('Direct message'); + await poHomeChannel.sidenav.inputDirectUsername.click(); + await page.keyboard.type('user2'); + await page.waitForTimeout(1000); + await page.keyboard.press('Enter'); + await poHomeChannel.sidenav.btnCreate.click(); + + await expect(page).toHaveURL(`/direct/rocketchat.internal.admin.testuser2`); + + await poHomeChannel.tabs.kebab.click({ force: true }); + await expect(poHomeChannel.tabs.btnEnableE2E).toBeVisible(); + await poHomeChannel.tabs.btnEnableE2E.click({ force: true }); + await page.waitForTimeout(1000); + + await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); + + await poHomeChannel.dismissToast(); + + await poHomeChannel.tabs.kebab.click({ force: true }); + await expect(poHomeChannel.tabs.btnEnableOTR).toBeVisible(); + await poHomeChannel.tabs.btnEnableOTR.click({ force: true }); + + await expect(page.getByText('OTR not available')).toBeVisible(); + }); + test('expect placeholder text in place of encrypted message, when E2EE is not setup', async ({ page }) => { const channelName = faker.string.uuid(); diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts index 8e4a6961a790..b8bd673c9cf3 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts @@ -52,6 +52,10 @@ export class HomeFlextab { return this.page.locator('role=menuitem[name="Enable E2E"]'); } + get btnEnableOTR(): Locator { + return this.page.locator('role=menuitem[name="OTR"]'); + } + get flexTabViewThreadMessage(): Locator { return this.page.locator('div.thread-list ul.thread [data-qa-type="message"]').last().locator('[data-qa-type="message-body"]'); } diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 4e658735e130..e9d1894ef74e 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -1782,6 +1782,7 @@ "E2E Encryption": "E2E Encryption", "E2E_Encryption_enabled_for_room": "End-to-end encryption enabled for #{{roomName}}", "E2E_Encryption_disabled_for_room": "End-to-end encryption disabled for #{{roomName}}", + "E2EE_not_available_OTR": "This room has OTR enabled, E2E encryption cannot work with OTR.", "Markdown_Parser": "Markdown Parser", "Markdown_SupportSchemesForLink": "Markdown Support Schemes for Link", "E2E Encryption_Description": "Keep conversations private, ensuring only the sender and intended recipients are able to read them.", @@ -4069,6 +4070,8 @@ "OTR_Chat_Timeout_Description": "%s failed to accept OTR chat invite in time. For privacy protection local cache was deleted, including all related system messages.", "OTR_Enable_Description": "Enable option to use off-the-record (OTR) messages in direct messages between 2 users. OTR messages are not recorded on the server and exchanged directly and encrypted between the 2 users.", "OTR_message": "OTR Message", + "OTR_not_available": "OTR not available", + "OTR_not_available_e2ee": "This room has E2E encryption enabled, OTR cannot work with encrypted messages.", "OTR_is_only_available_when_both_users_are_online": "OTR is only available when both users are online", "OTR_Session_ended_other_user_went_offline": "OTR Session has ended. User {{username}} went offline", "outbound-voip-calls": "Outbound Voip Calls", From afa560da52749c46802c1016cafddf0e8071c078 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 13 Jun 2024 11:07:07 -0300 Subject: [PATCH 16/94] chore: bump meteor 2.16 (#32585) --- apps/meteor/.meteor/packages | 14 +++++----- apps/meteor/.meteor/release | 2 +- apps/meteor/.meteor/versions | 26 +++++++++---------- .../.npm/package/npm-shrinkwrap.json | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/meteor/.meteor/packages b/apps/meteor/.meteor/packages index 8107c249add2..307b0d89eb0d 100644 --- a/apps/meteor/.meteor/packages +++ b/apps/meteor/.meteor/packages @@ -15,12 +15,12 @@ rocketchat:streamer rocketchat:version rocketchat:user-presence -accounts-base@2.2.10 +accounts-base@2.2.11 accounts-facebook@1.3.3 accounts-github@1.5.0 accounts-google@1.4.0 accounts-meteor-developer@1.5.0 -accounts-oauth@1.4.3 +accounts-oauth@1.4.4 accounts-password@2.4.0 accounts-twitter@1.5.0 @@ -29,20 +29,20 @@ google-oauth@1.4.4 oauth@2.2.1 oauth2@1.3.2 -check@1.3.2 +check@1.4.1 ddp-rate-limiter@1.2.1 rate-limit@1.1.1 -email@2.2.5 +email@2.2.6 http@2.0.0 meteor-base@1.5.1 -ddp-common@1.4.0 +ddp-common@1.4.1 webapp@1.13.8 -mongo@1.16.8 +mongo@1.16.10 reload@1.3.1 -service-configuration@1.3.3 +service-configuration@1.3.4 session@1.2.1 shell-server@0.5.0 diff --git a/apps/meteor/.meteor/release b/apps/meteor/.meteor/release index 966586ce54fe..5152abe9d582 100644 --- a/apps/meteor/.meteor/release +++ b/apps/meteor/.meteor/release @@ -1 +1 @@ -METEOR@2.15 +METEOR@2.16 diff --git a/apps/meteor/.meteor/versions b/apps/meteor/.meteor/versions index a4483a5cf40e..416ae456f05b 100644 --- a/apps/meteor/.meteor/versions +++ b/apps/meteor/.meteor/versions @@ -1,9 +1,9 @@ -accounts-base@2.2.10 +accounts-base@2.2.11 accounts-facebook@1.3.3 accounts-github@1.5.0 accounts-google@1.4.0 accounts-meteor-developer@1.5.0 -accounts-oauth@1.4.3 +accounts-oauth@1.4.4 accounts-password@2.4.0 accounts-twitter@1.5.0 allow-deny@1.1.1 @@ -15,14 +15,14 @@ binary-heap@1.0.11 boilerplate-generator@1.7.2 caching-compiler@1.2.2 callback-hook@1.5.1 -check@1.3.2 +check@1.4.1 coffeescript@2.7.0 coffeescript-compiler@2.4.1 ddp@1.4.1 -ddp-client@2.6.1 -ddp-common@1.4.0 +ddp-client@2.6.2 +ddp-common@1.4.1 ddp-rate-limiter@1.2.1 -ddp-server@2.7.0 +ddp-server@2.7.1 diff-sequence@1.1.2 dispatch:run-as-user@1.1.1 dynamic-import@0.7.3 @@ -31,7 +31,7 @@ ecmascript-runtime@0.8.1 ecmascript-runtime-client@0.12.1 ecmascript-runtime-server@0.11.0 ejson@1.1.3 -email@2.2.5 +email@2.2.6 es5-shim@4.8.0 facebook-oauth@1.11.3 facts-base@1.0.1 @@ -45,17 +45,17 @@ id-map@1.1.1 inter-process-messaging@0.1.1 kadira:flow-router@2.12.1 localstorage@1.2.0 -logging@1.3.3 +logging@1.3.4 meteor@1.11.5 meteor-base@1.5.1 meteor-developer-oauth@1.3.2 meteorhacks:inject-initial@1.0.5 minifier-css@1.6.4 -minimongo@1.9.3 +minimongo@1.9.4 modern-browsers@0.1.10 modules@0.20.0 modules-runtime@0.13.1 -mongo@1.16.8 +mongo@1.16.10 mongo-decimal@0.1.3 mongo-dev-server@1.1.0 mongo-id@1.0.8 @@ -84,7 +84,7 @@ rocketchat:streamer@1.1.0 rocketchat:user-presence@2.6.3 rocketchat:version@1.0.0 routepolicy@1.1.1 -service-configuration@1.3.3 +service-configuration@1.3.4 session@1.2.1 sha@1.0.9 shell-server@0.5.0 @@ -93,10 +93,10 @@ standard-minifier-css@1.9.2 tracker@1.3.3 twitter-oauth@1.3.3 typescript@4.9.5 -underscore@1.6.0 +underscore@1.6.1 url@1.3.2 webapp@1.13.8 webapp-hashing@1.1.1 zodern:caching-minifier@0.5.0 zodern:standard-minifier-js@5.3.1 -zodern:types@1.0.11 +zodern:types@1.0.13 diff --git a/apps/meteor/packages/flow-router/.npm/package/npm-shrinkwrap.json b/apps/meteor/packages/flow-router/.npm/package/npm-shrinkwrap.json index 47445b724946..8110d45c9f30 100644 --- a/apps/meteor/packages/flow-router/.npm/package/npm-shrinkwrap.json +++ b/apps/meteor/packages/flow-router/.npm/package/npm-shrinkwrap.json @@ -25,4 +25,4 @@ "integrity": "sha512-VH4FeG98gs6AkHivaW2O14vsOPBL9E80Sj7fITunoDijiYQ1lsVwJYmm1CSL+oLyO2N5HPdo23GXAG64uKOAZQ==" } } -} \ No newline at end of file +} From 97eaa176807a64d9cf10833eeda789d9c964d42b Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Fri, 14 Jun 2024 08:09:31 -0300 Subject: [PATCH 17/94] fix: Accepted Media Types settings validation (#32478) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Henrique Guimarães Ribeiro <43561537+rique223@users.noreply.github.com> --- .changeset/chilly-toys-hunt.md | 5 ++ .../app/file-upload/server/lib/FileUpload.ts | 3 +- apps/meteor/app/utils/client/restrictions.ts | 2 +- apps/meteor/app/utils/lib/restrictions.ts | 34 ++++++++----- apps/meteor/app/utils/server/restrictions.ts | 2 +- .../client/lib/chats/flows/uploadFiles.ts | 2 +- .../unit/app/utils/lib/restrictions.spec.ts | 49 +++++++++++++++++++ 7 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 .changeset/chilly-toys-hunt.md create mode 100644 apps/meteor/tests/unit/app/utils/lib/restrictions.spec.ts diff --git a/.changeset/chilly-toys-hunt.md b/.changeset/chilly-toys-hunt.md new file mode 100644 index 000000000000..79be3fcfc74c --- /dev/null +++ b/.changeset/chilly-toys-hunt.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed "File Upload > Accepted Media Types" setting to allow all type of files uploads diff --git a/apps/meteor/app/file-upload/server/lib/FileUpload.ts b/apps/meteor/app/file-upload/server/lib/FileUpload.ts index 4458f9d61881..c824ba6c31a5 100644 --- a/apps/meteor/app/file-upload/server/lib/FileUpload.ts +++ b/apps/meteor/app/file-upload/server/lib/FileUpload.ts @@ -170,7 +170,7 @@ export const FileUpload = { throw new Meteor.Error('error-file-too-large', reason); } - if (!fileUploadIsValidContentType(file.type as string, '')) { + if (!fileUploadIsValidContentType(file?.type)) { const reason = i18n.t('File_type_is_not_accepted', { lng: language }); throw new Meteor.Error('error-invalid-file-type', reason); } @@ -420,7 +420,6 @@ export const FileUpload = { await Avatars.deleteFile(oldAvatar._id); } await Avatars.updateFileNameById(file._id, user.username); - // console.log('upload finished ->', file); }, async requestCanAccessFiles({ headers = {}, url }: http.IncomingMessage, file?: IUpload) { diff --git a/apps/meteor/app/utils/client/restrictions.ts b/apps/meteor/app/utils/client/restrictions.ts index 261eddf4467d..d4c6b62d68dd 100644 --- a/apps/meteor/app/utils/client/restrictions.ts +++ b/apps/meteor/app/utils/client/restrictions.ts @@ -1,7 +1,7 @@ import { settings } from '../../settings/client'; import { fileUploadIsValidContentTypeFromSettings } from '../lib/restrictions'; -export const fileUploadIsValidContentType = function (type: string, customWhiteList?: string): boolean { +export const fileUploadIsValidContentType = function (type: string | undefined, customWhiteList?: string): boolean { const blackList = settings.get('FileUpload_MediaTypeBlackList'); const whiteList = customWhiteList || settings.get('FileUpload_MediaTypeWhiteList'); diff --git a/apps/meteor/app/utils/lib/restrictions.ts b/apps/meteor/app/utils/lib/restrictions.ts index ebebe113f31e..bf859e5b4700 100644 --- a/apps/meteor/app/utils/lib/restrictions.ts +++ b/apps/meteor/app/utils/lib/restrictions.ts @@ -1,12 +1,10 @@ -import _ from 'underscore'; - export const fileUploadMediaWhiteList = function (customWhiteList: string): string[] | undefined { const mediaTypeWhiteList = customWhiteList; if (!mediaTypeWhiteList || mediaTypeWhiteList === '*') { return; } - return _.map(mediaTypeWhiteList.split(','), (item) => { + return mediaTypeWhiteList.split(',').map((item) => { return item.trim(); }); }; @@ -17,37 +15,47 @@ const fileUploadMediaBlackList = function (customBlackList: string): string[] | return; } - return _.map(blacklist.split(','), (item) => item.trim()); + return blacklist.split(',').map((item) => item.trim()); }; -const isTypeOnList = function (type: string, list: string[]): boolean | undefined { - if (_.contains(list, type)) { +const isTypeOnList = function (type?: string, list?: string[]): boolean { + if (!type || !list) { + return false; + } + + if (list.includes(type)) { return true; } const wildCardGlob = '/*'; - const wildcards = _.filter(list, (item) => { + const wildcards = list.filter((item) => { return item.indexOf(wildCardGlob) > 0; }); - if (_.contains(wildcards, type.replace(/(\/.*)$/, wildCardGlob))) { + if (wildcards.includes(type.replace(/(\/.*)$/, wildCardGlob))) { return true; } + + return false; }; -export const fileUploadIsValidContentTypeFromSettings = function (type: string, customWhiteList: string, customBlackList: string): boolean { +export const fileUploadIsValidContentTypeFromSettings = function ( + type: string | undefined, + customWhiteList: string, + customBlackList: string, +): boolean { const blackList = fileUploadMediaBlackList(customBlackList); const whiteList = fileUploadMediaWhiteList(customWhiteList); - if (!type && blackList) { + if (blackList && type && isTypeOnList(type, blackList)) { return false; } - if (blackList && isTypeOnList(type, blackList)) { - return false; + if (whiteList) { + return isTypeOnList(type, whiteList); } if (!whiteList) { return true; } - return !!isTypeOnList(type, whiteList); + return false; }; diff --git a/apps/meteor/app/utils/server/restrictions.ts b/apps/meteor/app/utils/server/restrictions.ts index ca524b09d351..6eb1c9a655d4 100644 --- a/apps/meteor/app/utils/server/restrictions.ts +++ b/apps/meteor/app/utils/server/restrictions.ts @@ -1,7 +1,7 @@ import { settings } from '../../settings/server'; import { fileUploadIsValidContentTypeFromSettings } from '../lib/restrictions'; -export const fileUploadIsValidContentType = function (type: string, customWhiteList?: string): boolean { +export const fileUploadIsValidContentType = function (type: string | undefined, customWhiteList?: string): boolean { const blackList = settings.get('FileUpload_MediaTypeBlackList'); const whiteList = customWhiteList || settings.get('FileUpload_MediaTypeWhiteList'); diff --git a/apps/meteor/client/lib/chats/flows/uploadFiles.ts b/apps/meteor/client/lib/chats/flows/uploadFiles.ts index 82572aa2dbf5..62458d53fd60 100644 --- a/apps/meteor/client/lib/chats/flows/uploadFiles.ts +++ b/apps/meteor/client/lib/chats/flows/uploadFiles.ts @@ -46,7 +46,7 @@ export const uploadFiles = async (chat: ChatAPI, files: readonly File[], resetFi imperativeModal.close(); uploadNextFile(); }, - invalidContentType: !(file.type && fileUploadIsValidContentType(file.type)), + invalidContentType: !fileUploadIsValidContentType(file?.type), }, }); }; diff --git a/apps/meteor/tests/unit/app/utils/lib/restrictions.spec.ts b/apps/meteor/tests/unit/app/utils/lib/restrictions.spec.ts new file mode 100644 index 000000000000..f7a6b4439f21 --- /dev/null +++ b/apps/meteor/tests/unit/app/utils/lib/restrictions.spec.ts @@ -0,0 +1,49 @@ +import { expect } from 'chai'; + +import { fileUploadIsValidContentTypeFromSettings } from '../../../../../app/utils/lib/restrictions'; + +describe('fileUploadIsValidContentTypeFromSettings', () => { + it('should return true if type is not defined and whiteList is not defined', () => { + expect(fileUploadIsValidContentTypeFromSettings(undefined, '', '')).to.be.true; + }); + + it('should return false if type is not defined and whiteList is defined', () => { + expect(fileUploadIsValidContentTypeFromSettings(undefined, 'image/jpeg', '')).to.be.false; + }); + + it('should return true if type is defined and whiteList is not defined', () => { + expect(fileUploadIsValidContentTypeFromSettings('image/jpeg', '', '')).to.be.true; + }); + + it('should return true if type is defined and whiteList is defined and type is in whiteList', () => { + expect(fileUploadIsValidContentTypeFromSettings('image/jpeg', 'image/jpeg', '')).to.be.true; + }); + + it('should return false if type is defined and whiteList is defined and type is not in whiteList', () => { + expect(fileUploadIsValidContentTypeFromSettings('image/png', 'image/jpeg', '')).to.be.false; + }); + + it('should return false if type is defined and whiteList is not defined and type is in blackList', () => { + expect(fileUploadIsValidContentTypeFromSettings('image/jpeg', '', 'image/jpeg')).to.be.false; + }); + + it('should return true if type is defined and whiteList is not defined and type is not in blackList', () => { + expect(fileUploadIsValidContentTypeFromSettings('image/png', '', 'image/jpeg')).to.be.true; + }); + + it('should return true if type is defined and whiteList is defined and type is in whiteList with wildcard', () => { + expect(fileUploadIsValidContentTypeFromSettings('image/jpeg', 'image/*', '')).to.be.true; + }); + + it('should return false if type is defined and whiteList is defined and type is not in whiteList with wildcard', () => { + expect(fileUploadIsValidContentTypeFromSettings('text/plain', 'image/*', '')).to.be.false; + }); + + it('should return false if type is defined and whiteList is not defined and type is in blackList with wildcard', () => { + expect(fileUploadIsValidContentTypeFromSettings('image/jpeg', '', 'image/*')).to.be.false; + }); + + it('should return true if type is defined and whiteList is defined and type is not in blackList with wildcard', () => { + expect(fileUploadIsValidContentTypeFromSettings('text/plain', '', 'image/*')).to.be.true; + }); +}); From d3ab41681e1b4061209987d1c1811ad8310707ea Mon Sep 17 00:00:00 2001 From: csuadev <72958726+csuadev@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:50:11 +0200 Subject: [PATCH 18/94] chore: remove message column on moderation console (#32432) --- .../views/admin/moderation/ModerationConsoleTable.tsx | 10 ---------- .../admin/moderation/ModerationConsoleTableRow.tsx | 3 +-- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/apps/meteor/client/views/admin/moderation/ModerationConsoleTable.tsx b/apps/meteor/client/views/admin/moderation/ModerationConsoleTable.tsx index 6de7cdda1675..805d89c54c37 100644 --- a/apps/meteor/client/views/admin/moderation/ModerationConsoleTable.tsx +++ b/apps/meteor/client/views/admin/moderation/ModerationConsoleTable.tsx @@ -85,16 +85,6 @@ const ModerationConsoleTable: FC = () => { > {t('User')} , - - - {t('Moderation_Reported_message')} - , {t('Room')} , diff --git a/apps/meteor/client/views/admin/moderation/ModerationConsoleTableRow.tsx b/apps/meteor/client/views/admin/moderation/ModerationConsoleTableRow.tsx index 56419c61223c..65bf7069e074 100644 --- a/apps/meteor/client/views/admin/moderation/ModerationConsoleTableRow.tsx +++ b/apps/meteor/client/views/admin/moderation/ModerationConsoleTableRow.tsx @@ -13,7 +13,7 @@ export type ModerationConsoleRowProps = { }; const ModerationConsoleTableRow = ({ report, onClick, isDesktopOrLarger }: ModerationConsoleRowProps): JSX.Element => { - const { userId: _id, rooms, name, count, message, username, ts } = report; + const { userId: _id, rooms, name, count, username, ts } = report; const roomNames = rooms.map((room) => { if (room.t === 'd') { @@ -31,7 +31,6 @@ const ModerationConsoleTableRow = ({ report, onClick, isDesktopOrLarger }: Moder - {message} {concatenatedRoomNames} {formatDateAndTime(ts)} {count} From eaf2f11a6c7fbd1635f777b88019355c3fb4f9be Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Mon, 17 Jun 2024 09:52:53 -0300 Subject: [PATCH 19/94] fix: sidebar last message E2EE (#32431) --- .changeset/lastmessage-e2ee.md | 6 +++ .../lib/server/functions/cleanRoomHistory.ts | 2 +- .../app/lib/server/functions/deleteMessage.ts | 2 +- apps/meteor/server/models/raw/Messages.ts | 9 ++-- apps/meteor/tests/e2e/e2e-encryption.spec.ts | 45 +++++++++++++++++++ .../page-objects/fragments/home-sidenav.ts | 6 +++ .../src/models/IMessagesModel.ts | 2 +- 7 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 .changeset/lastmessage-e2ee.md diff --git a/.changeset/lastmessage-e2ee.md b/.changeset/lastmessage-e2ee.md new file mode 100644 index 000000000000..b3c8642dcff6 --- /dev/null +++ b/.changeset/lastmessage-e2ee.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/model-typings": patch +--- + +Fixed last message preview in Sidebar for E2E Ecrypted channels diff --git a/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts b/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts index f53061995152..2bfb1086c635 100644 --- a/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts +++ b/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts @@ -111,7 +111,7 @@ export async function cleanRoomHistory({ } if (count) { - const lastMessage = await Messages.getLastVisibleMessageSentWithNoTypeByRoomId(rid); + const lastMessage = await Messages.getLastVisibleUserMessageSentByRoomId(rid); await Rooms.resetLastMessageById(rid, lastMessage, -count); diff --git a/apps/meteor/app/lib/server/functions/deleteMessage.ts b/apps/meteor/app/lib/server/functions/deleteMessage.ts index 4582a88823ec..e977874b3454 100644 --- a/apps/meteor/app/lib/server/functions/deleteMessage.ts +++ b/apps/meteor/app/lib/server/functions/deleteMessage.ts @@ -81,7 +81,7 @@ export async function deleteMessage(message: IMessage, user: IUser): Promise implements IMessagesModel { return this.findOne(query, options); } - getLastVisibleMessageSentWithNoTypeByRoomId(rid: string, messageId?: string): Promise { - const query = { + getLastVisibleUserMessageSentByRoomId(rid: string, messageId?: string): Promise { + const query: Filter = { rid, _hidden: { $ne: true }, - t: { $exists: false }, - $or: [{ tmid: { $exists: false } }, { tshow: true }], + $or: [{ t: 'e2e' }, { t: { $exists: false }, tmid: { $exists: false } }, { t: { $exists: false }, tshow: true }], ...(messageId && { _id: { $ne: messageId } }), }; @@ -1055,7 +1054,7 @@ export class MessagesRaw extends BaseRaw implements IMessagesModel { }, }; - return this.findOne(query, options); + return this.findOne(query, options); } async cloneAndSaveAsHistoryByRecord(record: IMessage, user: IMessage['u']): Promise> { diff --git a/apps/meteor/tests/e2e/e2e-encryption.spec.ts b/apps/meteor/tests/e2e/e2e-encryption.spec.ts index bb4d2f478219..c2d1fcc24cb7 100644 --- a/apps/meteor/tests/e2e/e2e-encryption.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption.spec.ts @@ -265,6 +265,51 @@ test.describe.serial('e2e-encryption', () => { await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); }); + test('expect create a private channel, send unecrypted messages, encrypt the channel and delete the last message and check the last message in the sidebar', async ({ + page, + }) => { + const channelName = faker.string.uuid(); + + // Enable Sidebar Extended display mode + await poHomeChannel.sidenav.setDisplayMode('Extended'); + + // Create private channel + await poHomeChannel.sidenav.openNewByLabel('Channel'); + await poHomeChannel.sidenav.inputChannelName.fill(channelName); + await poHomeChannel.sidenav.btnCreate.click(); + await expect(page).toHaveURL(`/group/${channelName}`); + await expect(poHomeChannel.toastSuccess).toBeVisible(); + await poHomeChannel.dismissToast(); + + // Send Unencrypted Messages + await poHomeChannel.content.sendMessage('first unencrypted message'); + await poHomeChannel.content.sendMessage('second unencrypted message'); + + // Encrypt channel + await poHomeChannel.tabs.kebab.click({ force: true }); + await expect(poHomeChannel.tabs.btnEnableE2E).toBeVisible(); + await poHomeChannel.tabs.btnEnableE2E.click({ force: true }); + await page.waitForTimeout(1000); + await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); + + // Send Encrypted Messages + const encriptedMessage1 = 'first ENCRYPTED message'; + const encriptedMessage2 = 'second ENCRYPTED message'; + await poHomeChannel.content.sendMessage(encriptedMessage1); + await poHomeChannel.content.sendMessage(encriptedMessage2); + + // Delete last message + await expect(poHomeChannel.content.lastUserMessageBody).toHaveText(encriptedMessage2); + await poHomeChannel.content.openLastMessageMenu(); + await page.locator('role=menuitem[name="Delete"]').click(); + await page.locator('#modal-root .rcx-button-group--align-end .rcx-button--danger').click(); + + // Check last message in the sidebar + const sidebarChannel = await poHomeChannel.sidenav.getSidebarItemByName(channelName); + await expect(sidebarChannel).toBeVisible(); + await expect(sidebarChannel.locator('span')).toContainText(encriptedMessage1); + }); + test.describe('reset keys', () => { let anotherClientPage: Page; diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts index 3d689b27e3fc..dfae6c668bb9 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts @@ -49,6 +49,12 @@ export class HomeSidenav { return this.page.getByRole('toolbar', { name: 'Sidebar actions' }); } + async setDisplayMode(mode: 'Extended' | 'Medium' | 'Condensed'): Promise { + await this.sidebarToolbar.getByRole('button', { name: 'Display' }).click(); + await this.sidebarToolbar.getByRole('menuitemcheckbox', { name: mode }).click(); + await this.sidebarToolbar.click(); + } + // Note: this is different from openChat because queued chats are not searchable getQueuedChat(name: string): Locator { return this.page.locator('[data-qa="sidebar-item-title"]', { hasText: name }).first(); diff --git a/packages/model-typings/src/models/IMessagesModel.ts b/packages/model-typings/src/models/IMessagesModel.ts index 143080799671..0fb02a778c9d 100644 --- a/packages/model-typings/src/models/IMessagesModel.ts +++ b/packages/model-typings/src/models/IMessagesModel.ts @@ -205,7 +205,7 @@ export interface IMessagesModel extends IBaseModel { updateAllUsernamesByUserId(userId: string, username: string): Promise; setUrlsById(_id: string, urls: NonNullable): Promise; - getLastVisibleMessageSentWithNoTypeByRoomId(rid: string, messageId?: string): Promise; + getLastVisibleUserMessageSentByRoomId(rid: string, messageId?: string): Promise; findOneBySlackTs(slackTs: Date): Promise; From 9795e58c2cc9bbb40760706c16d88f57f42f554a Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Mon, 17 Jun 2024 11:46:46 -0300 Subject: [PATCH 20/94] fix: Force highlighted code language registration (#32507) --- .changeset/weak-books-tell.md | 5 ++ .../meteor/client/hooks/useHighlightedCode.ts | 16 +++++- .../admin/integrations/IntegrationsTable.tsx | 2 +- apps/meteor/tests/e2e/administration.spec.ts | 49 ++++++++++++++++++- apps/meteor/tests/e2e/page-objects/admin.ts | 40 ++++++++++++++- apps/meteor/tests/e2e/utils/index.ts | 1 + packages/i18n/src/locales/en.i18n.json | 1 + 7 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 .changeset/weak-books-tell.md diff --git a/.changeset/weak-books-tell.md b/.changeset/weak-books-tell.md new file mode 100644 index 000000000000..675901263f31 --- /dev/null +++ b/.changeset/weak-books-tell.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Forces the highlight code language registration, preventing it to not being available when trying to use on the UI diff --git a/apps/meteor/client/hooks/useHighlightedCode.ts b/apps/meteor/client/hooks/useHighlightedCode.ts index 43c4a5e6ea58..4e3405ca3034 100644 --- a/apps/meteor/client/hooks/useHighlightedCode.ts +++ b/apps/meteor/client/hooks/useHighlightedCode.ts @@ -1,7 +1,19 @@ +import { useTranslation } from '@rocket.chat/ui-contexts'; +import { useQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; -import hljs from '../../app/markdown/lib/hljs'; +import hljs, { register } from '../../app/markdown/lib/hljs'; export function useHighlightedCode(language: string, text: string): string { - return useMemo(() => hljs.highlight(language, text).value, [language, text]); + const t = useTranslation(); + const { isLoading } = useQuery(['register-highlight-language', language], async () => { + try { + await register(language); + return true; + } catch (error) { + console.error('Not possible to register the provided language'); + } + }); + + return useMemo(() => (isLoading ? t('Loading') : hljs.highlight(language, text).value), [isLoading, language, text, t]); } diff --git a/apps/meteor/client/views/admin/integrations/IntegrationsTable.tsx b/apps/meteor/client/views/admin/integrations/IntegrationsTable.tsx index 206458e09c9b..e2942f384c9d 100644 --- a/apps/meteor/client/views/admin/integrations/IntegrationsTable.tsx +++ b/apps/meteor/client/views/admin/integrations/IntegrationsTable.tsx @@ -107,7 +107,7 @@ const IntegrationsTable = ({ type }: { type?: string }) => { )} {isSuccess && data && data.integrations.length > 0 && ( <> - + {headers} {isSuccess && diff --git a/apps/meteor/tests/e2e/administration.spec.ts b/apps/meteor/tests/e2e/administration.spec.ts index 902d4f09b12c..e4af3c26c106 100644 --- a/apps/meteor/tests/e2e/administration.spec.ts +++ b/apps/meteor/tests/e2e/administration.spec.ts @@ -3,8 +3,7 @@ import { faker } from '@faker-js/faker'; import { IS_EE } from './config/constants'; import { Users } from './fixtures/userStates'; import { Admin, Utils } from './page-objects'; -import { createTargetChannel } from './utils'; -import { setSettingValueById } from './utils/setSettingValueById'; +import { createTargetChannel, setSettingValueById } from './utils'; import { test, expect } from './utils/test'; test.use({ storageState: Users.admin.state }); @@ -275,6 +274,52 @@ test.describe.parallel('administration', () => { }); }); + test.describe('Integrations', () => { + const messageCodeHighlightDefault = + 'javascript,css,markdown,dockerfile,json,go,rust,clean,bash,plaintext,powershell,scss,shell,yaml,vim'; + const incomingIntegrationName = faker.string.uuid(); + + test.beforeAll(async ({ api }) => { + await setSettingValueById(api, 'Message_Code_highlight', ''); + }); + + test.beforeEach(async ({ page }) => { + await page.goto('/admin/integrations'); + }); + + test.afterAll(async ({ api }) => { + await setSettingValueById(api, 'Message_Code_highlight', messageCodeHighlightDefault); + }); + + test('should display the example payload correctly', async () => { + await poAdmin.btnNew.click(); + await poAdmin.btnInstructions.click(); + + await expect(poAdmin.codeExamplePayload('Loading')).not.toBeVisible(); + }); + + test('should be able to create new incoming integration', async () => { + await poAdmin.btnNew.click(); + await poAdmin.inputName.fill(incomingIntegrationName); + await poAdmin.inputPostToChannel.fill('#general'); + await poAdmin.inputPostAs.fill(Users.admin.data.username); + await poAdmin.btnSave.click(); + + await expect(poAdmin.inputWebhookUrl).not.toHaveValue('Will be available here after saving.'); + + await poAdmin.btnBack.click(); + await expect(poAdmin.getIntegrationByName(incomingIntegrationName)).toBeVisible(); + }); + + test('should be able to delete an incoming integration', async () => { + await poAdmin.getIntegrationByName(incomingIntegrationName).click(); + await poAdmin.btnDelete.click(); + await poUtils.btnModalConfirmDelete.click(); + + await expect(poAdmin.getIntegrationByName(incomingIntegrationName)).not.toBeVisible(); + }); + }); + test.describe('Settings', () => { test.describe('General', () => { test.beforeEach(async ({ page }) => { diff --git a/apps/meteor/tests/e2e/page-objects/admin.ts b/apps/meteor/tests/e2e/page-objects/admin.ts index f3567652fe6e..210dbc95f326 100644 --- a/apps/meteor/tests/e2e/page-objects/admin.ts +++ b/apps/meteor/tests/e2e/page-objects/admin.ts @@ -213,11 +213,47 @@ export class Admin { return this.page.getByRole('button', { name: 'Add' }); } + getUserRowByUsername(username: string): Locator { + return this.page.locator('tr', { hasText: username }); + } + get btnBack(): Locator { return this.page.getByRole('button', { name: 'Back' }); } - getUserRowByUsername(username: string): Locator { - return this.page.locator('tr', { hasText: username }); + get btnNew(): Locator { + return this.page.getByRole('button', { name: 'New' }); + } + + get btnDelete(): Locator { + return this.page.getByRole('button', { name: 'Delete' }); + } + + get btnInstructions(): Locator { + return this.page.getByRole('button', { name: 'Instructions' }); + } + + get inputName(): Locator { + return this.page.getByRole('textbox', { name: 'Name' }); + } + + get inputPostToChannel(): Locator { + return this.page.getByRole('textbox', { name: 'Post to Channel' }); + } + + get inputPostAs(): Locator { + return this.page.getByRole('textbox', { name: 'Post as' }); + } + + codeExamplePayload(text: string): Locator { + return this.page.locator('code', { hasText: text }); + } + + getIntegrationByName(name: string): Locator { + return this.page.getByRole('table', { name: 'Integrations table' }).locator('tr', { hasText: name }); + } + + get inputWebhookUrl(): Locator { + return this.page.getByRole('textbox', { name: 'Webhook URL' }); } } diff --git a/apps/meteor/tests/e2e/utils/index.ts b/apps/meteor/tests/e2e/utils/index.ts index 9f83fc0ae246..e1daf601f648 100644 --- a/apps/meteor/tests/e2e/utils/index.ts +++ b/apps/meteor/tests/e2e/utils/index.ts @@ -1,2 +1,3 @@ export * from './create-target-channel'; export * from './setSettingValueById'; +export * from './getSettingValueById'; diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index e9d1894ef74e..779c71c9d755 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -2763,6 +2763,7 @@ "Integrations_Outgoing_Type_RoomLeft": "User Left Room", "Integrations_Outgoing_Type_SendMessage": "Message Sent", "Integrations_Outgoing_Type_UserCreated": "User Created", + "Integrations_table": "Integrations table", "InternalHubot": "Internal Hubot", "InternalHubot_EnableForChannels": "Enable for Public Channels", "InternalHubot_EnableForDirectMessages": "Enable for Direct Messages", From 59df102d0cdcb6968ef04fd5f683d3ef6af9b1f3 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Mon, 17 Jun 2024 15:16:17 -0300 Subject: [PATCH 21/94] fix: Long katex strings breaking overflow in x axis (#32609) --- .changeset/healthy-clouds-hide.md | 5 +++++ packages/gazzodown/src/katex/KatexBlock.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/healthy-clouds-hide.md diff --git a/.changeset/healthy-clouds-hide.md b/.changeset/healthy-clouds-hide.md new file mode 100644 index 000000000000..528a1bf27568 --- /dev/null +++ b/.changeset/healthy-clouds-hide.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/gazzodown": patch +--- + +Fixes long katex lines overflowing the message component diff --git a/packages/gazzodown/src/katex/KatexBlock.tsx b/packages/gazzodown/src/katex/KatexBlock.tsx index 25e9c77dc863..5913185d3969 100644 --- a/packages/gazzodown/src/katex/KatexBlock.tsx +++ b/packages/gazzodown/src/katex/KatexBlock.tsx @@ -19,7 +19,7 @@ const KatexBlock = ({ code }: KatexBlockProps): ReactElement => { [code], ); - return
; + return
; }; export default KatexBlock; From 1c4b7024880c1ba6a77464a8bd24da0361113d43 Mon Sep 17 00:00:00 2001 From: Aaron Ogle Date: Mon, 17 Jun 2024 14:47:04 -0500 Subject: [PATCH 22/94] chore: Add telemetry to CI so we can get a better understanding of resource usage (#32113) --- .github/workflows/ci-test-e2e.yml | 7 +++++++ .github/workflows/ci-test-unit.yml | 6 ++++++ .github/workflows/ci.yml | 12 ++++++++++++ 3 files changed, 25 insertions(+) diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index 1dc8993bfa87..b46c124d149b 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -90,6 +90,13 @@ jobs: name: MongoDB ${{ matrix.mongodb-version }}${{ inputs.db-watcher-disabled == 'true' && ' [no watchers]' || '' }} (${{ matrix.shard }}/${{ inputs.total-shard }})${{ matrix.mongodb-version == '6.0' && ' - Alpine' || '' }} steps: + - name: Collect Workflow Telemetry + uses: catchpoint/workflow-telemetry-action@v2 + with: + theme: dark + job_summary: true + comment_on_pr: false + - name: Login to GitHub Container Registry if: (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') uses: docker/login-action@v2 diff --git a/.github/workflows/ci-test-unit.yml b/.github/workflows/ci-test-unit.yml index 066cc2e3773e..cf28bbdfc01a 100644 --- a/.github/workflows/ci-test-unit.yml +++ b/.github/workflows/ci-test-unit.yml @@ -21,6 +21,12 @@ jobs: name: Unit Tests steps: + - name: Collect Workflow Telemetry + uses: catchpoint/workflow-telemetry-action@v2 + with: + theme: dark + job_summary: true + comment_on_pr: false - uses: actions/checkout@v4 - name: Setup NodeJS diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b16ab459d6bd..b9aa8f616857 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -168,6 +168,12 @@ jobs: runs-on: ubuntu-20.04 steps: + - name: Collect Workflow Telemetry + uses: catchpoint/workflow-telemetry-action@v2 + with: + theme: dark + job_summary: true + comment_on_pr: false - name: Github Info run: | echo "GITHUB_ACTION: $GITHUB_ACTION" @@ -192,6 +198,12 @@ jobs: runs-on: ubuntu-20.04 steps: + - name: Collect Workflow Telemetry + uses: catchpoint/workflow-telemetry-action@v2 + with: + theme: dark + job_summary: true + comment_on_pr: false - name: Github Info run: | echo "GITHUB_ACTION: $GITHUB_ACTION" From 465c8edff56ecbcd10c2f10be613cf1f25f106c7 Mon Sep 17 00:00:00 2001 From: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com> Date: Tue, 18 Jun 2024 02:05:30 +0530 Subject: [PATCH 23/94] fix: E2EE thread main message reactivity (#32381) --- .changeset/three-squids-brake.md | 5 +++ .../hooks/useThreadMainMessageQuery.ts | 6 ++-- apps/meteor/tests/e2e/e2e-encryption.spec.ts | 34 +++++++++++++++++++ .../page-objects/fragments/home-content.ts | 4 +++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 .changeset/three-squids-brake.md diff --git a/.changeset/three-squids-brake.md b/.changeset/three-squids-brake.md new file mode 100644 index 000000000000..89ed21f8048c --- /dev/null +++ b/.changeset/three-squids-brake.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixed Encrypted thread main message reactivity issues. Earlier the encrypted thread main message was having some reactivity issues and flaky behavior. diff --git a/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts index ecf2d54a45f7..76e80d774ca3 100644 --- a/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts +++ b/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts @@ -7,6 +7,7 @@ import { useCallback, useEffect, useRef } from 'react'; import { withDebouncing } from '../../../../../../lib/utils/highOrderFunctions'; import type { FieldExpression, Query } from '../../../../../lib/minimongo'; import { createFilterFromQuery } from '../../../../../lib/minimongo'; +import { onClientMessageReceived } from '../../../../../lib/onClientMessageReceived'; import { useRoom } from '../../../contexts/RoomContext'; import { useGetMessageByID } from './useGetMessageByID'; @@ -107,8 +108,9 @@ export const useThreadMainMessageQuery = ( unsubscribeRef.current = unsubscribeRef.current || subscribeToMessage(mainMessage, { - onMutate: (message) => { - queryClient.setQueryData(queryKey, () => message); + onMutate: async (message) => { + const msg = await onClientMessageReceived(message); + queryClient.setQueryData(queryKey, () => msg); debouncedInvalidate(); }, onDelete: () => { diff --git a/apps/meteor/tests/e2e/e2e-encryption.spec.ts b/apps/meteor/tests/e2e/e2e-encryption.spec.ts index c2d1fcc24cb7..69b77d1ceffb 100644 --- a/apps/meteor/tests/e2e/e2e-encryption.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption.spec.ts @@ -179,6 +179,40 @@ test.describe.serial('e2e-encryption', () => { await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); }); + test('expect create a private encrypted channel and send a encrypted thread message', async ({ page }) => { + const channelName = faker.string.uuid(); + + await poHomeChannel.sidenav.createEncryptedChannel(channelName); + + await expect(page).toHaveURL(`/group/${channelName}`); + + await poHomeChannel.dismissToast(); + + await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); + + await poHomeChannel.content.sendMessage('This is the thread main message.'); + + await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('This is the thread main message.'); + await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + + await page.locator('[data-qa-type="message"]').last().hover(); + await page.locator('role=button[name="Reply in thread"]').click(); + + await expect(page).toHaveURL(/.*thread/); + + await expect(poHomeChannel.content.mainThreadMessageText).toContainText('This is the thread main message.'); + await expect(poHomeChannel.content.mainThreadMessageText.locator('.rcx-icon--name-key')).toBeVisible(); + + await poHomeChannel.content.toggleAlsoSendThreadToChannel(true); + await page.getByRole('dialog').locator('[name="msg"]').last().fill('This is an encrypted thread message also sent in channel'); + await page.keyboard.press('Enter'); + await expect(poHomeChannel.content.lastThreadMessageText).toContainText('This is an encrypted thread message also sent in channel'); + await expect(poHomeChannel.content.lastThreadMessageText.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(poHomeChannel.content.lastUserMessage).toContainText('This is an encrypted thread message also sent in channel'); + await expect(poHomeChannel.content.mainThreadMessageText).toContainText('This is the thread main message.'); + await expect(poHomeChannel.content.mainThreadMessageText.locator('.rcx-icon--name-key')).toBeVisible(); + }); + test('expect create a private channel, encrypt it and send an encrypted message', async ({ page }) => { const channelName = faker.string.uuid(); diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts index 02f7dde09a85..786c5217dadf 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts @@ -143,6 +143,10 @@ export class HomeContent { return this.page.locator('div.thread-list ul.thread [data-qa-type="message"]').last().locator('.rcx-attachment__details'); } + get mainThreadMessageText(): Locator { + return this.page.locator('div.thread-list ul.thread [data-qa-type="message"]').first(); + } + get lastThreadMessageText(): Locator { return this.page.locator('div.thread-list ul.thread [data-qa-type="message"]').last(); } From 2ef71e8ea6793a59af45a8089b04177a2f48d153 Mon Sep 17 00:00:00 2001 From: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com> Date: Tue, 18 Jun 2024 02:58:53 +0530 Subject: [PATCH 24/94] feat: E2EE room setup header (#32446) Co-authored-by: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Co-authored-by: Hugo Costa <20212776+hugocostadev@users.noreply.github.com> --- .changeset/gold-flowers-shake.md | 6 +++ apps/meteor/client/ui.ts | 2 + .../client/views/room/Header/Header.tsx | 24 +++++++---- .../client/views/room/Header/RoomHeader.tsx | 5 ++- .../views/room/Header/RoomHeaderE2EESetup.tsx | 29 +++++++++++++ .../RoomToolbox/RoomToolboxE2EESetup.tsx | 41 +++++++++++++++++++ apps/meteor/tests/e2e/e2e-encryption.spec.ts | 23 +++++++++-- .../page-objects/fragments/home-flextab.ts | 4 ++ 8 files changed, 121 insertions(+), 13 deletions(-) create mode 100644 .changeset/gold-flowers-shake.md create mode 100644 apps/meteor/client/views/room/Header/RoomHeaderE2EESetup.tsx create mode 100644 apps/meteor/client/views/room/Header/RoomToolbox/RoomToolboxE2EESetup.tsx diff --git a/.changeset/gold-flowers-shake.md b/.changeset/gold-flowers-shake.md new file mode 100644 index 000000000000..26182d785c22 --- /dev/null +++ b/.changeset/gold-flowers-shake.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/i18n': minor +'@rocket.chat/meteor': minor +--- + +Added E2EE room setup header, with just limited functionality and room actions. diff --git a/apps/meteor/client/ui.ts b/apps/meteor/client/ui.ts index 98d3233134a5..6c7971a8cca0 100644 --- a/apps/meteor/client/ui.ts +++ b/apps/meteor/client/ui.ts @@ -78,3 +78,5 @@ export const quickActionHooks = [ useCloseChatQuickAction, useOnHoldChatQuickAction, ] satisfies (() => QuickActionsActionConfig | undefined)[]; + +export const roomActionHooksForE2EESetup = [useChannelSettingsRoomAction, useMembersListRoomAction, useE2EERoomAction]; diff --git a/apps/meteor/client/views/room/Header/Header.tsx b/apps/meteor/client/views/room/Header/Header.tsx index bd5537e0098f..c350544e8157 100644 --- a/apps/meteor/client/views/room/Header/Header.tsx +++ b/apps/meteor/client/views/room/Header/Header.tsx @@ -1,15 +1,16 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { isVoipRoom } from '@rocket.chat/core-typings'; +import { isDirectMessageRoom, isVoipRoom } from '@rocket.chat/core-typings'; import { HeaderToolbar } from '@rocket.chat/ui-client'; -import { useLayout } from '@rocket.chat/ui-contexts'; +import { useLayout, useSetting } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { lazy, memo, useMemo } from 'react'; import SidebarToggler from '../../../components/SidebarToggler'; -const DirectRoomHeader = lazy(() => import('./DirectRoomHeader')); const OmnichannelRoomHeader = lazy(() => import('./Omnichannel/OmnichannelRoomHeader')); const VoipRoomHeader = lazy(() => import('./Omnichannel/VoipRoomHeader')); +const RoomHeaderE2EESetup = lazy(() => import('./RoomHeaderE2EESetup')); +const DirectRoomHeader = lazy(() => import('./DirectRoomHeader')); const RoomHeader = lazy(() => import('./RoomHeader')); type HeaderProps = { @@ -18,6 +19,9 @@ type HeaderProps = { const Header = ({ room }: HeaderProps): ReactElement | null => { const { isMobile, isEmbedded, showTopNavbarEmbeddedLayout } = useLayout(); + const encrypted = Boolean(room.encrypted); + const unencryptedMessagesAllowed = useSetting('E2E_Allow_Unencrypted_Messages'); + const shouldDisplayE2EESetup = encrypted && !unencryptedMessagesAllowed; const slots = useMemo( () => ({ @@ -34,10 +38,6 @@ const Header = ({ room }: HeaderProps): ReactElement | null => { return null; } - if (room.t === 'd' && (room.uids?.length ?? 0) < 3) { - return ; - } - if (room.t === 'l') { return ; } @@ -46,7 +46,15 @@ const Header = ({ room }: HeaderProps): ReactElement | null => { return ; } - return ; + if (shouldDisplayE2EESetup) { + return ; + } + + if (isDirectMessageRoom(room) && (room.uids?.length ?? 0) < 3) { + return ; + } + + return ; }; export default memo(Header); diff --git a/apps/meteor/client/views/room/Header/RoomHeader.tsx b/apps/meteor/client/views/room/Header/RoomHeader.tsx index 05f80a984982..fee9be6a55a6 100644 --- a/apps/meteor/client/views/room/Header/RoomHeader.tsx +++ b/apps/meteor/client/views/room/Header/RoomHeader.tsx @@ -30,9 +30,10 @@ export type RoomHeaderProps = { pos?: unknown; }; }; + roomToolbox?: JSX.Element; }; -const RoomHeader = ({ room, topic = '', slots = {} }: RoomHeaderProps) => { +const RoomHeader = ({ room, topic = '', slots = {}, roomToolbox }: RoomHeaderProps) => { const t = useTranslation(); return ( @@ -65,7 +66,7 @@ const RoomHeader = ({ room, topic = '', slots = {} }: RoomHeaderProps) => { {slots?.toolbox?.pre} - {slots?.toolbox?.content || } + {slots?.toolbox?.content || roomToolbox || } {slots?.toolbox?.pos} diff --git a/apps/meteor/client/views/room/Header/RoomHeaderE2EESetup.tsx b/apps/meteor/client/views/room/Header/RoomHeaderE2EESetup.tsx new file mode 100644 index 000000000000..2b868c28882d --- /dev/null +++ b/apps/meteor/client/views/room/Header/RoomHeaderE2EESetup.tsx @@ -0,0 +1,29 @@ +import { isDirectMessageRoom } from '@rocket.chat/core-typings'; +import React, { lazy } from 'react'; + +import { E2EEState } from '../../../../app/e2e/client/E2EEState'; +import { E2ERoomState } from '../../../../app/e2e/client/E2ERoomState'; +import { useE2EERoomState } from '../hooks/useE2EERoomState'; +import { useE2EEState } from '../hooks/useE2EEState'; +import DirectRoomHeader from './DirectRoomHeader'; +import RoomHeader from './RoomHeader'; +import type { RoomHeaderProps } from './RoomHeader'; + +const RoomToolboxE2EESetup = lazy(() => import('./RoomToolbox/RoomToolboxE2EESetup')); + +const RoomHeaderE2EESetup = ({ room, topic = '', slots = {} }: RoomHeaderProps) => { + const e2eeState = useE2EEState(); + const e2eRoomState = useE2EERoomState(room._id); + + if (e2eeState === E2EEState.SAVE_PASSWORD || e2eeState === E2EEState.ENTER_PASSWORD || e2eRoomState === E2ERoomState.WAITING_KEYS) { + return } />; + } + + if (isDirectMessageRoom(room) && (room.uids?.length ?? 0) < 3) { + return ; + } + + return ; +}; + +export default RoomHeaderE2EESetup; diff --git a/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolboxE2EESetup.tsx b/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolboxE2EESetup.tsx new file mode 100644 index 000000000000..9b79dff5a6bd --- /dev/null +++ b/apps/meteor/client/views/room/Header/RoomToolbox/RoomToolboxE2EESetup.tsx @@ -0,0 +1,41 @@ +import { useStableArray } from '@rocket.chat/fuselage-hooks'; +import { HeaderToolbarAction } from '@rocket.chat/ui-client'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import React from 'react'; + +import { roomActionHooksForE2EESetup } from '../../../../ui'; +import type { RoomToolboxActionConfig } from '../../contexts/RoomToolboxContext'; +import { useRoomToolbox } from '../../contexts/RoomToolboxContext'; + +const RoomToolboxE2EESetup = () => { + const t = useTranslation(); + const toolbox = useRoomToolbox(); + + const { tab } = toolbox; + + const actions = useStableArray( + roomActionHooksForE2EESetup + .map((roomActionHook) => roomActionHook()) + .filter((roomAction): roomAction is RoomToolboxActionConfig => !!roomAction), + ); + + return ( + <> + {actions.map(({ id, icon, title, action, disabled, tooltip }, index) => ( + toolbox.openTab(id))} + disabled={disabled} + tooltip={tooltip} + /> + ))} + + ); +}; + +export default RoomToolboxE2EESetup; diff --git a/apps/meteor/tests/e2e/e2e-encryption.spec.ts b/apps/meteor/tests/e2e/e2e-encryption.spec.ts index 69b77d1ceffb..8b0753c952d2 100644 --- a/apps/meteor/tests/e2e/e2e-encryption.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption.spec.ts @@ -429,11 +429,17 @@ test.describe.serial('e2ee room setup', () => { await poHomeChannel.dismissToast(); - await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); + await poHomeChannel.content.encryptedRoomHeaderIcon.first().waitFor(); + await expect(poHomeChannel.content.encryptedRoomHeaderIcon.first()).toBeVisible(); await page.locator('role=button[name="Save E2EE password"]').waitFor(); await expect(page.locator('role=button[name="Save E2EE password"]')).toBeVisible(); + await poHomeChannel.tabs.btnE2EERoomSetupDisableE2E.waitFor(); + await expect(poHomeChannel.tabs.btnE2EERoomSetupDisableE2E).toBeVisible(); + await expect(poHomeChannel.tabs.btnTabMembers).toBeVisible(); + await expect(poHomeChannel.tabs.btnRoomInfo).toBeVisible(); + await expect(poHomeChannel.content.inputMessage).not.toBeVisible(); await page.locator('role=button[name="Save E2EE password"]').click(); @@ -477,11 +483,17 @@ test.describe.serial('e2ee room setup', () => { await poHomeChannel.dismissToast(); - await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); + await expect(poHomeChannel.content.encryptedRoomHeaderIcon.first()).toBeVisible(); await page.locator('role=button[name="Enter your E2E password"]').waitFor(); await expect(page.locator('role=banner >> text="Enter your E2E password"')).toBeVisible(); + + await poHomeChannel.tabs.btnE2EERoomSetupDisableE2E.waitFor(); + await expect(poHomeChannel.tabs.btnE2EERoomSetupDisableE2E).toBeVisible(); + await expect(poHomeChannel.tabs.btnTabMembers).toBeVisible(); + await expect(poHomeChannel.tabs.btnRoomInfo).toBeVisible(); + await expect(poHomeChannel.content.inputMessage).not.toBeVisible(); await page.locator('role=button[name="Enter your E2E password"]').click(); @@ -518,7 +530,7 @@ test.describe.serial('e2ee room setup', () => { await poHomeChannel.dismissToast(); - await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); + await expect(poHomeChannel.content.encryptedRoomHeaderIcon.first()).toBeVisible(); await poHomeChannel.content.sendMessage('hello world'); @@ -551,5 +563,10 @@ test.describe.serial('e2ee room setup', () => { await expect(poHomeChannel.content.inputMessage).not.toBeVisible(); await expect(page.locator('.rcx-states__title')).toContainText('Check back later'); + + await poHomeChannel.tabs.btnE2EERoomSetupDisableE2E.waitFor(); + await expect(poHomeChannel.tabs.btnE2EERoomSetupDisableE2E).toBeVisible(); + await expect(poHomeChannel.tabs.btnTabMembers).toBeVisible(); + await expect(poHomeChannel.tabs.btnRoomInfo).toBeVisible(); }); }); diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts index b8bd673c9cf3..a6d91bc6fc34 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts @@ -44,6 +44,10 @@ export class HomeFlextab { return this.page.locator('role=menuitem[name="Notifications Preferences"]'); } + get btnE2EERoomSetupDisableE2E(): Locator { + return this.page.locator('[data-qa-id=ToolBoxAction-key]'); + } + get btnDisableE2E(): Locator { return this.page.locator('role=menuitem[name="Disable E2E"]'); } From 4f72d62aa73b12456280861be884c99a1e12c2a1 Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Mon, 17 Jun 2024 19:17:08 -0300 Subject: [PATCH 25/94] feat: Apps-Engine Deno Runtime update (#31821) Co-authored-by: Rafael Tapia <18501599+tapiarafael@users.noreply.github.com> --- .changeset/tame-weeks-shout.md | 41 +++ .github/actions/setup-node/action.yml | 8 + apps/meteor/.docker/Dockerfile | 25 +- apps/meteor/.docker/Dockerfile.alpine | 73 ++++- .../app/apps/server/bridges/commands.ts | 8 +- apps/meteor/app/apps/server/bridges/http.ts | 94 +++--- .../app/metrics/server/lib/collectMetrics.ts | 2 +- .../server/lib/getAppsStatistics.js | 18 - .../server/lib/getAppsStatistics.ts | 51 +++ .../app/statistics/server/lib/statistics.ts | 2 +- .../ee/lib/misc/formatAppInstanceForRest.ts | 4 +- .../endpoints/appsCountHandler.ts | 4 +- .../ee/server/apps/communication/rest.ts | 26 +- .../server/apps/communication/websockets.ts | 4 +- apps/meteor/ee/server/apps/cron.ts | 2 +- apps/meteor/ee/server/apps/orchestrator.js | 49 +-- .../server/apps/storage/AppRealLogStorage.ts | 36 ++ apps/meteor/ee/server/apps/storage/index.js | 2 +- .../ee/server/apps/storage/logs-storage.js | 32 -- apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- .../server/services/apps-engine/service.ts | 7 +- .../apps/02-send-messages-as-user.js | 2 +- docker-compose-ci.yml | 1 + ee/apps/ddp-streamer/package.json | 2 +- ee/packages/presence/package.json | 2 +- packages/apps/package.json | 2 +- packages/core-services/package.json | 2 +- packages/core-typings/package.json | 2 +- packages/fuselage-ui-kit/package.json | 2 +- .../model-typings/src/models/IAppLogsModel.ts | 3 + packages/rest-typings/package.json | 2 +- yarn.lock | 310 +++++++++++++++++- 33 files changed, 622 insertions(+), 200 deletions(-) create mode 100644 .changeset/tame-weeks-shout.md delete mode 100644 apps/meteor/app/statistics/server/lib/getAppsStatistics.js create mode 100644 apps/meteor/app/statistics/server/lib/getAppsStatistics.ts create mode 100644 apps/meteor/ee/server/apps/storage/AppRealLogStorage.ts delete mode 100644 apps/meteor/ee/server/apps/storage/logs-storage.js diff --git a/.changeset/tame-weeks-shout.md b/.changeset/tame-weeks-shout.md new file mode 100644 index 000000000000..72bfc864274f --- /dev/null +++ b/.changeset/tame-weeks-shout.md @@ -0,0 +1,41 @@ +--- +'@rocket.chat/omnichannel-services': minor +'rocketchat-services': minor +'@rocket.chat/omnichannel-transcript': minor +'@rocket.chat/authorization-service': minor +'@rocket.chat/web-ui-registration': minor +'@rocket.chat/stream-hub-service': minor +'@rocket.chat/uikit-playground': minor +'@rocket.chat/presence-service': minor +'@rocket.chat/fuselage-ui-kit': minor +'@rocket.chat/instance-status': minor +'@rocket.chat/account-service': minor +'@rocket.chat/mock-providers': minor +'@rocket.chat/api-client': minor +'@rocket.chat/ddp-client': minor +'@rocket.chat/pdf-worker': minor +'@rocket.chat/ui-theming': minor +'@rocket.chat/core-services': minor +'@rocket.chat/model-typings': minor +'@rocket.chat/ui-video-conf': minor +'@rocket.chat/core-typings': minor +'@rocket.chat/rest-typings': minor +'@rocket.chat/ddp-streamer': minor +'@rocket.chat/queue-worker': minor +'@rocket.chat/presence': minor +'@rocket.chat/ui-composer': minor +'@rocket.chat/ui-contexts': minor +'@rocket.chat/license': minor +'@rocket.chat/gazzodown': minor +'@rocket.chat/ui-avatar': minor +'@rocket.chat/ui-client': minor +'@rocket.chat/livechat': minor +'@rocket.chat/models': minor +'@rocket.chat/ui-kit': minor +'@rocket.chat/apps': minor +'@rocket.chat/cron': minor +'@rocket.chat/i18n': minor +'@rocket.chat/meteor': minor +--- + +New runtime for apps in the Apps-Engine based on the Deno platform diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml index 0e921e81f1f3..caa3c63e00f0 100644 --- a/.github/actions/setup-node/action.yml +++ b/.github/actions/setup-node/action.yml @@ -10,6 +10,10 @@ inputs: install: required: false type: boolean + deno-dir: + required: false + type: string + default: ~/.deno-cache outputs: node-version: @@ -19,6 +23,9 @@ runs: using: composite steps: + - run: echo 'DENO_DIR=${{ inputs.deno-dir }}' >> $GITHUB_ENV + shell: bash + - name: Cache Node Modules if: inputs.cache-modules id: cache-node-modules @@ -26,6 +33,7 @@ runs: with: path: | node_modules + ${{ env.DENO_DIR }} apps/meteor/node_modules apps/meteor/ee/server/services/node_modules key: node-modules-${{ hashFiles('yarn.lock') }} diff --git a/apps/meteor/.docker/Dockerfile b/apps/meteor/.docker/Dockerfile index 456ed4becafd..1e9ed3f5e592 100644 --- a/apps/meteor/.docker/Dockerfile +++ b/apps/meteor/.docker/Dockerfile @@ -13,12 +13,24 @@ RUN groupadd -g 65533 -r rocketchat \ # --chown requires Docker 17.12 and works only on Linux ADD --chown=rocketchat:rocketchat . /app +# needs a mongoinstance - defaults to container linking with alias 'mongo' +ENV DEPLOY_METHOD=docker \ + NODE_ENV=production \ + MONGO_URL=mongodb://mongo:27017/rocketchat \ + HOME=/tmp \ + PORT=3000 \ + ROOT_URL=http://localhost:3000 \ + Accounts_AvatarStorePath=/app/uploads \ + DENO_DIR=/usr/share/deno + RUN aptMark="$(apt-mark showmanual)" \ && apt-get install -y --no-install-recommends g++ make python3 ca-certificates \ && cd /app/bundle/programs/server \ && npm install \ - && cd npm/node_modules/isolated-vm \ - && npm install \ + && cd npm/node_modules/isolated-vm \ + && npm install \ + && cd /app/bundle/programs/server/npm/node_modules/@rocket.chat/apps-engine/deno-runtime \ + && ../../../deno-bin/bin/deno cache main.ts \ && apt-mark auto '.*' > /dev/null \ && apt-mark manual $aptMark > /dev/null \ && find /usr/local -type f -executable -exec ldd '{}' ';' \ @@ -37,15 +49,6 @@ VOLUME /app/uploads WORKDIR /app/bundle -# needs a mongoinstance - defaults to container linking with alias 'mongo' -ENV DEPLOY_METHOD=docker \ - NODE_ENV=production \ - MONGO_URL=mongodb://mongo:27017/rocketchat \ - HOME=/tmp \ - PORT=3000 \ - ROOT_URL=http://localhost:3000 \ - Accounts_AvatarStorePath=/app/uploads - EXPOSE 3000 CMD ["node", "main.js"] diff --git a/apps/meteor/.docker/Dockerfile.alpine b/apps/meteor/.docker/Dockerfile.alpine index 94baef809217..feebf76a03e7 100644 --- a/apps/meteor/.docker/Dockerfile.alpine +++ b/apps/meteor/.docker/Dockerfile.alpine @@ -1,13 +1,68 @@ FROM node:14.21.3-alpine3.16 -RUN apk add --no-cache ttf-dejavu +ENV LANG=C.UTF-8 + +# Installing glibc deps required by Deno +# This replaces libc6-compat +# Copied from https://github.com/Docker-Hub-frolvlad/docker-alpine-glibc, which denoland/deno:alpine-1.37.1 uses +# NOTE: Glibc 2.35 package is broken: https://github.com/sgerrand/alpine-pkg-glibc/issues/176, so we stick to 2.34 for now +RUN ALPINE_GLIBC_BASE_URL="https://github.com/sgerrand/alpine-pkg-glibc/releases/download" && \ + ALPINE_GLIBC_PACKAGE_VERSION="2.34-r0" && \ + ALPINE_GLIBC_BASE_PACKAGE_FILENAME="glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \ + ALPINE_GLIBC_BIN_PACKAGE_FILENAME="glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \ + ALPINE_GLIBC_I18N_PACKAGE_FILENAME="glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \ + apk add --no-cache --virtual=.build-dependencies wget ca-certificates && \ + echo \ + "-----BEGIN PUBLIC KEY-----\ + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApZ2u1KJKUu/fW4A25y9m\ + y70AGEa/J3Wi5ibNVGNn1gT1r0VfgeWd0pUybS4UmcHdiNzxJPgoWQhV2SSW1JYu\ + tOqKZF5QSN6X937PTUpNBjUvLtTQ1ve1fp39uf/lEXPpFpOPL88LKnDBgbh7wkCp\ + m2KzLVGChf83MS0ShL6G9EQIAUxLm99VpgRjwqTQ/KfzGtpke1wqws4au0Ab4qPY\ + KXvMLSPLUp7cfulWvhmZSegr5AdhNw5KNizPqCJT8ZrGvgHypXyiFvvAH5YRtSsc\ + Zvo9GI2e2MaZyo9/lvb+LbLEJZKEQckqRj4P26gmASrZEPStwc+yqy1ShHLA0j6m\ + 1QIDAQAB\ + -----END PUBLIC KEY-----" | sed 's/ */\n/g' > "/etc/apk/keys/sgerrand.rsa.pub" && \ + wget \ + "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \ + "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \ + "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \ + mv /etc/nsswitch.conf /etc/nsswitch.conf.bak && \ + apk add --no-cache --force-overwrite \ + "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \ + "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \ + "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \ + \ + mv /etc/nsswitch.conf.bak /etc/nsswitch.conf && \ + rm "/etc/apk/keys/sgerrand.rsa.pub" && \ + (/usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true) && \ + echo "export LANG=$LANG" > /etc/profile.d/locale.sh && \ + \ + apk del glibc-i18n && \ + \ + rm "/root/.wget-hsts" && \ + apk del .build-dependencies && \ + rm \ + "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \ + "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \ + "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \ + apk add --no-cache ttf-dejavu ADD . /app LABEL maintainer="buildmaster@rocket.chat" +# needs a mongo instance - defaults to container linking with alias 'mongo' +ENV DEPLOY_METHOD=docker \ + NODE_ENV=production \ + MONGO_URL=mongodb://mongo:27017/rocketchat \ + HOME=/tmp \ + PORT=3000 \ + ROOT_URL=http://localhost:3000 \ + Accounts_AvatarStorePath=/app/uploads \ + DENO_DIR=/usr/share/deno + RUN set -x \ - && apk add --no-cache --virtual .fetch-deps python3 make g++ libc6-compat \ + && apk add --no-cache --virtual .fetch-deps python3 make g++ \ && cd /app/bundle/programs/server \ && npm install --production \ # Start hack for sharp... @@ -20,20 +75,14 @@ RUN set -x \ && npm install isolated-vm@4.4.2 \ && mv node_modules/isolated-vm npm/node_modules/isolated-vm \ # End hack for isolated-vm - && cd npm \ + # Cache Deno dependencies for Apps-Engine + && cd npm/node_modules/@rocket.chat/apps-engine/deno-runtime \ + && /app/bundle/programs/server/npm/node_modules/deno-bin/bin/deno cache main.ts \ + && cd /app/bundle/programs/server/npm \ && npm rebuild bcrypt --build-from-source \ && npm cache clear --force \ && apk del .fetch-deps -# needs a mongo instance - defaults to container linking with alias 'mongo' -ENV DEPLOY_METHOD=docker \ - NODE_ENV=production \ - MONGO_URL=mongodb://mongo:27017/rocketchat \ - HOME=/tmp \ - PORT=3000 \ - ROOT_URL=http://localhost:3000 \ - Accounts_AvatarStorePath=/app/uploads - VOLUME /app/uploads WORKDIR /app/bundle diff --git a/apps/meteor/app/apps/server/bridges/commands.ts b/apps/meteor/app/apps/server/bridges/commands.ts index 5e018c51de89..5ffef6473051 100644 --- a/apps/meteor/app/apps/server/bridges/commands.ts +++ b/apps/meteor/app/apps/server/bridges/commands.ts @@ -111,8 +111,8 @@ export class AppCommandsBridge extends CommandBridge { permission: command.permission, callback: this._appCommandExecutor.bind(this), providesPreview: command.providesPreview, - previewer: !command.previewer ? undefined : this._appCommandPreviewer.bind(this), - previewCallback: (!command.executePreviewItem ? undefined : this._appCommandPreviewExecutor.bind(this)) as + previewer: command.providesPreview ? this._appCommandPreviewer.bind(this) : undefined, + previewCallback: (command.providesPreview ? this._appCommandPreviewExecutor.bind(this) : undefined) as | (typeof slashCommands.commands)[string]['previewCallback'] | undefined, } as SlashCommand; @@ -155,10 +155,6 @@ export class AppCommandsBridge extends CommandBridge { if (typeof command.providesPreview !== 'boolean') { throw new Error('Invalid Slash Command parameter provided, it must be a valid ISlashCommand object.'); } - - if (typeof command.executor !== 'function') { - throw new Error('Invalid Slash Command parameter provided, it must be a valid ISlashCommand object.'); - } } private async _appCommandExecutor({ command, message, params, triggerId, userId }: SlashCommandCallbackParams): Promise { diff --git a/apps/meteor/app/apps/server/bridges/http.ts b/apps/meteor/app/apps/server/bridges/http.ts index 1535a18823c5..9d62769336a2 100644 --- a/apps/meteor/app/apps/server/bridges/http.ts +++ b/apps/meteor/app/apps/server/bridges/http.ts @@ -72,55 +72,51 @@ export class AppHttpBridge extends HttpBridge { this.orch.debugLog(`The App ${info.appId} is requesting from the outter webs:`, info); - try { - const response = await fetch( - url.href, - { - method, - body: content, - headers, - timeout, - }, - (request.hasOwnProperty('strictSSL') && !request.strictSSL) || - (request.hasOwnProperty('rejectUnauthorized') && request.rejectUnauthorized), - ); - - const result: IHttpResponse = { - url: info.url, - method: info.method, - statusCode: response.status, - headers: Object.fromEntries(response.headers as unknown as any), - }; - - const body = Buffer.from(await response.arrayBuffer()); - - if (request.encoding === null) { - /** - * The property `content` is not appropriately typed in the - * Apps-engine definition, and we can't simply change it there - * as it would be a breaking change. Thus, we're left with this - * type assertion. - */ - result.content = body as any; - } else { - result.content = body.toString(request.encoding as BufferEncoding); - result.data = ((): any => { - const contentType = (response.headers.get('content-type') || '').split(';')[0]; - if (!['application/json', 'text/javascript', 'application/javascript', 'application/x-javascript'].includes(contentType)) { - return null; - } - - try { - return JSON.parse(result.content); - } catch { - return null; - } - })(); - } - - return result; - } catch (e: any) { - return e.response; + const response = await fetch( + url.href, + { + method, + body: content, + headers, + timeout, + }, + (request.hasOwnProperty('strictSSL') && !request.strictSSL) || + (request.hasOwnProperty('rejectUnauthorized') && request.rejectUnauthorized), + ); + + const result: IHttpResponse = { + url: info.url, + method: info.method, + statusCode: response.status, + headers: Object.fromEntries(response.headers as unknown as any), + }; + + const body = Buffer.from(await response.arrayBuffer()); + + if (request.encoding === null) { + /** + * The property `content` is not appropriately typed in the + * Apps-engine definition, and we can't simply change it there + * as it would be a breaking change. Thus, we're left with this + * type assertion. + */ + result.content = body as any; + } else { + result.content = body.toString(request.encoding as BufferEncoding); + result.data = ((): any => { + const contentType = (response.headers.get('content-type') || '').split(';')[0]; + if (!['application/json', 'text/javascript', 'application/javascript', 'application/x-javascript'].includes(contentType)) { + return null; + } + + try { + return JSON.parse(result.content); + } catch { + return null; + } + })(); } + + return result; } } diff --git a/apps/meteor/app/metrics/server/lib/collectMetrics.ts b/apps/meteor/app/metrics/server/lib/collectMetrics.ts index 136686f49c9e..978b3d59ec98 100644 --- a/apps/meteor/app/metrics/server/lib/collectMetrics.ts +++ b/apps/meteor/app/metrics/server/lib/collectMetrics.ts @@ -39,7 +39,7 @@ const setPrometheusData = async (): Promise => { metrics.ddpConnectedUsers.set(_.unique(authenticatedSessions.map((s) => s.userId)).length); // Apps metrics - const { totalInstalled, totalActive, totalFailed } = getAppsStatistics(); + const { totalInstalled, totalActive, totalFailed } = await getAppsStatistics(); metrics.totalAppsInstalled.set(totalInstalled || 0); metrics.totalAppsEnabled.set(totalActive || 0); diff --git a/apps/meteor/app/statistics/server/lib/getAppsStatistics.js b/apps/meteor/app/statistics/server/lib/getAppsStatistics.js deleted file mode 100644 index 1d84bead3e85..000000000000 --- a/apps/meteor/app/statistics/server/lib/getAppsStatistics.js +++ /dev/null @@ -1,18 +0,0 @@ -import { Apps } from '@rocket.chat/apps'; -import { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; - -import { Info } from '../../../utils/rocketchat.info'; - -export function getAppsStatistics() { - return { - engineVersion: Info.marketplaceApiVersion, - totalInstalled: (Apps.self?.isInitialized() && Apps.getManager().get().length) ?? 0, - totalActive: (Apps.self?.isInitialized() && Apps.getManager().get({ enabled: true }).length) ?? 0, - totalFailed: - (Apps.self?.isInitialized() && - Apps.getManager() - .get({ disabled: true }) - .filter(({ app: { status } }) => status !== AppStatus.MANUALLY_DISABLED).length) ?? - 0, - }; -} diff --git a/apps/meteor/app/statistics/server/lib/getAppsStatistics.ts b/apps/meteor/app/statistics/server/lib/getAppsStatistics.ts new file mode 100644 index 000000000000..930fc15a9c55 --- /dev/null +++ b/apps/meteor/app/statistics/server/lib/getAppsStatistics.ts @@ -0,0 +1,51 @@ +import { Apps } from '@rocket.chat/apps'; +import { AppStatus, AppStatusUtils } from '@rocket.chat/apps-engine/definition/AppStatus'; + +import { Info } from '../../../utils/rocketchat.info'; + +export type AppsStatistics = { + engineVersion: string; + totalInstalled: number | false; + totalActive: number | false; + totalFailed: number | false; +}; + +export async function getAppsStatistics(): Promise { + if (!Apps.self?.isInitialized()) { + return { + engineVersion: Info.marketplaceApiVersion, + totalInstalled: false, + totalActive: false, + totalFailed: false, + }; + } + + const apps = await Apps.getManager().get(); + + let totalInstalled = 0; + let totalActive = 0; + let totalFailed = 0; + + await Promise.all( + apps.map(async (app) => { + totalInstalled++; + + const status = await app.getStatus(); + + if (status === AppStatus.MANUALLY_DISABLED) { + totalFailed++; + } + + if (AppStatusUtils.isEnabled(status)) { + totalActive++; + } + }), + ); + + return { + engineVersion: Info.marketplaceApiVersion, + totalInstalled, + totalActive, + totalFailed, + }; +} diff --git a/apps/meteor/app/statistics/server/lib/statistics.ts b/apps/meteor/app/statistics/server/lib/statistics.ts index a6fcc5b17b5b..cff2aaefcc5a 100644 --- a/apps/meteor/app/statistics/server/lib/statistics.ts +++ b/apps/meteor/app/statistics/server/lib/statistics.ts @@ -467,7 +467,7 @@ export const statistics = { }), ); - statistics.apps = getAppsStatistics(); + statistics.apps = await getAppsStatistics(); statistics.services = await getServicesStatistics(); statistics.importer = getImporterStatistics(); statistics.videoConf = await VideoConf.getStatistics(); diff --git a/apps/meteor/ee/lib/misc/formatAppInstanceForRest.ts b/apps/meteor/ee/lib/misc/formatAppInstanceForRest.ts index d76b7ae59aeb..bf096122c50f 100644 --- a/apps/meteor/ee/lib/misc/formatAppInstanceForRest.ts +++ b/apps/meteor/ee/lib/misc/formatAppInstanceForRest.ts @@ -14,10 +14,10 @@ interface IAppInfoRest extends IAppInfo { migrated: boolean; } -export function formatAppInstanceForRest(app: ProxiedApp): IAppInfoRest { +export async function formatAppInstanceForRest(app: ProxiedApp): Promise { const appRest: IAppInfoRest = { ...app.getInfo(), - status: app.getStatus(), + status: await app.getStatus(), languages: app.getStorageItem().languageContent, private: getInstallationSourceFromAppStorageItem(app.getStorageItem()) === 'private', migrated: !!app.getStorageItem().migrated, diff --git a/apps/meteor/ee/server/apps/communication/endpoints/appsCountHandler.ts b/apps/meteor/ee/server/apps/communication/endpoints/appsCountHandler.ts index fc436b8229cf..878dd9aab92c 100644 --- a/apps/meteor/ee/server/apps/communication/endpoints/appsCountHandler.ts +++ b/apps/meteor/ee/server/apps/communication/endpoints/appsCountHandler.ts @@ -19,10 +19,10 @@ export const appsCountHandler = (apiManager: AppsRestApi) => authRequired: false, }, { - get(): SuccessResult { + async get(): Promise> { const manager = apiManager._manager as AppManager; - const apps = manager.get({ enabled: true }); + const apps = await manager.get({ enabled: true }); const { maxMarketplaceApps, maxPrivateApps } = License.getAppsConfig(); return API.v1.success({ diff --git a/apps/meteor/ee/server/apps/communication/rest.ts b/apps/meteor/ee/server/apps/communication/rest.ts index df30cccc8e73..02f8aeb7b344 100644 --- a/apps/meteor/ee/server/apps/communication/rest.ts +++ b/apps/meteor/ee/server/apps/communication/rest.ts @@ -209,8 +209,9 @@ export class AppsRestApi { { authRequired: true }, { async get() { - const apps = manager.get().map(formatAppInstanceForRest); - return API.v1.success({ apps }); + const apps = await manager.get(); + const formatted = await Promise.all(apps.map(formatAppInstanceForRest)); + return API.v1.success({ apps: formatted }); }, }, ); @@ -302,7 +303,8 @@ export class AppsRestApi { } apiDeprecationLogger.endpoint(this.request.route, '7.0.0', this.response, 'Use /apps/installed to get the installed apps list.'); - const apps = manager.get().map(formatAppInstanceForRest); + const proxiedApps = await manager.get(); + const apps = await Promise.all(proxiedApps.map(formatAppInstanceForRest)); return API.v1.success({ apps }); }, @@ -412,7 +414,7 @@ export class AppsRestApi { }); } - info.status = aff.getApp().getStatus(); + info.status = await aff.getApp().getStatus(); void notifyAppInstall(orchestrator.getMarketplaceUrl() as string, 'install', info); @@ -508,8 +510,8 @@ export class AppsRestApi { 'languages', { authRequired: false }, { - get() { - const apps = manager.get().map((prl) => ({ + async get() { + const apps = (await manager.get()).map((prl) => ({ id: prl.getID(), languages: prl.getStorageItem().languageContent, })); @@ -760,7 +762,7 @@ export class AppsRestApi { }); } - info.status = aff.getApp().getStatus(); + info.status = await aff.getApp().getStatus(); void notifyAppInstall(orchestrator.getMarketplaceUrl() as string, 'update', info); @@ -784,10 +786,14 @@ export class AppsRestApi { ?.get('users') .convertToApp(await Meteor.userAsync()); - await manager.remove(prl.getID(), { user }); - const info: IAppInfo & { status?: AppStatus } = prl.getInfo(); - info.status = prl.getStatus(); + try { + await manager.remove(prl.getID(), { user }); + info.status = AppStatus.DISABLED; + } catch (e) { + info.status = await prl.getStatus(); + return API.v1.failure({ app: info }); + } void notifyAppInstall(orchestrator.getMarketplaceUrl() as string, 'uninstall', info); diff --git a/apps/meteor/ee/server/apps/communication/websockets.ts b/apps/meteor/ee/server/apps/communication/websockets.ts index 65a2a73ca063..83a161427143 100644 --- a/apps/meteor/ee/server/apps/communication/websockets.ts +++ b/apps/meteor/ee/server/apps/communication/websockets.ts @@ -51,7 +51,7 @@ export class AppServerListener { async onAppStatusUpdated({ appId, status }: { appId: string; status: AppStatus }): Promise { const app = this.orch.getManager()?.getOneById(appId); - if (!app || app.getStatus() === status) { + if (!app || (await app.getStatus()) === status) { return; } @@ -76,10 +76,12 @@ export class AppServerListener { setting, when: new Date(), }); + await this.orch .getManager()! .getSettingsManager() .updateAppSetting(appId, setting as any); // TO-DO: fix type of `setting` + this.clientStreamer.emitWithoutBroadcast(AppEvents.APP_SETTING_UPDATED, { appId, setting }); } diff --git a/apps/meteor/ee/server/apps/cron.ts b/apps/meteor/ee/server/apps/cron.ts index e58610d2cbf0..f904486bf610 100644 --- a/apps/meteor/ee/server/apps/cron.ts +++ b/apps/meteor/ee/server/apps/cron.ts @@ -57,7 +57,7 @@ const notifyAdminsAboutRenewedApps = async function _notifyAdminsAboutRenewedApp } const renewedApps = apps.filter( - (app) => app.getStatus() === AppStatus.DISABLED && app.getPreviousStatus() === AppStatus.INVALID_LICENSE_DISABLED, + async (app) => (await app.getStatus()) === AppStatus.DISABLED && app.getPreviousStatus() === AppStatus.INVALID_LICENSE_DISABLED, ); if (renewedApps.length === 0) { diff --git a/apps/meteor/ee/server/apps/orchestrator.js b/apps/meteor/ee/server/apps/orchestrator.js index 37c31e890e89..c252579138cb 100644 --- a/apps/meteor/ee/server/apps/orchestrator.js +++ b/apps/meteor/ee/server/apps/orchestrator.js @@ -21,7 +21,7 @@ import { AppThreadsConverter } from '../../../app/apps/server/converters/threads import { settings } from '../../../app/settings/server'; import { canEnableApp } from '../../app/license/server/canEnableApp'; import { AppServerNotifier, AppsRestApi, AppUIKitInteractionApi } from './communication'; -import { AppRealLogsStorage, AppRealStorage, ConfigurableAppSourceStorage } from './storage'; +import { AppRealLogStorage, AppRealStorage, ConfigurableAppSourceStorage } from './storage'; function isTesting() { return process.env.TEST_MODE === 'true'; @@ -54,7 +54,7 @@ export class AppServerOrchestrator { this._logModel = AppLogs; this._persistModel = AppsPersistence; this._storage = new AppRealStorage(this._model); - this._logStorage = new AppRealLogsStorage(this._logModel); + this._logStorage = new AppRealLogStorage(this._logModel); this._appSourceStorage = new ConfigurableAppSourceStorage(appsSourceStorageType, appsSourceStorageFilesystemPath); this._converters = new Map(); @@ -172,34 +172,35 @@ export class AppServerOrchestrator { await this.getManager().load(); // Before enabling each app we verify if there is still room for it - await this.getManager() - .get() - // We reduce everything to a promise chain so it runs sequentially - .reduce( - (control, app) => - control.then(async () => { - const canEnable = await canEnableApp(app.getStorageItem()); - - if (canEnable) { - return this.getManager().loadOne(app.getID()); - } - - this._rocketchatLogger.warn(`App "${app.getInfo().name}" can't be enabled due to CE limits.`); - }), - Promise.resolve(), - ); + const apps = await this.getManager().get(); + + /* eslint-disable no-await-in-loop */ + // This needs to happen sequentially to keep track of app limits + for (const app of apps) { + const canEnable = await canEnableApp(app.getStorageItem()); + + if (!canEnable) { + this._rocketchatLogger.warn(`App "${app.getInfo().name}" can't be enabled due to CE limits.`); + // We need to continue as the limits are applied depending on the app installation source + // i.e. if one limit is hit, we can't break the loop as the following apps might still be valid + continue; + } + + await this.getManager().loadOne(app.getID()); + } + /* eslint-enable no-await-in-loop */ await this.getBridges().getSchedulerBridge().startScheduler(); - this._rocketchatLogger.info(`Loaded the Apps Framework and loaded a total of ${this.getManager().get({ enabled: true }).length} Apps!`); + const appCount = (await this.getManager().get({ enabled: true })).length; + + this._rocketchatLogger.info(`Loaded the Apps Framework and loaded a total of ${appCount} Apps!`); } async disableApps() { - await this.getManager() - .get() - .forEach((app) => { - this.getManager().disable(app.getID()); - }); + const apps = await this.getManager().get(); + + await Promise.all(apps.map((app) => this.getManager().disable(app.getID()))); } async unload() { diff --git a/apps/meteor/ee/server/apps/storage/AppRealLogStorage.ts b/apps/meteor/ee/server/apps/storage/AppRealLogStorage.ts new file mode 100644 index 000000000000..17a8f2f838aa --- /dev/null +++ b/apps/meteor/ee/server/apps/storage/AppRealLogStorage.ts @@ -0,0 +1,36 @@ +import type { ILoggerStorageEntry } from '@rocket.chat/apps-engine/server/logging'; +import type { IAppLogStorageFindOptions } from '@rocket.chat/apps-engine/server/storage'; +import { AppLogStorage } from '@rocket.chat/apps-engine/server/storage'; +import { InstanceStatus } from '@rocket.chat/instance-status'; +import type { AppLogs } from '@rocket.chat/models'; + +export class AppRealLogStorage extends AppLogStorage { + constructor(private db: typeof AppLogs) { + super('mongodb'); + } + + async find( + query: { + [field: string]: any; + }, + { fields, ...options }: IAppLogStorageFindOptions, + ): Promise { + return this.db.findPaginated(query, { projection: fields, ...options }).cursor.toArray(); + } + + async storeEntries(logEntry: ILoggerStorageEntry): Promise { + logEntry.instanceId = InstanceStatus.id(); + + const id = (await this.db.insertOne(logEntry)).insertedId; + + return this.db.findOneById(id); + } + + async getEntriesFor(appId: string): Promise { + return this.db.find({ appId }).toArray(); + } + + async removeEntriesFor(appId: string): Promise { + await this.db.deleteOne({ appId }); + } +} diff --git a/apps/meteor/ee/server/apps/storage/index.js b/apps/meteor/ee/server/apps/storage/index.js index 7f8d90715a96..7b8d2f5af96e 100644 --- a/apps/meteor/ee/server/apps/storage/index.js +++ b/apps/meteor/ee/server/apps/storage/index.js @@ -1,6 +1,6 @@ import './AppFileSystemSourceStorage'; import './AppGridFSSourceStorage'; -export { AppRealLogsStorage } from './logs-storage'; +export { AppRealLogStorage } from './AppRealLogStorage'; export { AppRealStorage } from './AppRealStorage'; export { ConfigurableAppSourceStorage } from './ConfigurableAppSourceStorage'; diff --git a/apps/meteor/ee/server/apps/storage/logs-storage.js b/apps/meteor/ee/server/apps/storage/logs-storage.js deleted file mode 100644 index b48599ca2d38..000000000000 --- a/apps/meteor/ee/server/apps/storage/logs-storage.js +++ /dev/null @@ -1,32 +0,0 @@ -import { AppConsole } from '@rocket.chat/apps-engine/server/logging'; -import { AppLogStorage } from '@rocket.chat/apps-engine/server/storage'; -import { InstanceStatus } from '@rocket.chat/instance-status'; - -export class AppRealLogsStorage extends AppLogStorage { - constructor(model) { - super('mongodb'); - this.db = model; - } - - async find(...args) { - return this.db.find(...args).toArray(); - } - - async storeEntries(appId, logger) { - const item = AppConsole.toStorageEntry(appId, logger); - - item.instanceId = InstanceStatus.id(); - - const id = (await this.db.insertOne(item)).insertedId; - - return this.db.findOneById(id); - } - - async getEntriesFor(appId) { - return this.db.find({ appId }).toArray(); - } - - async removeEntriesFor(appId) { - await this.db.remove({ appId }); - } -} diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index c2119b1d3b24..20af1002f738 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -18,7 +18,7 @@ "author": "Rocket.Chat", "license": "MIT", "dependencies": { - "@rocket.chat/apps-engine": "1.42.2", + "@rocket.chat/apps-engine": "alpha", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", diff --git a/apps/meteor/package.json b/apps/meteor/package.json index d79155167845..9d02e91c6cba 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -231,7 +231,7 @@ "@rocket.chat/agenda": "workspace:^", "@rocket.chat/api-client": "workspace:^", "@rocket.chat/apps": "workspace:^", - "@rocket.chat/apps-engine": "1.42.2", + "@rocket.chat/apps-engine": "alpha", "@rocket.chat/base64": "workspace:^", "@rocket.chat/cas-validate": "workspace:^", "@rocket.chat/core-services": "workspace:^", diff --git a/apps/meteor/server/services/apps-engine/service.ts b/apps/meteor/server/services/apps-engine/service.ts index 41a53cf5bbb6..19838fd8411d 100644 --- a/apps/meteor/server/services/apps-engine/service.ts +++ b/apps/meteor/server/services/apps-engine/service.ts @@ -75,7 +75,7 @@ export class AppsEngineService extends ServiceClassInternal implements IAppsEngi return; } - if (app.getStatus() === status) { + if ((await app.getStatus()) === status) { Apps.self?.getRocketChatLogger().info(`"apps.statusUpdate" event received for app "${appId}", but the status is the same`); return; } @@ -116,10 +116,7 @@ export class AppsEngineService extends ServiceClassInternal implements IAppsEngi } async getApps(query: IGetAppsFilter): Promise { - return Apps.self - ?.getManager() - ?.get(query) - .map((app) => app.getApp().getInfo()); + return (await Apps.self?.getManager()?.get(query))?.map((app) => app.getInfo()); } async getAppStorageItemById(appId: string): Promise { diff --git a/apps/meteor/tests/end-to-end/apps/02-send-messages-as-user.js b/apps/meteor/tests/end-to-end/apps/02-send-messages-as-user.js index a0be32734306..61d812571d7d 100644 --- a/apps/meteor/tests/end-to-end/apps/02-send-messages-as-user.js +++ b/apps/meteor/tests/end-to-end/apps/02-send-messages-as-user.js @@ -95,7 +95,7 @@ describe('Apps - Send Messages As User', function () { after(() => Promise.all([deleteRoom({ type: 'p', roomId: group._id }), deleteUser(user)])); - it('should send a message as app user', (done) => { + it('should return 500 when sending a message as user that has no permissions', (done) => { request .post(apps(`/public/${app.id}/send-message-as-user?userId=${user._id}`)) .set(userCredentials) diff --git a/docker-compose-ci.yml b/docker-compose-ci.yml index a533ae29d2df..67b89d61ef52 100644 --- a/docker-compose-ci.yml +++ b/docker-compose-ci.yml @@ -11,6 +11,7 @@ services: image: ghcr.io/${LOWERCASE_REPOSITORY}/rocket.chat:${RC_DOCKER_TAG} environment: - TEST_MODE=true + - DEBUG=${DEBUG} - EXIT_UNHANDLEDPROMISEREJECTION=true - 'MONGO_URL=${MONGO_URL}' - 'MONGO_OPLOG_URL=${MONGO_OPLOG_URL}' diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index c1dd482d2e75..9a2fd6065765 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -15,7 +15,7 @@ ], "author": "Rocket.Chat", "dependencies": { - "@rocket.chat/apps-engine": "1.42.2", + "@rocket.chat/apps-engine": "alpha", "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "~0.31.25", diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 4e609c5d954b..4de31f3214b4 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@babel/preset-env": "~7.22.20", "@babel/preset-typescript": "~7.22.15", - "@rocket.chat/apps-engine": "1.42.2", + "@rocket.chat/apps-engine": "alpha", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/rest-typings": "workspace:^", "@types/node": "^14.18.63", diff --git a/packages/apps/package.json b/packages/apps/package.json index ee99ba288fab..359bb605e82f 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -22,7 +22,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "1.42.2", + "@rocket.chat/apps-engine": "alpha", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/model-typings": "workspace:^" } diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 6033814bf2fa..9a4705673b18 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -34,7 +34,7 @@ "extends": "../../package.json" }, "dependencies": { - "@rocket.chat/apps-engine": "1.42.2", + "@rocket.chat/apps-engine": "alpha", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/icons": "^0.36.0", "@rocket.chat/message-parser": "workspace:^", diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 9256b3e8b6e7..b9b259a1b78e 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -22,7 +22,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "1.42.2", + "@rocket.chat/apps-engine": "alpha", "@rocket.chat/icons": "^0.36.0", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/ui-kit": "workspace:~" diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 25d44e876dff..119a23759280 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -63,7 +63,7 @@ "@babel/preset-env": "~7.22.20", "@babel/preset-react": "~7.22.15", "@babel/preset-typescript": "~7.22.15", - "@rocket.chat/apps-engine": "^1.42.2", + "@rocket.chat/apps-engine": "alpha", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/eslint-config": "workspace:^", "@rocket.chat/fuselage": "^0.54.2", diff --git a/packages/model-typings/src/models/IAppLogsModel.ts b/packages/model-typings/src/models/IAppLogsModel.ts index f73964c57687..6a6bc765cd8e 100644 --- a/packages/model-typings/src/models/IAppLogsModel.ts +++ b/packages/model-typings/src/models/IAppLogsModel.ts @@ -1,6 +1,9 @@ +import type { DeleteResult, Filter } from 'mongodb'; + import type { IBaseModel } from './IBaseModel'; // TODO: type for AppLogs export interface IAppLogsModel extends IBaseModel { resetTTLIndex(expireAfterSeconds: number): Promise; + remove(query: Filter): Promise; } diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 2d567eb10fab..91ec61eb40e7 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -24,7 +24,7 @@ "/dist" ], "dependencies": { - "@rocket.chat/apps-engine": "1.42.2", + "@rocket.chat/apps-engine": "alpha", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/ui-kit": "workspace:~", diff --git a/yarn.lock b/yarn.lock index 1f73a73df3e1..6321b0aff77f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3653,6 +3653,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/aix-ppc64@npm:0.20.2" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/android-arm64@npm:0.17.19" @@ -3660,6 +3667,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/android-arm64@npm:0.20.2" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/android-arm@npm:0.17.19" @@ -3667,6 +3681,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/android-arm@npm:0.20.2" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/android-x64@npm:0.17.19" @@ -3674,6 +3695,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/android-x64@npm:0.20.2" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/darwin-arm64@npm:0.17.19" @@ -3681,6 +3709,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/darwin-arm64@npm:0.20.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/darwin-x64@npm:0.17.19" @@ -3688,6 +3723,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/darwin-x64@npm:0.20.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/freebsd-arm64@npm:0.17.19" @@ -3695,6 +3737,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/freebsd-arm64@npm:0.20.2" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/freebsd-x64@npm:0.17.19" @@ -3702,6 +3751,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/freebsd-x64@npm:0.20.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-arm64@npm:0.17.19" @@ -3709,6 +3765,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-arm64@npm:0.20.2" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-arm@npm:0.17.19" @@ -3716,6 +3779,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-arm@npm:0.20.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-ia32@npm:0.17.19" @@ -3723,6 +3793,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-ia32@npm:0.20.2" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-loong64@npm:0.17.19" @@ -3730,6 +3807,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-loong64@npm:0.20.2" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-mips64el@npm:0.17.19" @@ -3737,6 +3821,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-mips64el@npm:0.20.2" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-ppc64@npm:0.17.19" @@ -3744,6 +3835,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-ppc64@npm:0.20.2" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-riscv64@npm:0.17.19" @@ -3751,6 +3849,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-riscv64@npm:0.20.2" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-s390x@npm:0.17.19" @@ -3758,6 +3863,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-s390x@npm:0.20.2" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/linux-x64@npm:0.17.19" @@ -3765,6 +3877,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/linux-x64@npm:0.20.2" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/netbsd-x64@npm:0.17.19" @@ -3772,6 +3891,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/netbsd-x64@npm:0.20.2" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/openbsd-x64@npm:0.17.19" @@ -3779,6 +3905,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/openbsd-x64@npm:0.20.2" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/sunos-x64@npm:0.17.19" @@ -3786,6 +3919,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/sunos-x64@npm:0.20.2" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/win32-arm64@npm:0.17.19" @@ -3793,6 +3933,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/win32-arm64@npm:0.20.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/win32-ia32@npm:0.17.19" @@ -3800,6 +3947,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/win32-ia32@npm:0.20.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.17.19": version: 0.17.19 resolution: "@esbuild/win32-x64@npm:0.17.19" @@ -3807,6 +3961,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.20.2": + version: 0.20.2 + resolution: "@esbuild/win32-x64@npm:0.20.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" @@ -4725,6 +4886,13 @@ __metadata: languageName: node linkType: hard +"@msgpack/msgpack@npm:3.0.0-beta2": + version: 3.0.0-beta2 + resolution: "@msgpack/msgpack@npm:3.0.0-beta2" + checksum: d86e5d48146051952d6bea35a6cf733a401cf65ad5614d79689aa48c7076021737ca2c782978dd1b6c0c9c45888b246e379e45ae906179e3a0e8ef4ee6f221c1 + languageName: node + linkType: hard + "@napi-rs/cli@npm:^2.2.0": version: 2.6.2 resolution: "@napi-rs/cli@npm:2.6.2" @@ -8340,21 +8508,25 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/apps-engine@npm:1.42.2, @rocket.chat/apps-engine@npm:^1.42.2": - version: 1.42.2 - resolution: "@rocket.chat/apps-engine@npm:1.42.2" +"@rocket.chat/apps-engine@npm:alpha": + version: 1.43.0-alpha.763 + resolution: "@rocket.chat/apps-engine@npm:1.43.0-alpha.763" dependencies: + "@msgpack/msgpack": 3.0.0-beta2 adm-zip: ^0.5.9 cryptiles: ^4.1.3 + debug: ^4.3.4 + deno-bin: 1.37.1 + esbuild: ^0.20.2 jose: ^4.11.1 + jsonrpc-lite: ^2.2.0 lodash.clonedeep: ^4.5.0 semver: ^5.7.1 stack-trace: 0.0.10 uuid: ~8.3.2 - vm2: ^3.9.19 peerDependencies: "@rocket.chat/ui-kit": "*" - checksum: d7aa23249823e37072b6b7af16a40d9a4e7cb6b8047f2a87e52163dfe516d6c8a09b21cafd4f28dfbe4dd3da9cd0190d71f7623fec8c573a3f215ca4f9529b56 + checksum: f4498febb2f11766c6cab98c3738ca8ba50e9cfa68d129577a781a6fbbe91cfc48c82d6e418f05f0db6b3561becd6aab09b5b19b26652deb5e5621d7fd7b4c4a languageName: node linkType: hard @@ -8362,7 +8534,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/apps@workspace:packages/apps" dependencies: - "@rocket.chat/apps-engine": 1.42.2 + "@rocket.chat/apps-engine": alpha "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/model-typings": "workspace:^" "@types/jest": ~29.5.7 @@ -8441,7 +8613,7 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": 1.42.2 + "@rocket.chat/apps-engine": alpha "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/icons": ^0.36.0 @@ -8467,7 +8639,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/core-typings@workspace:packages/core-typings" dependencies: - "@rocket.chat/apps-engine": 1.42.2 + "@rocket.chat/apps-engine": alpha "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/icons": ^0.36.0 "@rocket.chat/message-parser": "workspace:^" @@ -8544,7 +8716,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/ddp-streamer@workspace:ee/apps/ddp-streamer" dependencies: - "@rocket.chat/apps-engine": 1.42.2 + "@rocket.chat/apps-engine": alpha "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/emitter": ~0.31.25 @@ -8740,7 +8912,7 @@ __metadata: "@babel/preset-env": ~7.22.20 "@babel/preset-react": ~7.22.15 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": ^1.42.2 + "@rocket.chat/apps-engine": alpha "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/fuselage": ^0.54.2 @@ -9184,7 +9356,7 @@ __metadata: "@rocket.chat/agenda": "workspace:^" "@rocket.chat/api-client": "workspace:^" "@rocket.chat/apps": "workspace:^" - "@rocket.chat/apps-engine": 1.42.2 + "@rocket.chat/apps-engine": alpha "@rocket.chat/base64": "workspace:^" "@rocket.chat/cas-validate": "workspace:^" "@rocket.chat/core-services": "workspace:^" @@ -9822,7 +9994,7 @@ __metadata: "@babel/core": ~7.22.20 "@babel/preset-env": ~7.22.20 "@babel/preset-typescript": ~7.22.15 - "@rocket.chat/apps-engine": 1.42.2 + "@rocket.chat/apps-engine": alpha "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" @@ -9937,7 +10109,7 @@ __metadata: version: 0.0.0-use.local resolution: "@rocket.chat/rest-typings@workspace:packages/rest-typings" dependencies: - "@rocket.chat/apps-engine": 1.42.2 + "@rocket.chat/apps-engine": alpha "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/eslint-config": "workspace:^" "@rocket.chat/message-parser": "workspace:^" @@ -20891,6 +21063,19 @@ __metadata: languageName: node linkType: hard +"deno-bin@npm:1.37.1": + version: 1.37.1 + resolution: "deno-bin@npm:1.37.1" + dependencies: + adm-zip: ^0.5.4 + follow-redirects: ^1.10.0 + bin: + deno: bin/deno.js + deno-bin: bin/deno.js + checksum: 1c985611aa67b4b72f68b5608644af73dbff75619ac4fba67fecf036763acf76c66a9bb537cf09865c855313ceec6af1190474fa0163a616620b8af705c82736 + languageName: node + linkType: hard + "depd@npm:2.0.0, depd@npm:~2.0.0": version: 2.0.0 resolution: "depd@npm:2.0.0" @@ -22166,6 +22351,86 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.20.2": + version: 0.20.2 + resolution: "esbuild@npm:0.20.2" + dependencies: + "@esbuild/aix-ppc64": 0.20.2 + "@esbuild/android-arm": 0.20.2 + "@esbuild/android-arm64": 0.20.2 + "@esbuild/android-x64": 0.20.2 + "@esbuild/darwin-arm64": 0.20.2 + "@esbuild/darwin-x64": 0.20.2 + "@esbuild/freebsd-arm64": 0.20.2 + "@esbuild/freebsd-x64": 0.20.2 + "@esbuild/linux-arm": 0.20.2 + "@esbuild/linux-arm64": 0.20.2 + "@esbuild/linux-ia32": 0.20.2 + "@esbuild/linux-loong64": 0.20.2 + "@esbuild/linux-mips64el": 0.20.2 + "@esbuild/linux-ppc64": 0.20.2 + "@esbuild/linux-riscv64": 0.20.2 + "@esbuild/linux-s390x": 0.20.2 + "@esbuild/linux-x64": 0.20.2 + "@esbuild/netbsd-x64": 0.20.2 + "@esbuild/openbsd-x64": 0.20.2 + "@esbuild/sunos-x64": 0.20.2 + "@esbuild/win32-arm64": 0.20.2 + "@esbuild/win32-ia32": 0.20.2 + "@esbuild/win32-x64": 0.20.2 + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: bc88050fc1ca5c1bd03648f9979e514bdefb956a63aa3974373bb7b9cbac0b3aac9b9da1b5bdca0b3490e39d6b451c72815dbd6b7d7f978c91fbe9c9e9aa4e4c + languageName: node + linkType: hard + "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" @@ -23826,6 +24091,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.10.0": + version: 1.15.4 + resolution: "follow-redirects@npm:1.15.4" + peerDependenciesMeta: + debug: + optional: true + checksum: e178d1deff8b23d5d24ec3f7a94cde6e47d74d0dc649c35fc9857041267c12ec5d44650a0c5597ef83056ada9ea6ca0c30e7c4f97dbf07d035086be9e6a5b7b6 + languageName: node + linkType: hard + "fontkit@npm:^2.0.2": version: 2.0.2 resolution: "fontkit@npm:2.0.2" @@ -28792,6 +29067,13 @@ __metadata: languageName: node linkType: hard +"jsonrpc-lite@npm:^2.2.0": + version: 2.2.0 + resolution: "jsonrpc-lite@npm:2.2.0" + checksum: 3062101d3c93401d176c1c24b90e0feebdd063546f8ed89c299531dd792c4d37c6766666d160efb83b94f17f7e2deed4346cdd9124b99581ed4620779e8733bb + languageName: node + linkType: hard + "jsonwebtoken@npm:^8.1.0, jsonwebtoken@npm:^8.5.1": version: 8.5.1 resolution: "jsonwebtoken@npm:8.5.1" @@ -36853,7 +37135,7 @@ __metadata: version: 0.0.0-use.local resolution: "rocketchat-services@workspace:apps/meteor/ee/server/services" dependencies: - "@rocket.chat/apps-engine": 1.42.2 + "@rocket.chat/apps-engine": alpha "@rocket.chat/core-services": "workspace:^" "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/emitter": ~0.31.25 From 94b12edfc6a561a4db0c318c65c6f40786b1fbf8 Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Tue, 18 Jun 2024 08:44:05 -0300 Subject: [PATCH 26/94] fix: Not possible to edit room without proper permission with retention policy enabled (#32547) --- .changeset/nervous-wolves-collect.md | 5 +++ .../EditRoomInfo/useEditRoomInitialValues.ts | 19 +++++++----- .../meteor/tests/e2e/retention-policy.spec.ts | 31 ++++++++++++++----- 3 files changed, 40 insertions(+), 15 deletions(-) create mode 100644 .changeset/nervous-wolves-collect.md diff --git a/.changeset/nervous-wolves-collect.md b/.changeset/nervous-wolves-collect.md new file mode 100644 index 000000000000..e32377f54179 --- /dev/null +++ b/.changeset/nervous-wolves-collect.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes the issue not allowing users without edit-room-retention-policy permission try to edit the room with the retention policy enabled diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts index 128f6c3c66f8..1cb76cadd335 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts +++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts @@ -1,4 +1,5 @@ import type { IRoomWithRetentionPolicy } from '@rocket.chat/core-typings'; +import { usePermission } from '@rocket.chat/ui-contexts'; import { useMemo } from 'react'; import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator'; @@ -6,6 +7,8 @@ import { useRetentionPolicy } from '../../../hooks/useRetentionPolicy'; export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy) => { const retentionPolicy = useRetentionPolicy(room); + const canEditRoomRetentionPolicy = usePermission('edit-room-retention-policy', room._id); + const { t, ro, archived, topic, description, announcement, joinCodeRequired, sysMes, encrypted, retention, reactWhenReadOnly } = room; return useMemo( @@ -24,13 +27,14 @@ export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy) => { systemMessages: Array.isArray(sysMes) ? sysMes : [], hideSysMes: Array.isArray(sysMes) ? !!sysMes?.length : !!sysMes, encrypted, - ...(retentionPolicy?.enabled && { - retentionEnabled: retention?.enabled ?? retentionPolicy.isActive, - retentionOverrideGlobal: !!retention?.overrideGlobal, - retentionMaxAge: retention?.maxAge ?? retentionPolicy.maxAge, - retentionExcludePinned: retention?.excludePinned ?? retentionPolicy.excludePinned, - retentionFilesOnly: retention?.filesOnly ?? retentionPolicy.filesOnly, - }), + ...(canEditRoomRetentionPolicy && + retentionPolicy?.enabled && { + retentionEnabled: retention?.enabled ?? retentionPolicy.isActive, + retentionOverrideGlobal: !!retention?.overrideGlobal, + retentionMaxAge: retention?.maxAge ?? retentionPolicy.maxAge, + retentionExcludePinned: retention?.excludePinned ?? retentionPolicy.excludePinned, + retentionFilesOnly: retention?.filesOnly ?? retentionPolicy.filesOnly, + }), }), [ announcement, @@ -46,6 +50,7 @@ export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy) => { topic, encrypted, reactWhenReadOnly, + canEditRoomRetentionPolicy, ], ); }; diff --git a/apps/meteor/tests/e2e/retention-policy.spec.ts b/apps/meteor/tests/e2e/retention-policy.spec.ts index 9c18edcf4af3..d17276a160af 100644 --- a/apps/meteor/tests/e2e/retention-policy.spec.ts +++ b/apps/meteor/tests/e2e/retention-policy.spec.ts @@ -85,15 +85,30 @@ test.describe.serial('retention-policy', () => { await expect(poHomeChannel.tabs.room.pruneAccordion).toBeVisible(); }); - test('should not show prune section in edit channel for users without permission', async ({ browser }) => { - const { page } = await createAuxContext(browser, Users.user1); - const auxContext = { page, poHomeChannel: new HomeChannel(page) }; - await auxContext.poHomeChannel.sidenav.openChat(targetChannel); - await auxContext.poHomeChannel.tabs.btnRoomInfo.click(); - await auxContext.poHomeChannel.tabs.room.btnEdit.click(); + test.describe('edit-room-retention-policy permission', async () => { + test('should not show prune section in edit channel for users without permission', async ({ browser }) => { + const { page } = await createAuxContext(browser, Users.user1); + const auxContext = { page, poHomeChannel: new HomeChannel(page) }; + await auxContext.poHomeChannel.sidenav.openChat(targetChannel); + await auxContext.poHomeChannel.tabs.btnRoomInfo.click(); + await auxContext.poHomeChannel.tabs.room.btnEdit.click(); + + await expect(poHomeChannel.tabs.room.pruneAccordion).not.toBeVisible(); + await auxContext.page.close(); + }); - await expect(poHomeChannel.tabs.room.pruneAccordion).not.toBeVisible(); - await auxContext.page.close(); + test('users without permission should be able to edit the channel', async ({ browser }) => { + const { page } = await createAuxContext(browser, Users.user1); + const auxContext = { page, poHomeChannel: new HomeChannel(page) }; + await auxContext.poHomeChannel.sidenav.openChat(targetChannel); + await auxContext.poHomeChannel.tabs.btnRoomInfo.click(); + await auxContext.poHomeChannel.tabs.room.btnEdit.click(); + await auxContext.poHomeChannel.tabs.room.checkboxReadOnly.check(); + await auxContext.poHomeChannel.tabs.room.btnSave.click(); + + await expect(auxContext.poHomeChannel.getSystemMessageByText('set room to read only')).toBeVisible(); + await auxContext.page.close(); + }); }); test.describe('retention policy applies enabled by default', () => { From faf386bf65ea76bdec78dd3fe6c710f4ad89b571 Mon Sep 17 00:00:00 2001 From: Allan RIbeiro <35040806+AllanPazRibeiro@users.noreply.github.com> Date: Tue, 18 Jun 2024 09:30:37 -0300 Subject: [PATCH 27/94] fix: prevent broadcasting of system messages when hide setting is enabled (#32522) --- .changeset/grumpy-games-greet.md | 4 + .../server/functions/loadMessageHistory.ts | 7 +- .../lib/server/lib/getHiddenSystemMessages.ts | 24 +- .../lib/server/methods/getChannelHistory.ts | 7 +- .../lib/systemMessage/hideSystemMessage.ts | 13 ++ .../server/modules/watchers/lib/messages.ts | 15 +- .../server/lib/getHiddenSystemMessage.spec.ts | 90 ++++++++ .../systemMessage/hideSystemMessage.spec.ts | 48 ++++ .../modules/watchers/lib/messages.spec.ts | 215 ++++++++++++++++++ 9 files changed, 397 insertions(+), 26 deletions(-) create mode 100644 .changeset/grumpy-games-greet.md create mode 100644 apps/meteor/server/lib/systemMessage/hideSystemMessage.ts create mode 100644 apps/meteor/tests/unit/app/lib/server/lib/getHiddenSystemMessage.spec.ts create mode 100644 apps/meteor/tests/unit/server/lib/systemMessage/hideSystemMessage.spec.ts create mode 100644 apps/meteor/tests/unit/server/modules/watchers/lib/messages.spec.ts diff --git a/.changeset/grumpy-games-greet.md b/.changeset/grumpy-games-greet.md new file mode 100644 index 000000000000..1e7f03658ad3 --- /dev/null +++ b/.changeset/grumpy-games-greet.md @@ -0,0 +1,4 @@ +--- +'@rocket.chat/meteor': patch +--- +Changed streaming logic to prevent hidden system messages from being broadcasted through `stream-room-messages`. diff --git a/apps/meteor/app/lib/server/functions/loadMessageHistory.ts b/apps/meteor/app/lib/server/functions/loadMessageHistory.ts index 2f6b7a1f694d..fee7061cae96 100644 --- a/apps/meteor/app/lib/server/functions/loadMessageHistory.ts +++ b/apps/meteor/app/lib/server/functions/loadMessageHistory.ts @@ -1,7 +1,8 @@ -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, MessageTypesValues } from '@rocket.chat/core-typings'; import { Messages, Rooms } from '@rocket.chat/models'; import type { FindOptions } from 'mongodb'; +import { settings } from '../../../settings/server/cached'; import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; import { getHiddenSystemMessages } from '../lib/getHiddenSystemMessages'; @@ -29,7 +30,9 @@ export async function loadMessageHistory({ throw new Error('error-invalid-room'); } - const hiddenMessageTypes = getHiddenSystemMessages(room); + const hiddenSystemMessages = settings.get('Hide_System_Messages'); + + const hiddenMessageTypes = getHiddenSystemMessages(room, hiddenSystemMessages); const options: FindOptions = { sort: { diff --git a/apps/meteor/app/lib/server/lib/getHiddenSystemMessages.ts b/apps/meteor/app/lib/server/lib/getHiddenSystemMessages.ts index 74b31b63da6a..08f52620e080 100644 --- a/apps/meteor/app/lib/server/lib/getHiddenSystemMessages.ts +++ b/apps/meteor/app/lib/server/lib/getHiddenSystemMessages.ts @@ -1,26 +1,10 @@ import type { MessageTypesValues, IRoom } from '@rocket.chat/core-typings'; -import { settings } from '../../../settings/server'; - -const hideMessagesOfTypeServer = new Set(); - -settings.watch('Hide_System_Messages', (values) => { - if (!values || !Array.isArray(values)) { - return; - } - - const hiddenTypes = values.reduce((array, value): MessageTypesValues[] => { +export const getHiddenSystemMessages = (room: IRoom, hiddenSystemMessages: MessageTypesValues[]): MessageTypesValues[] => { + const hiddenTypes = hiddenSystemMessages.reduce((array, value): MessageTypesValues[] => { const newValue: MessageTypesValues[] = value === 'mute_unmute' ? ['user-muted', 'user-unmuted'] : [value]; - return [...array, ...newValue]; }, [] as MessageTypesValues[]); - hideMessagesOfTypeServer.clear(); - - hiddenTypes.forEach((item) => hideMessagesOfTypeServer.add(item)); -}); - -// TODO probably remove on chained event system -export function getHiddenSystemMessages(room: IRoom): MessageTypesValues[] { - return Array.isArray(room?.sysMes) ? room.sysMes : [...hideMessagesOfTypeServer]; -} + return Array.isArray(room?.sysMes) ? room.sysMes : hiddenTypes; +}; diff --git a/apps/meteor/app/lib/server/methods/getChannelHistory.ts b/apps/meteor/app/lib/server/methods/getChannelHistory.ts index 3c68fb7a2bf2..00ff01639593 100644 --- a/apps/meteor/app/lib/server/methods/getChannelHistory.ts +++ b/apps/meteor/app/lib/server/methods/getChannelHistory.ts @@ -1,4 +1,4 @@ -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, MessageTypesValues } from '@rocket.chat/core-typings'; import { Messages, Subscriptions, Rooms } from '@rocket.chat/models'; import type { ServerMethods } from '@rocket.chat/ui-contexts'; import { check } from 'meteor/check'; @@ -7,6 +7,7 @@ import _ from 'underscore'; import { canAccessRoomAsync } from '../../../authorization/server'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { settings } from '../../../settings/server/cached'; import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; import { getHiddenSystemMessages } from '../lib/getHiddenSystemMessages'; @@ -67,7 +68,9 @@ Meteor.methods({ throw new Meteor.Error('error-invalid-date', 'Invalid date', { method: 'getChannelHistory' }); } - const hiddenMessageTypes = getHiddenSystemMessages(room); + const hiddenSystemMessages = settings.get('Hide_System_Messages'); + + const hiddenMessageTypes = getHiddenSystemMessages(room, hiddenSystemMessages); const options: Record = { sort: { diff --git a/apps/meteor/server/lib/systemMessage/hideSystemMessage.ts b/apps/meteor/server/lib/systemMessage/hideSystemMessage.ts new file mode 100644 index 000000000000..cc6b7c13b85e --- /dev/null +++ b/apps/meteor/server/lib/systemMessage/hideSystemMessage.ts @@ -0,0 +1,13 @@ +import type { MessageTypesValues } from '@rocket.chat/core-typings'; + +export const isMutedUnmuted = (messageType: string): boolean => { + return messageType === 'user-muted' || messageType === 'user-unmuted'; +}; + +export const shouldHideSystemMessage = (messageType: MessageTypesValues, hideSystemMessage?: MessageTypesValues[]): boolean => { + if (!hideSystemMessage?.length) { + return false; + } + + return hideSystemMessage.includes(messageType) || (isMutedUnmuted(messageType) && hideSystemMessage.includes('mute_unmute')); +}; diff --git a/apps/meteor/server/modules/watchers/lib/messages.ts b/apps/meteor/server/modules/watchers/lib/messages.ts index 576f27f83b96..2f71e0ed1b66 100644 --- a/apps/meteor/server/modules/watchers/lib/messages.ts +++ b/apps/meteor/server/modules/watchers/lib/messages.ts @@ -1,9 +1,9 @@ import { api, dbWatchersDisabled } from '@rocket.chat/core-services'; -import type { IMessage, SettingValue, IUser } from '@rocket.chat/core-typings'; +import type { IMessage, IUser, MessageTypesValues } from '@rocket.chat/core-typings'; import { Messages, Settings, Users } from '@rocket.chat/models'; import mem from 'mem'; -const getSettingCached = mem(async (setting: string): Promise => Settings.getValueById(setting), { maxAge: 10000 }); +import { shouldHideSystemMessage } from '../../../lib/systemMessage/hideSystemMessage'; const getUserNameCached = mem( async (userId: string): Promise => { @@ -13,12 +13,23 @@ const getUserNameCached = mem( { maxAge: 10000 }, ); +const getSettingCached = mem(Settings.getValueById, { maxAge: 10000 }); + export async function getMessageToBroadcast({ id, data }: { id: IMessage['_id']; data?: IMessage }): Promise { const message = data ?? (await Messages.findOneById(id)); if (!message) { return; } + if (message.t) { + const hiddenSystemMessages = (await getSettingCached('Hide_System_Messages')) as MessageTypesValues[]; + const shouldHide = shouldHideSystemMessage(message.t, hiddenSystemMessages); + + if (shouldHide) { + return; + } + } + if (message._hidden || message.imported != null) { return; } diff --git a/apps/meteor/tests/unit/app/lib/server/lib/getHiddenSystemMessage.spec.ts b/apps/meteor/tests/unit/app/lib/server/lib/getHiddenSystemMessage.spec.ts new file mode 100644 index 000000000000..4fb3df00b8c5 --- /dev/null +++ b/apps/meteor/tests/unit/app/lib/server/lib/getHiddenSystemMessage.spec.ts @@ -0,0 +1,90 @@ +import type { MessageTypesValues, IRoom, IUser } from '@rocket.chat/core-typings'; +import { expect } from 'chai'; + +import { getHiddenSystemMessages } from '../../../../../../app/lib/server/lib/getHiddenSystemMessages'; + +describe('getHiddenSystemMessages', () => { + it('should return room.sysMes if it is an array', async () => { + const room: IRoom = { + _id: 'roomId', + sysMes: ['mute_unmute', 'room_changed_description'] as MessageTypesValues[], + t: 'c', + msgs: 0, + u: {} as IUser, + usersCount: 0, + _updatedAt: new Date(), + }; + + const result = getHiddenSystemMessages(room, []); + + expect(result).to.deep.equal(room.sysMes); + }); + + it('should return cached hidden system messages if room.sysMes is not an array', async () => { + const cachedHiddenSystemMessage: MessageTypesValues[] = ['mute_unmute', 'room_changed_description']; + + const room: IRoom = { + _id: 'roomId', + t: 'c', + msgs: 0, + u: {} as IUser, + usersCount: 0, + _updatedAt: new Date(), + }; + + const result = getHiddenSystemMessages(room, cachedHiddenSystemMessage); + + expect(result).to.deep.equal(['user-muted', 'user-unmuted', 'room_changed_description']); + }); + + it('should return an empty array if both room.sysMes and cached hidden system messages are undefined', async () => { + const room: IRoom = { + _id: 'roomId', + t: 'c', + msgs: 0, + u: {} as IUser, + usersCount: 0, + _updatedAt: new Date(), + }; + + const result = getHiddenSystemMessages(room, []); + + expect(result).to.deep.equal([]); + }); + + it('should return cached hidden system messages if room.sysMes is null', async () => { + const cachedHiddenSystemMessage: MessageTypesValues[] = ['subscription-role-added', 'room_changed_announcement']; + + const room: IRoom = { + _id: 'roomId', + sysMes: undefined, + t: 'c', + msgs: 0, + u: {} as IUser, + usersCount: 0, + _updatedAt: new Date(), + }; + + const result = getHiddenSystemMessages(room, cachedHiddenSystemMessage); + + expect(result).to.deep.equal(cachedHiddenSystemMessage); + }); + + it('should return cached hidden system messages if room.sysMes array and hidden system message is available', async () => { + const cachedHiddenSystemMessage: MessageTypesValues[] = ['room_changed_announcement', 'room-archived']; + + const room: IRoom = { + _id: 'roomId', + sysMes: ['mute_unmute', 'room_changed_description'] as MessageTypesValues[], + t: 'c', + msgs: 0, + u: {} as IUser, + usersCount: 0, + _updatedAt: new Date(), + }; + + const result = getHiddenSystemMessages(room, cachedHiddenSystemMessage); + + expect(result).to.deep.equal(['mute_unmute', 'room_changed_description']); + }); +}); diff --git a/apps/meteor/tests/unit/server/lib/systemMessage/hideSystemMessage.spec.ts b/apps/meteor/tests/unit/server/lib/systemMessage/hideSystemMessage.spec.ts new file mode 100644 index 000000000000..61d2696068ae --- /dev/null +++ b/apps/meteor/tests/unit/server/lib/systemMessage/hideSystemMessage.spec.ts @@ -0,0 +1,48 @@ +import type { MessageTypesValues } from '@rocket.chat/core-typings'; +import { expect } from 'chai'; + +import { isMutedUnmuted, shouldHideSystemMessage } from '../../../../../server/lib/systemMessage/hideSystemMessage'; + +describe('hideSystemMessage', () => { + describe('isMutedUnmuted', () => { + it('should return true for user-muted', () => { + expect(isMutedUnmuted('user-muted')).to.be.true; + }); + + it('should return true for user-unmuted', () => { + expect(isMutedUnmuted('user-unmuted')).to.be.true; + }); + + it('should return false for other message types', () => { + expect(isMutedUnmuted('some-other-type')).to.be.false; + }); + }); + + describe('shouldHideSystemMessage', () => { + it('should return true if message type is in hidden system messages', async () => { + const hiddenMessages: MessageTypesValues[] = ['user-muted', 'mute_unmute']; + + const result = shouldHideSystemMessage('user-muted', hiddenMessages); + expect(result).to.be.true; + }); + + it('should return true if message type is user-muted and mute_unmute is in hidden system messages', async () => { + const hiddenMessages: MessageTypesValues[] = ['mute_unmute']; + + const result = shouldHideSystemMessage('user-muted', hiddenMessages); + expect(result).to.be.true; + }); + + it('should return false if message type is not in hidden system messages', async () => { + const hiddenMessages: MessageTypesValues[] = ['room-archived']; + + const result = shouldHideSystemMessage('user-muted', hiddenMessages); + expect(result).to.be.false; + }); + + it('should return false if hidden system messages are undefined', async () => { + const result = shouldHideSystemMessage('user-muted', undefined); + expect(result).to.be.false; + }); + }); +}); diff --git a/apps/meteor/tests/unit/server/modules/watchers/lib/messages.spec.ts b/apps/meteor/tests/unit/server/modules/watchers/lib/messages.spec.ts new file mode 100644 index 000000000000..5ef8bbdd1634 --- /dev/null +++ b/apps/meteor/tests/unit/server/modules/watchers/lib/messages.spec.ts @@ -0,0 +1,215 @@ +import type { IMessage } from '@rocket.chat/core-typings'; +import { expect } from 'chai'; +import proxyquire from 'proxyquire'; +import sinon from 'sinon'; + +describe('Message Broadcast Tests', () => { + let getSettingValueByIdStub: sinon.SinonStub; + let usersFindOneStub: sinon.SinonStub; + let messagesFindOneStub: sinon.SinonStub; + let broadcastStub: sinon.SinonStub; + let getMessageToBroadcast: any; + let broadcastMessageFromData: any; + let memStub: sinon.SinonStub; + + const sampleMessage: IMessage = { + _id: '123', + rid: 'room1', + msg: 'Hello', + ts: new Date(), + u: { _id: 'user1', username: 'user1', name: 'Real User' }, + mentions: [], + t: 'user-muted', + _updatedAt: new Date(), + }; + + const modelsStubs = () => ({ + Messages: { + findOneById: messagesFindOneStub, + }, + Users: { + findOne: usersFindOneStub, + }, + Settings: { + getValueById: getSettingValueByIdStub, + }, + }); + + const coreStubs = (dbWatchersDisabled: boolean) => ({ + api: { + broadcast: broadcastStub, + }, + dbWatchersDisabled, + }); + + beforeEach(() => { + getSettingValueByIdStub = sinon.stub(); + usersFindOneStub = sinon.stub(); + messagesFindOneStub = sinon.stub(); + broadcastStub = sinon.stub(); + memStub = sinon.stub().callsFake((fn: any) => fn); + + const proxyMock = proxyquire.noCallThru().load('../../../../../../server/modules/watchers/lib/messages', { + '@rocket.chat/models': modelsStubs(), + '@rocket.chat/core-services': coreStubs(false), + 'mem': memStub, + }); + + getMessageToBroadcast = proxyMock.getMessageToBroadcast; + broadcastMessageFromData = proxyMock.broadcastMessageFromData; + }); + + afterEach(() => { + sinon.reset(); + }); + + describe('getMessageToBroadcast', () => { + let originalEnv: NodeJS.ProcessEnv; + + beforeEach(() => { + originalEnv = { ...process.env }; + sinon.resetHistory(); + }); + + afterEach(() => { + process.env = originalEnv; + }); + + const testCases = [ + { + description: 'should return undefined if message is hidden or imported', + message: { ...sampleMessage, _hidden: true }, + hideSystemMessages: [], + useRealName: false, + expectedResult: undefined, + }, + { + description: 'should hide message if type is in hideSystemMessage settings', + message: sampleMessage, + hideSystemMessages: ['user-muted', 'mute_unmute'], + useRealName: false, + expectedResult: undefined, + }, + { + description: 'should return the message with real name if useRealName is true', + message: sampleMessage, + hideSystemMessages: [], + useRealName: true, + expectedResult: { ...sampleMessage, u: { ...sampleMessage.u, name: 'Real User' } }, + }, + { + description: 'should return the message if Hide_System_Messages is undefined', + message: sampleMessage, + hideSystemMessages: undefined, + useRealName: false, + expectedResult: sampleMessage, + }, + { + description: 'should return undefined if the message type is muted and a mute_unmute is received', + message: { ...sampleMessage, t: 'mute_unmute' }, + hideSystemMessages: ['user-muted', 'mute_unmute'], + useRealName: false, + expectedResult: undefined, + }, + { + description: 'should return the message if no system messages are muted', + message: sampleMessage, + hideSystemMessages: [], + useRealName: false, + expectedResult: sampleMessage, + }, + { + description: 'should hide message if type is room-archived', + message: { ...sampleMessage, t: 'room-archived' }, + hideSystemMessages: ['room-archived'], + useRealName: false, + expectedResult: undefined, + }, + { + description: 'should hide message if type is user-unmuted', + message: { ...sampleMessage, t: 'user-unmuted' }, + hideSystemMessages: ['user-unmuted'], + useRealName: false, + expectedResult: undefined, + }, + { + description: 'should hide message if type is subscription-role-added', + message: { ...sampleMessage, t: 'subscription-role-added' }, + hideSystemMessages: ['subscription-role-added'], + useRealName: false, + expectedResult: undefined, + }, + { + description: 'should hide message if type is message_pinned', + message: { ...sampleMessage, t: 'message_pinned' }, + hideSystemMessages: ['message_pinned'], + useRealName: false, + expectedResult: undefined, + }, + { + description: 'should hide message if type is new-owner', + message: { ...sampleMessage, t: 'new-owner' }, + hideSystemMessages: ['new-owner'], + useRealName: false, + expectedResult: undefined, + }, + ]; + + testCases.forEach(({ description, message, hideSystemMessages, useRealName, expectedResult }) => { + it(description, async () => { + messagesFindOneStub.resolves(message); + getSettingValueByIdStub.withArgs('Hide_System_Messages').resolves(hideSystemMessages); + getSettingValueByIdStub.withArgs('UI_Use_Real_Name').resolves(useRealName); + + if (useRealName) { + usersFindOneStub.resolves({ name: 'Real User' }); + } + + const result = await getMessageToBroadcast({ id: '123' }); + + expect(result).to.deep.equal(expectedResult); + }); + }); + }); + + describe('broadcastMessageFromData', () => { + const setupProxyMock = (dbWatchersDisabled: boolean) => { + const proxyMock = proxyquire.noCallThru().load('../../../../../../server/modules/watchers/lib/messages', { + '@rocket.chat/models': modelsStubs(), + '@rocket.chat/core-services': coreStubs(dbWatchersDisabled), + 'mem': memStub, + }); + broadcastMessageFromData = proxyMock.broadcastMessageFromData; + }; + + const testCases = [ + { + description: 'should broadcast the message if dbWatchersDisabled is true', + dbWatchersDisabled: true, + expectBroadcast: true, + }, + { + description: 'should not broadcast the message if dbWatchersDisabled is false', + dbWatchersDisabled: false, + expectBroadcast: false, + }, + ]; + + testCases.forEach(({ description, dbWatchersDisabled, expectBroadcast }) => { + it(description, async () => { + setupProxyMock(dbWatchersDisabled); + messagesFindOneStub.resolves(sampleMessage); + getSettingValueByIdStub.resolves([]); + + await broadcastMessageFromData({ id: '123', data: sampleMessage }); + + if (expectBroadcast) { + expect(broadcastStub.calledOnce).to.be.true; + expect(broadcastStub.calledOnceWith('watch.messages', { message: sampleMessage })).to.be.true; + } else { + expect(broadcastStub.called).to.be.false; + } + }); + }); + }); +}); From ffbbd8c40bb7a7cd7fe16cb41464a543adabc344 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 18 Jun 2024 10:11:23 -0300 Subject: [PATCH 28/94] regression: don't notify role changes during startup (#32619) --- .../server/lib/roles/createOrUpdateProtectedRole.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts b/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts index cdc43cdad93a..ea59a2961ea4 100644 --- a/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts +++ b/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts @@ -1,8 +1,6 @@ import type { IRole, AtLeast } from '@rocket.chat/core-typings'; import { Roles } from '@rocket.chat/models'; -import { notifyOnRoleChanged, notifyOnRoleChangedById } from '../../../app/lib/server/lib/notifyListener'; - export const createOrUpdateProtectedRoleAsync = async ( roleId: string, roleData: AtLeast, 'name'>, @@ -12,7 +10,7 @@ export const createOrUpdateProtectedRoleAsync = async ( }); if (role) { - const updatedRole = await Roles.updateById( + await Roles.updateById( roleId, roleData.name || role.name, roleData.scope || role.scope, @@ -20,8 +18,6 @@ export const createOrUpdateProtectedRoleAsync = async ( roleData.mandatory2fa || role.mandatory2fa, ); - void notifyOnRoleChanged(updatedRole); - return; } @@ -33,6 +29,4 @@ export const createOrUpdateProtectedRoleAsync = async ( ...roleData, protected: true, }); - - void notifyOnRoleChangedById(roleId); }; From b23f9ed91ab21ad83ff01bc512fafc0c9987a3e5 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 18 Jun 2024 11:32:29 -0300 Subject: [PATCH 29/94] fix: Supported Versions misbehaving (#32610) --- .changeset/dry-shoes-tap.md | 5 ++++ .../supportedVersionsChooseLatest.ts | 2 +- .../supportedVersionsToken.ts | 26 +++++++++++++++++++ apps/meteor/jest.config.ts | 1 + .../plugin/compile-version.js | 23 ++++++++++++---- 5 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 .changeset/dry-shoes-tap.md diff --git a/.changeset/dry-shoes-tap.md b/.changeset/dry-shoes-tap.md new file mode 100644 index 000000000000..f5abf51c0df0 --- /dev/null +++ b/.changeset/dry-shoes-tap.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes the supported versions problem, where in most cases the data chosen was the oldest diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts index 3493401144cf..32753ba00429 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts @@ -2,7 +2,7 @@ import type { SignedSupportedVersions } from '@rocket.chat/server-cloud-communic export const supportedVersionsChooseLatest = async (...tokens: (SignedSupportedVersions | undefined)[]) => { const [token] = (tokens.filter((r) => r?.timestamp != null) as SignedSupportedVersions[]).sort((a, b) => { - return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(); + return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(); }); return token; diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts index 473acef88c29..a543c0681f38 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts @@ -62,6 +62,7 @@ const cacheValueInSettings = ( reset: () => Promise; } => { const reset = async () => { + SystemLogger.debug(`Resetting cached value ${key} in settings`); const value = await fn(); await Settings.updateValueById(key, value); @@ -134,6 +135,31 @@ const getSupportedVersionsToken = async () => { (response.success && response.result) || undefined, ); + SystemLogger.debug({ + msg: 'Supported versions', + supportedVersionsFromBuild: supportedVersionsFromBuild.timestamp, + versionsFromLicense: versionsFromLicense?.supportedVersions?.timestamp, + response: response.success && response.result?.timestamp, + }); + + switch (supportedVersions) { + case supportedVersionsFromBuild: + SystemLogger.info({ + msg: 'Using supported versions from build', + }); + break; + case versionsFromLicense?.supportedVersions: + SystemLogger.info({ + msg: 'Using supported versions from license', + }); + break; + case response.success && response.result: + SystemLogger.info({ + msg: 'Using supported versions from cloud', + }); + break; + } + await buildVersionUpdateMessage(supportedVersions?.versions); return supportedVersions?.signed; diff --git a/apps/meteor/jest.config.ts b/apps/meteor/jest.config.ts index adbd8c26344f..72538cf14d16 100644 --- a/apps/meteor/jest.config.ts +++ b/apps/meteor/jest.config.ts @@ -33,6 +33,7 @@ const config: Config = { '/app/livechat/server/business-hour/**/*.spec.ts?(x)', '/app/livechat/server/api/**/*.spec.ts', '/ee/app/authorization/server/validateUserRoles.spec.ts', + '/app/cloud/server/functions/supportedVersionsToken/**.spec.ts', ], transformIgnorePatterns: ['!/node_modules/jose'], errorOnDeprecated: true, diff --git a/apps/meteor/packages/rocketchat-version/plugin/compile-version.js b/apps/meteor/packages/rocketchat-version/plugin/compile-version.js index e737f07663f3..8750c6851202 100644 --- a/apps/meteor/packages/rocketchat-version/plugin/compile-version.js +++ b/apps/meteor/packages/rocketchat-version/plugin/compile-version.js @@ -21,10 +21,10 @@ class VersionCompiler { function handleError(err) { console.error(err); // TODO remove this when we are ready to fail - // if (process.env.NODE_ENV !== 'development') { - // reject(err); - // return; - // } + if (process.env.NODE_ENV !== 'development') { + reject(err); + return; + } resolve({}); } @@ -34,11 +34,24 @@ class VersionCompiler { response.on('data', function (chunk) { data += chunk; }); - response.on('end', function () { + response.on('end', async function () { const supportedVersions = JSON.parse(data); if (!supportedVersions?.signed) { return handleError(new Error(`Invalid supportedVersions result:\n URL: ${url} \n RESULT: ${data}`)); } + + // check if timestamp is inside 1 hour within build + if (Math.abs(new Date().getTime() - new Date(supportedVersions.timestamp).getTime()) > 1000 * 60 * 60) { + return handleError(new Error(`Invalid supportedVersions timestamp:\n URL: ${url} \n RESULT: ${data}`)); + } + + for await (const version of supportedVersions.versions) { + // check if expiration is after the first rocket.chat release + if (new Date(version.expiration) < new Date('2019-04-01T00:00:00.000Z')) { + return handleError(new Error(`Invalid supportedVersions expiration:\n URL: ${url} \n RESULT: ${data}`)); + } + } + resolve(supportedVersions); }); response.on('error', function (err) { From 1bdffcde914bf21cb947c8636574096060fbe9bd Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 18 Jun 2024 10:58:22 -0600 Subject: [PATCH 30/94] fix: `QueueInactivityMonitor` not processing inquiries (#32452) --- .changeset/green-camels-repair.md | 5 + .../server/hooks/afterInquiryQueued.ts | 20 +-- .../server/hooks/afterInquiryQueued.spec.ts | 120 ++++++++++++++++++ 3 files changed, 135 insertions(+), 10 deletions(-) create mode 100644 .changeset/green-camels-repair.md create mode 100644 apps/meteor/ee/tests/unit/apps/livechat-enterprise/server/hooks/afterInquiryQueued.spec.ts diff --git a/.changeset/green-camels-repair.md b/.changeset/green-camels-repair.md new file mode 100644 index 000000000000..58b0f6f1a00c --- /dev/null +++ b/.changeset/green-camels-repair.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed 2 issues with `QueueInactivityMonitor` callback. This callback was in charge of scheduling the job that would close the inquiry, but it was checking on a property that didn't exist. This caused the callback to early return without scheduling the job, making the feature to not to work. diff --git a/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterInquiryQueued.ts b/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterInquiryQueued.ts index cb6993b38aec..4dfb3fc9d6eb 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterInquiryQueued.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterInquiryQueued.ts @@ -1,3 +1,4 @@ +import type { ILivechatInquiryRecord } from '@rocket.chat/core-typings'; import moment from 'moment'; import { settings } from '../../../../../app/settings/server'; @@ -5,28 +6,27 @@ import { callbacks } from '../../../../../lib/callbacks'; import { OmnichannelQueueInactivityMonitor } from '../lib/QueueInactivityMonitor'; import { cbLogger } from '../lib/logger'; -let timer = 0; - -const scheduleInquiry = async (inquiry: any): Promise => { - if (!inquiry?._id) { +export const afterInquiryQueued = async (inquiry: ILivechatInquiryRecord) => { + if (!inquiry?._id || !inquiry?._updatedAt) { return; } - if (!inquiry?._updatedAt || !inquiry?._createdAt) { + const timer = settings.get('Livechat_max_queue_wait_time'); + + if (timer <= 0) { return; } // schedule individual jobs instead of property for close inactivty - const newQueueTime = moment(inquiry._updatedAt || inquiry._createdAt).add(timer, 'minutes'); + const newQueueTime = moment(inquiry._updatedAt).add(timer, 'minutes'); cbLogger.debug(`Scheduling estimated close time at ${newQueueTime} for queued inquiry ${inquiry._id}`); await OmnichannelQueueInactivityMonitor.scheduleInquiry(inquiry._id, new Date(newQueueTime.format())); }; -settings.watch('Livechat_max_queue_wait_time', (value) => { - timer = value as number; - if (timer <= 0) { +settings.watch('Livechat_max_queue_wait_time', (value) => { + if (value <= 0) { callbacks.remove('livechat.afterInquiryQueued', 'livechat-inquiry-queued-set-queue-timer'); return; } - callbacks.add('livechat.afterInquiryQueued', scheduleInquiry, callbacks.priority.HIGH, 'livechat-inquiry-queued-set-queue-timer'); + callbacks.add('livechat.afterInquiryQueued', afterInquiryQueued, callbacks.priority.HIGH, 'livechat-inquiry-queued-set-queue-timer'); }); diff --git a/apps/meteor/ee/tests/unit/apps/livechat-enterprise/server/hooks/afterInquiryQueued.spec.ts b/apps/meteor/ee/tests/unit/apps/livechat-enterprise/server/hooks/afterInquiryQueued.spec.ts new file mode 100644 index 000000000000..dcbefd1dfd6e --- /dev/null +++ b/apps/meteor/ee/tests/unit/apps/livechat-enterprise/server/hooks/afterInquiryQueued.spec.ts @@ -0,0 +1,120 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import moment from 'moment'; +import proxyquire from 'proxyquire'; +import sinon from 'sinon'; + +const settingStub = { + watch: sinon.stub(), + get: sinon.stub(), +}; + +const callbackStub = { + add: sinon.stub(), + remove: sinon.stub(), + priority: { HIGH: 'high' }, +}; + +const queueMonitorStub = { + scheduleInquiry: sinon.stub(), +}; + +const { afterInquiryQueued } = proxyquire + .noCallThru() + .load('../../../../../../app/livechat-enterprise/server/hooks/afterInquiryQueued.ts', { + '../../../../../app/settings/server': { + settings: settingStub, + }, + '../../../../../lib/callbacks': { + callbacks: callbackStub, + }, + '../lib/QueueInactivityMonitor': { + OmnichannelQueueInactivityMonitor: queueMonitorStub, + }, + '../lib/logger': { + cbLogger: { debug: sinon.stub() }, + }, + }); + +describe('hooks/afterInquiryQueued', () => { + beforeEach(() => { + callbackStub.add.resetHistory(); + callbackStub.remove.resetHistory(); + queueMonitorStub.scheduleInquiry.resetHistory(); + settingStub.get.resetHistory(); + }); + + it('should call settings.watch at first', () => { + expect(settingStub.watch.callCount).to.be.equal(1); + }); + + it('should call the callback on settings.watch with proper values', () => { + const func = settingStub.watch.getCall(0).args[1]; + + func(1); + expect(callbackStub.add.callCount).to.be.equal(1); + + func(2); + expect(callbackStub.add.callCount).to.be.equal(2); + + func(0); + expect(callbackStub.remove.callCount).to.be.equal(1); + + func(-1); + expect(callbackStub.remove.callCount).to.be.equal(2); + + func(3); + expect(callbackStub.add.callCount).to.be.equal(3); + }); + + it('should return undefined if no inquiry is passed, or if inquiry doesnt have valid properties', async () => { + expect(await afterInquiryQueued(null)).to.be.equal(undefined); + expect(await afterInquiryQueued({})).to.be.equal(undefined); + expect(await afterInquiryQueued({ _id: 'invalid' })).to.be.equal(undefined); + expect(await afterInquiryQueued({ _updatedAt: new Date() })); + expect(await afterInquiryQueued({ _updatedAt: null, _id: 'afsd34asdX' })).to.be.equal(undefined); + }); + + it('should do nothing if timer is set to 0 or less', async () => { + const inquiry = { + _id: 'afsd34asdX', + _updatedAt: new Date(), + }; + + settingStub.get.returns(0); + await afterInquiryQueued(inquiry); + expect(queueMonitorStub.scheduleInquiry.callCount).to.be.equal(0); + + settingStub.get.returns(-1); + await afterInquiryQueued(inquiry); + expect(queueMonitorStub.scheduleInquiry.callCount).to.be.equal(0); + }); + + it('should call .scheduleInquiry with proper data', async () => { + const inquiry = { + _id: 'afsd34asdX', + _updatedAt: new Date(), + }; + + settingStub.get.returns(1); + await afterInquiryQueued(inquiry); + + const newQueueTime = moment(inquiry._updatedAt).add(1, 'minutes'); + + expect(queueMonitorStub.scheduleInquiry.calledWith(inquiry._id, new Date(newQueueTime.format()))).to.be.true; + }); + + it('should call .scheduleInquiry with proper data when more than 1 min is passed as param', async () => { + const inquiry = { + _id: 'afv34avzx', + _updatedAt: new Date(), + }; + + settingStub.get.returns(3); + await afterInquiryQueued(inquiry); + + const newQueueTime = moment(inquiry._updatedAt).add(3, 'minutes'); + + expect(queueMonitorStub.scheduleInquiry.calledWith(inquiry._id, new Date(newQueueTime.format()))).to.be.true; + }); +}); From 30399688fce5bb1482b7737c34cfa92a896ea877 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 18 Jun 2024 13:45:38 -0600 Subject: [PATCH 31/94] fix: PDFs uploaded by "PDF transcript" feature were returnig 403 when attempting to download (#32329) --- .changeset/rude-llamas-notice.md | 8 ++ .../app/file-upload/server/lib/FileUpload.ts | 18 ++++- apps/meteor/server/settings/file-upload.ts | 28 ++++++- apps/meteor/tests/end-to-end/api/09-rooms.js | 34 +++++++++ .../src/OmnichannelTranscript.ts | 76 +++++++++++++------ packages/i18n/src/locales/en.i18n.json | 2 + 6 files changed, 136 insertions(+), 30 deletions(-) create mode 100644 .changeset/rude-llamas-notice.md diff --git a/.changeset/rude-llamas-notice.md b/.changeset/rude-llamas-notice.md new file mode 100644 index 000000000000..90c0ca3bd20a --- /dev/null +++ b/.changeset/rude-llamas-notice.md @@ -0,0 +1,8 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/i18n": patch +"@rocket.chat/omnichannel-services": patch +--- + +Added a new setting `Restrict files access to users who can access room` that controls file visibility. This new setting allows users that "can access a room" to also download the files that are there. This is specially important for users with livechat manager or monitor roles, or agents that have special permissions to view closed rooms, since this allows them to download files on the conversation even after the conversation is closed. +New setting is disabled by default and it is mutually exclusive with the setting `Restrict file access to room members` since this allows _more_ types of users to download files. diff --git a/apps/meteor/app/file-upload/server/lib/FileUpload.ts b/apps/meteor/app/file-upload/server/lib/FileUpload.ts index c824ba6c31a5..08e2ccb0a52b 100644 --- a/apps/meteor/app/file-upload/server/lib/FileUpload.ts +++ b/apps/meteor/app/file-upload/server/lib/FileUpload.ts @@ -28,7 +28,7 @@ import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; import { UploadFS } from '../../../../server/ufs'; import { ufsComplete } from '../../../../server/ufs/ufs-methods'; import type { Store, StoreOptions } from '../../../../server/ufs/ufs-store'; -import { canAccessRoomAsync } from '../../../authorization/server/functions/canAccessRoom'; +import { canAccessRoomAsync, canAccessRoomIdAsync } from '../../../authorization/server/functions/canAccessRoom'; import { settings } from '../../../settings/server'; import { mime } from '../../../utils/lib/mimeTypes'; import { isValidJWT, generateJWT } from '../../../utils/server/lib/JWTHelper'; @@ -463,16 +463,26 @@ export const FileUpload = { return false; } - if (!settings.get('FileUpload_Restrict_to_room_members') || !file?.rid) { + if (!file?.rid) { return true; } - const subscription = await Subscriptions.findOneByRoomIdAndUserId(file.rid, user._id, { projection: { _id: 1 } }); + const fileUploadRestrictedToMembers = settings.get('FileUpload_Restrict_to_room_members'); + const fileUploadRestrictToUsersWhoCanAccessRoom = settings.get('FileUpload_Restrict_to_users_who_can_access_room'); - if (subscription) { + if (!fileUploadRestrictToUsersWhoCanAccessRoom && !fileUploadRestrictedToMembers) { return true; } + if (fileUploadRestrictedToMembers && !fileUploadRestrictToUsersWhoCanAccessRoom) { + const sub = await Subscriptions.findOneByRoomIdAndUserId(file.rid, user._id, { projection: { _id: 1 } }); + return !!sub; + } + + if (fileUploadRestrictToUsersWhoCanAccessRoom && !fileUploadRestrictedToMembers) { + return canAccessRoomIdAsync(file.rid, user._id); + } + return false; }, diff --git a/apps/meteor/server/settings/file-upload.ts b/apps/meteor/server/settings/file-upload.ts index 76e788cda0e2..505520b73e57 100644 --- a/apps/meteor/server/settings/file-upload.ts +++ b/apps/meteor/server/settings/file-upload.ts @@ -33,10 +33,30 @@ export const createFileUploadSettings = () => await this.add('FileUpload_Restrict_to_room_members', true, { type: 'boolean', - enableQuery: { - _id: 'FileUpload_ProtectFiles', - value: true, - }, + enableQuery: [ + { + _id: 'FileUpload_ProtectFiles', + value: true, + }, + { + _id: 'FileUpload_Restrict_to_users_who_can_access_room', + value: false, + }, + ], + }); + + await this.add('FileUpload_Restrict_to_users_who_can_access_room', false, { + type: 'boolean', + enableQuery: [ + { + _id: 'FileUpload_ProtectFiles', + value: true, + }, + { + _id: 'FileUpload_Restrict_to_room_members', + value: false, + }, + ], }); await this.add('FileUpload_RotateImages', true, { diff --git a/apps/meteor/tests/end-to-end/api/09-rooms.js b/apps/meteor/tests/end-to-end/api/09-rooms.js index dc8a6a209300..72bd5819593e 100644 --- a/apps/meteor/tests/end-to-end/api/09-rooms.js +++ b/apps/meteor/tests/end-to-end/api/09-rooms.js @@ -87,11 +87,13 @@ describe('[Rooms]', function () { let userCredentials; const testChannelName = `channel.test.upload.${Date.now()}-${Math.random()}`; let blockedMediaTypes; + let testPrivateChannel; before(async () => { user = await createUser({ joinDefaultChannels: false }); userCredentials = await login(user.username, password); testChannel = (await createRoom({ type: 'c', name: testChannelName })).body.channel; + testPrivateChannel = (await createRoom({ type: 'p', name: `channel.test.private.${Date.now()}-${Math.random()}` })).body.group; blockedMediaTypes = await getSettingValueById('FileUpload_MediaTypeBlackList'); const newBlockedMediaTypes = blockedMediaTypes .split(',') @@ -105,8 +107,10 @@ describe('[Rooms]', function () { deleteRoom({ type: 'c', roomId: testChannel._id }), deleteUser(user), updateSetting('FileUpload_Restrict_to_room_members', true), + updateSetting('FileUpload_Restrict_to_users_who_can_access_room', false), updateSetting('FileUpload_ProtectFiles', true), updateSetting('FileUpload_MediaTypeBlackList', blockedMediaTypes), + deleteRoom({ roomId: testPrivateChannel._id, type: 'p' }), ]), ); @@ -221,6 +225,7 @@ describe('[Rooms]', function () { it('should be able to get the file when no access to the room if setting allows it', async () => { await updateSetting('FileUpload_Restrict_to_room_members', false); + await updateSetting('FileUpload_Restrict_to_users_who_can_access_room', false); await request.get(fileNewUrl).set(userCredentials).expect('Content-Type', 'image/png').expect(200); await request.get(fileOldUrl).set(userCredentials).expect('Content-Type', 'image/png').expect(200); }); @@ -237,6 +242,35 @@ describe('[Rooms]', function () { await request.get(fileOldUrl).set(credentials).expect('Content-Type', 'image/png').expect(200); }); + it('should be able to get the file if not member but can access room if setting allows', async () => { + await updateSetting('FileUpload_Restrict_to_room_members', false); + await updateSetting('FileUpload_Restrict_to_users_who_can_access_room', true); + + await request.get(fileNewUrl).set(userCredentials).expect('Content-Type', 'image/png').expect(200); + await request.get(fileOldUrl).set(userCredentials).expect('Content-Type', 'image/png').expect(200); + }); + + it('should not be able to get the file if not member and cannot access room', async () => { + const { body } = await request + .post(api(`rooms.upload/${testPrivateChannel._id}`)) + .set(credentials) + .attach('file', imgURL) + .expect('Content-Type', 'application/json') + .expect(200); + + const fileUrl = `/file-upload/${body.message.file._id}/${body.message.file.name}`; + + await request.get(fileUrl).set(userCredentials).expect(403); + }); + + it('should respect the setting with less permissions when both are true', async () => { + await updateSetting('FileUpload_ProtectFiles', true); + await updateSetting('FileUpload_Restrict_to_room_members', true); + await updateSetting('FileUpload_Restrict_to_users_who_can_access_room', true); + await request.get(fileNewUrl).set(userCredentials).expect(403); + await request.get(fileOldUrl).set(userCredentials).expect(403); + }); + it('should not be able to get the file without credentials', async () => { await request.get(fileNewUrl).attach('file', imgURL).expect(403); await request.get(fileOldUrl).attach('file', imgURL).expect(403); diff --git a/ee/packages/omnichannel-services/src/OmnichannelTranscript.ts b/ee/packages/omnichannel-services/src/OmnichannelTranscript.ts index 2d273991508b..5f99269f671b 100644 --- a/ee/packages/omnichannel-services/src/OmnichannelTranscript.ts +++ b/ee/packages/omnichannel-services/src/OmnichannelTranscript.ts @@ -336,22 +336,15 @@ export class OmnichannelTranscript extends ServiceClass implements IOmnichannelT const outBuff = await streamToBuffer(stream as Readable); try { - const file = await uploadService.uploadFile({ - userId: details.userId, + const { rid } = await roomService.createDirectMessage({ to: details.userId, from: 'rocket.cat' }); + const [rocketCatFile, transcriptFile] = await this.uploadFiles({ + details, buffer: outBuff, - details: { - // transcript_{company-name)_{date}_{hour}.pdf - name: `${transcriptText}_${data.siteName}_${new Intl.DateTimeFormat('en-US').format(new Date())}_${ - data.visitor?.name || data.visitor?.username || 'Visitor' - }.pdf`, - type: 'application/pdf', - rid: details.rid, - // Rocket.cat is the goat - userId: 'rocket.cat', - size: outBuff.length, - }, + roomIds: [rid, details.rid], + data, + transcriptText, }); - await this.pdfComplete({ details, file }); + await this.pdfComplete({ details, transcriptFile, rocketCatFile }); } catch (e: any) { this.pdfFailed({ details, e }); } @@ -380,7 +373,49 @@ export class OmnichannelTranscript extends ServiceClass implements IOmnichannelT }); } - private async pdfComplete({ details, file }: { details: WorkDetailsWithSource; file: IUpload }): Promise { + private async uploadFiles({ + details, + buffer, + roomIds, + data, + transcriptText, + }: { + details: WorkDetailsWithSource; + buffer: Buffer; + roomIds: string[]; + data: any; + transcriptText: string; + }): Promise { + return Promise.all( + roomIds.map((roomId) => { + return uploadService.uploadFile({ + userId: details.userId, + buffer, + details: { + // transcript_{company-name}_{date}_{hour}.pdf + name: `${transcriptText}_${data.siteName}_${new Intl.DateTimeFormat('en-US').format(new Date())}_${ + data.visitor?.name || data.visitor?.username || 'Visitor' + }.pdf`, + type: 'application/pdf', + rid: roomId, + // Rocket.cat is the goat + userId: 'rocket.cat', + size: buffer.length, + }, + }); + }), + ); + } + + private async pdfComplete({ + details, + transcriptFile, + rocketCatFile, + }: { + details: WorkDetailsWithSource; + transcriptFile: IUpload; + rocketCatFile: IUpload; + }): Promise { this.log.info(`Transcript for room ${details.rid} by user ${details.userId} - Complete`); const user = await Users.findOneById(details.userId); if (!user) { @@ -388,17 +423,14 @@ export class OmnichannelTranscript extends ServiceClass implements IOmnichannelT } // Send the file to the livechat room where this was requested, to keep it in context try { - const [, { rid }] = await Promise.all([ - LivechatRooms.setPdfTranscriptFileIdById(details.rid, file._id), - roomService.createDirectMessage({ to: details.userId, from: 'rocket.cat' }), - ]); + await LivechatRooms.setPdfTranscriptFileIdById(details.rid, transcriptFile._id); this.log.info(`Transcript for room ${details.rid} by user ${details.userId} - Sending success message to user`); const result = await Promise.allSettled([ uploadService.sendFileMessage({ roomId: details.rid, userId: 'rocket.cat', - file, + file: transcriptFile, message: { // Translate from service msg: await translationService.translateToServerLanguage('pdf_success_message'), @@ -406,9 +438,9 @@ export class OmnichannelTranscript extends ServiceClass implements IOmnichannelT }), // Send the file to the user who requested it, so they can download it uploadService.sendFileMessage({ - roomId: rid, + roomId: rocketCatFile.rid || '', userId: 'rocket.cat', - file, + file: rocketCatFile, message: { // Translate from service msg: await translationService.translate('pdf_success_message', user), diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 779c71c9d755..836b534df601 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -2354,6 +2354,8 @@ "FileUpload_Enable_json_web_token_for_files_description": "Appends a JWT to uploaded files urls", "FileUpload_Restrict_to_room_members": "Restrict files to rooms' members", "FileUpload_Restrict_to_room_members_Description": "Restrict the access of files uploaded on rooms to the rooms' members only", + "FileUpload_Restrict_to_users_who_can_access_room": "Restrict files to users who can access the room", + "FileUpload_Restrict_to_users_who_can_access_room_Description": "Restrict the access of files uploaded on rooms to the users who can access the room. This option is mutually exclusive with the \"Restrict files to rooms' members\" option as this one allows for users that are not part of some rooms but have special permissions that allow them to see it to access the files uploaded, for example, Omnichannel Managers & Monitors", "FileUpload_Enabled": "File Uploads Enabled", "FileUpload_Enabled_Direct": "File Uploads Enabled in Direct Messages ", "FileUpload_Error": "File Upload Error", From 6c4977f8ce0eb31f44ff62fd6bcfa8aa81139d01 Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 18 Jun 2024 20:39:14 +0000 Subject: [PATCH 32/94] Bump 6.9.2 --- .changeset/bump-patch-1718743154258.md | 5 +++++ yarn.lock | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 .changeset/bump-patch-1718743154258.md diff --git a/.changeset/bump-patch-1718743154258.md b/.changeset/bump-patch-1718743154258.md new file mode 100644 index 000000000000..e1eaa7980afb --- /dev/null +++ b/.changeset/bump-patch-1718743154258.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Bump @rocket.chat/meteor version. diff --git a/yarn.lock b/yarn.lock index 2688eb2a0cf8..55ea08d561de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8795,10 +8795,10 @@ __metadata: "@rocket.chat/icons": "*" "@rocket.chat/prettier-config": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 3.0.0 - "@rocket.chat/ui-contexts": 7.0.0 + "@rocket.chat/ui-avatar": 3.0.1 + "@rocket.chat/ui-contexts": 7.0.1 "@rocket.chat/ui-kit": 0.34.0 - "@rocket.chat/ui-video-conf": 7.0.0 + "@rocket.chat/ui-video-conf": 7.0.1 "@tanstack/react-query": "*" react: "*" react-dom: "*" @@ -8887,8 +8887,8 @@ __metadata: "@rocket.chat/fuselage-tokens": "*" "@rocket.chat/message-parser": 0.31.29 "@rocket.chat/styled": "*" - "@rocket.chat/ui-client": 7.0.0 - "@rocket.chat/ui-contexts": 7.0.0 + "@rocket.chat/ui-client": 7.0.1 + "@rocket.chat/ui-contexts": 7.0.1 katex: "*" react: "*" languageName: unknown @@ -10106,7 +10106,7 @@ __metadata: typescript: ~5.3.3 peerDependencies: "@rocket.chat/fuselage": "*" - "@rocket.chat/ui-contexts": 7.0.0 + "@rocket.chat/ui-contexts": 7.0.1 react: ~17.0.2 languageName: unknown linkType: soft @@ -10159,7 +10159,7 @@ __metadata: "@rocket.chat/fuselage": "*" "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" - "@rocket.chat/ui-contexts": 7.0.0 + "@rocket.chat/ui-contexts": 7.0.1 react: ~17.0.2 languageName: unknown linkType: soft @@ -10335,8 +10335,8 @@ __metadata: "@rocket.chat/fuselage-hooks": "*" "@rocket.chat/icons": "*" "@rocket.chat/styled": "*" - "@rocket.chat/ui-avatar": 3.0.0 - "@rocket.chat/ui-contexts": 7.0.0 + "@rocket.chat/ui-avatar": 3.0.1 + "@rocket.chat/ui-contexts": 7.0.1 react: ^17.0.2 react-dom: ^17.0.2 languageName: unknown @@ -10426,7 +10426,7 @@ __metadata: peerDependencies: "@rocket.chat/layout": "*" "@rocket.chat/tools": 0.2.1 - "@rocket.chat/ui-contexts": 7.0.0 + "@rocket.chat/ui-contexts": 7.0.1 "@tanstack/react-query": "*" react: "*" react-hook-form: "*" From 4ddf08e77bf743d6ede2ef98f81a0dcd44750660 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:58:10 +0000 Subject: [PATCH 33/94] fix: Not possible to edit room without proper permission with retention policy enabled (#32622) Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com> --- .changeset/nervous-wolves-collect.md | 5 +++ .../EditRoomInfo/useEditRoomInitialValues.ts | 19 +++++++---- .../meteor/tests/e2e/retention-policy.spec.ts | 33 ++++++++++++++----- 3 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 .changeset/nervous-wolves-collect.md diff --git a/.changeset/nervous-wolves-collect.md b/.changeset/nervous-wolves-collect.md new file mode 100644 index 000000000000..e32377f54179 --- /dev/null +++ b/.changeset/nervous-wolves-collect.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes the issue not allowing users without edit-room-retention-policy permission try to edit the room with the retention policy enabled diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts index 128f6c3c66f8..1cb76cadd335 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts +++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts @@ -1,4 +1,5 @@ import type { IRoomWithRetentionPolicy } from '@rocket.chat/core-typings'; +import { usePermission } from '@rocket.chat/ui-contexts'; import { useMemo } from 'react'; import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator'; @@ -6,6 +7,8 @@ import { useRetentionPolicy } from '../../../hooks/useRetentionPolicy'; export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy) => { const retentionPolicy = useRetentionPolicy(room); + const canEditRoomRetentionPolicy = usePermission('edit-room-retention-policy', room._id); + const { t, ro, archived, topic, description, announcement, joinCodeRequired, sysMes, encrypted, retention, reactWhenReadOnly } = room; return useMemo( @@ -24,13 +27,14 @@ export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy) => { systemMessages: Array.isArray(sysMes) ? sysMes : [], hideSysMes: Array.isArray(sysMes) ? !!sysMes?.length : !!sysMes, encrypted, - ...(retentionPolicy?.enabled && { - retentionEnabled: retention?.enabled ?? retentionPolicy.isActive, - retentionOverrideGlobal: !!retention?.overrideGlobal, - retentionMaxAge: retention?.maxAge ?? retentionPolicy.maxAge, - retentionExcludePinned: retention?.excludePinned ?? retentionPolicy.excludePinned, - retentionFilesOnly: retention?.filesOnly ?? retentionPolicy.filesOnly, - }), + ...(canEditRoomRetentionPolicy && + retentionPolicy?.enabled && { + retentionEnabled: retention?.enabled ?? retentionPolicy.isActive, + retentionOverrideGlobal: !!retention?.overrideGlobal, + retentionMaxAge: retention?.maxAge ?? retentionPolicy.maxAge, + retentionExcludePinned: retention?.excludePinned ?? retentionPolicy.excludePinned, + retentionFilesOnly: retention?.filesOnly ?? retentionPolicy.filesOnly, + }), }), [ announcement, @@ -46,6 +50,7 @@ export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy) => { topic, encrypted, reactWhenReadOnly, + canEditRoomRetentionPolicy, ], ); }; diff --git a/apps/meteor/tests/e2e/retention-policy.spec.ts b/apps/meteor/tests/e2e/retention-policy.spec.ts index ba9ec90eff3b..8a808aae579f 100644 --- a/apps/meteor/tests/e2e/retention-policy.spec.ts +++ b/apps/meteor/tests/e2e/retention-policy.spec.ts @@ -85,16 +85,31 @@ test.describe.serial('retention-policy', () => { await expect(poHomeChannel.tabs.room.pruneAccordion).toBeVisible(); }); - test('should not show prune section in edit channel for users without permission', async ({ browser }) => { - const { page } = await createAuxContext(browser, Users.user1); - const auxContext = { page, poHomeChannel: new HomeChannel(page) }; - await auxContext.poHomeChannel.sidenav.openChat(targetChannel); - await auxContext.poHomeChannel.tabs.btnRoomInfo.click(); - await auxContext.poHomeChannel.tabs.room.btnEdit.click(); + test.describe('edit-room-retention-policy permission', async () => { + test('should not show prune section in edit channel for users without permission', async ({ browser }) => { + const { page } = await createAuxContext(browser, Users.user1); + const auxContext = { page, poHomeChannel: new HomeChannel(page) }; + await auxContext.poHomeChannel.sidenav.openChat(targetChannel); + await auxContext.poHomeChannel.tabs.btnRoomInfo.click(); + await auxContext.poHomeChannel.tabs.room.btnEdit.click(); + + await expect(poHomeChannel.tabs.room.pruneAccordion).not.toBeVisible(); + await auxContext.page.close(); + }); - await expect(poHomeChannel.tabs.room.pruneAccordion).not.toBeVisible(); - await auxContext.page.close(); - }) + test('users without permission should be able to edit the channel', async ({ browser }) => { + const { page } = await createAuxContext(browser, Users.user1); + const auxContext = { page, poHomeChannel: new HomeChannel(page) }; + await auxContext.poHomeChannel.sidenav.openChat(targetChannel); + await auxContext.poHomeChannel.tabs.btnRoomInfo.click(); + await auxContext.poHomeChannel.tabs.room.btnEdit.click(); + await auxContext.poHomeChannel.tabs.room.checkboxReadOnly.check(); + await auxContext.poHomeChannel.tabs.room.btnSave.click(); + + await expect(auxContext.poHomeChannel.getSystemMessageByText('set room to read only')).toBeVisible(); + await auxContext.page.close(); + }); + }); test.describe('retention policy applies enabled by default', () => { test.beforeAll(async ({ api }) => { From 904f970154b5a5ae33896cfedd4f588278ae4702 Mon Sep 17 00:00:00 2001 From: "dionisio-bot[bot]" <117394943+dionisio-bot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:36:46 +0000 Subject: [PATCH 34/94] fix: Supported Versions misbehaving (#32621) Co-authored-by: Guilherme Gazzo <5263975+ggazzo@users.noreply.github.com> --- .changeset/dry-shoes-tap.md | 5 ++++ .../supportedVersionsChooseLatest.ts | 2 +- .../supportedVersionsToken.ts | 26 +++++++++++++++++++ apps/meteor/jest.config.ts | 1 + .../plugin/compile-version.js | 23 ++++++++++++---- 5 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 .changeset/dry-shoes-tap.md diff --git a/.changeset/dry-shoes-tap.md b/.changeset/dry-shoes-tap.md new file mode 100644 index 000000000000..f5abf51c0df0 --- /dev/null +++ b/.changeset/dry-shoes-tap.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes the supported versions problem, where in most cases the data chosen was the oldest diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts index 3493401144cf..32753ba00429 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsChooseLatest.ts @@ -2,7 +2,7 @@ import type { SignedSupportedVersions } from '@rocket.chat/server-cloud-communic export const supportedVersionsChooseLatest = async (...tokens: (SignedSupportedVersions | undefined)[]) => { const [token] = (tokens.filter((r) => r?.timestamp != null) as SignedSupportedVersions[]).sort((a, b) => { - return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(); + return new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(); }); return token; diff --git a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts index 473acef88c29..a543c0681f38 100644 --- a/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts +++ b/apps/meteor/app/cloud/server/functions/supportedVersionsToken/supportedVersionsToken.ts @@ -62,6 +62,7 @@ const cacheValueInSettings = ( reset: () => Promise; } => { const reset = async () => { + SystemLogger.debug(`Resetting cached value ${key} in settings`); const value = await fn(); await Settings.updateValueById(key, value); @@ -134,6 +135,31 @@ const getSupportedVersionsToken = async () => { (response.success && response.result) || undefined, ); + SystemLogger.debug({ + msg: 'Supported versions', + supportedVersionsFromBuild: supportedVersionsFromBuild.timestamp, + versionsFromLicense: versionsFromLicense?.supportedVersions?.timestamp, + response: response.success && response.result?.timestamp, + }); + + switch (supportedVersions) { + case supportedVersionsFromBuild: + SystemLogger.info({ + msg: 'Using supported versions from build', + }); + break; + case versionsFromLicense?.supportedVersions: + SystemLogger.info({ + msg: 'Using supported versions from license', + }); + break; + case response.success && response.result: + SystemLogger.info({ + msg: 'Using supported versions from cloud', + }); + break; + } + await buildVersionUpdateMessage(supportedVersions?.versions); return supportedVersions?.signed; diff --git a/apps/meteor/jest.config.ts b/apps/meteor/jest.config.ts index adbd8c26344f..72538cf14d16 100644 --- a/apps/meteor/jest.config.ts +++ b/apps/meteor/jest.config.ts @@ -33,6 +33,7 @@ const config: Config = { '/app/livechat/server/business-hour/**/*.spec.ts?(x)', '/app/livechat/server/api/**/*.spec.ts', '/ee/app/authorization/server/validateUserRoles.spec.ts', + '/app/cloud/server/functions/supportedVersionsToken/**.spec.ts', ], transformIgnorePatterns: ['!/node_modules/jose'], errorOnDeprecated: true, diff --git a/apps/meteor/packages/rocketchat-version/plugin/compile-version.js b/apps/meteor/packages/rocketchat-version/plugin/compile-version.js index e737f07663f3..8750c6851202 100644 --- a/apps/meteor/packages/rocketchat-version/plugin/compile-version.js +++ b/apps/meteor/packages/rocketchat-version/plugin/compile-version.js @@ -21,10 +21,10 @@ class VersionCompiler { function handleError(err) { console.error(err); // TODO remove this when we are ready to fail - // if (process.env.NODE_ENV !== 'development') { - // reject(err); - // return; - // } + if (process.env.NODE_ENV !== 'development') { + reject(err); + return; + } resolve({}); } @@ -34,11 +34,24 @@ class VersionCompiler { response.on('data', function (chunk) { data += chunk; }); - response.on('end', function () { + response.on('end', async function () { const supportedVersions = JSON.parse(data); if (!supportedVersions?.signed) { return handleError(new Error(`Invalid supportedVersions result:\n URL: ${url} \n RESULT: ${data}`)); } + + // check if timestamp is inside 1 hour within build + if (Math.abs(new Date().getTime() - new Date(supportedVersions.timestamp).getTime()) > 1000 * 60 * 60) { + return handleError(new Error(`Invalid supportedVersions timestamp:\n URL: ${url} \n RESULT: ${data}`)); + } + + for await (const version of supportedVersions.versions) { + // check if expiration is after the first rocket.chat release + if (new Date(version.expiration) < new Date('2019-04-01T00:00:00.000Z')) { + return handleError(new Error(`Invalid supportedVersions expiration:\n URL: ${url} \n RESULT: ${data}`)); + } + } + resolve(supportedVersions); }); response.on('error', function (err) { From f9a125f7517bd224955940ac7af68ec1e250265b Mon Sep 17 00:00:00 2001 From: rocketchat-github-ci Date: Tue, 18 Jun 2024 21:46:12 +0000 Subject: [PATCH 35/94] Release 6.9.2 [no ci] --- .changeset/bump-patch-1718743154258.md | 5 --- .changeset/dry-shoes-tap.md | 5 --- .changeset/nervous-wolves-collect.md | 5 --- apps/meteor/CHANGELOG.md | 38 +++++++++++++++++++ apps/meteor/app/utils/rocketchat.info | 2 +- apps/meteor/ee/server/services/CHANGELOG.md | 13 +++++++ apps/meteor/ee/server/services/package.json | 2 +- apps/meteor/package.json | 2 +- ee/apps/account-service/CHANGELOG.md | 13 +++++++ ee/apps/account-service/package.json | 2 +- ee/apps/authorization-service/CHANGELOG.md | 13 +++++++ ee/apps/authorization-service/package.json | 2 +- ee/apps/ddp-streamer/CHANGELOG.md | 15 ++++++++ ee/apps/ddp-streamer/package.json | 2 +- ee/apps/omnichannel-transcript/CHANGELOG.md | 14 +++++++ ee/apps/omnichannel-transcript/package.json | 2 +- ee/apps/presence-service/CHANGELOG.md | 13 +++++++ ee/apps/presence-service/package.json | 2 +- ee/apps/queue-worker/CHANGELOG.md | 13 +++++++ ee/apps/queue-worker/package.json | 2 +- ee/apps/stream-hub-service/CHANGELOG.md | 12 ++++++ ee/apps/stream-hub-service/package.json | 2 +- ee/packages/api-client/CHANGELOG.md | 10 +++++ ee/packages/api-client/package.json | 2 +- ee/packages/ddp-client/CHANGELOG.md | 10 +++++ ee/packages/ddp-client/package.json | 2 +- ee/packages/license/CHANGELOG.md | 9 +++++ ee/packages/license/package.json | 2 +- ee/packages/omnichannel-services/CHANGELOG.md | 14 +++++++ ee/packages/omnichannel-services/package.json | 2 +- ee/packages/pdf-worker/CHANGELOG.md | 9 +++++ ee/packages/pdf-worker/package.json | 2 +- ee/packages/presence/CHANGELOG.md | 11 ++++++ ee/packages/presence/package.json | 2 +- package.json | 2 +- packages/apps/CHANGELOG.md | 10 +++++ packages/apps/package.json | 2 +- packages/core-services/CHANGELOG.md | 11 ++++++ packages/core-services/package.json | 2 +- packages/core-typings/CHANGELOG.md | 2 + packages/core-typings/package.json | 2 +- packages/cron/CHANGELOG.md | 10 +++++ packages/cron/package.json | 2 +- packages/fuselage-ui-kit/CHANGELOG.md | 13 +++++++ packages/fuselage-ui-kit/package.json | 10 ++--- packages/gazzodown/CHANGELOG.md | 11 ++++++ packages/gazzodown/package.json | 6 +-- packages/instance-status/CHANGELOG.md | 9 +++++ packages/instance-status/package.json | 2 +- packages/livechat/CHANGELOG.md | 9 +++++ packages/livechat/package.json | 2 +- packages/model-typings/CHANGELOG.md | 9 +++++ packages/model-typings/package.json | 2 +- packages/models/CHANGELOG.md | 9 +++++ packages/models/package.json | 2 +- packages/rest-typings/CHANGELOG.md | 9 +++++ packages/rest-typings/package.json | 2 +- packages/ui-avatar/CHANGELOG.md | 9 +++++ packages/ui-avatar/package.json | 4 +- packages/ui-client/CHANGELOG.md | 9 +++++ packages/ui-client/package.json | 4 +- packages/ui-contexts/CHANGELOG.md | 11 ++++++ packages/ui-contexts/package.json | 2 +- packages/ui-video-conf/CHANGELOG.md | 10 +++++ packages/ui-video-conf/package.json | 6 +-- packages/uikit-playground/CHANGELOG.md | 11 ++++++ packages/uikit-playground/package.json | 2 +- packages/web-ui-registration/CHANGELOG.md | 9 +++++ packages/web-ui-registration/package.json | 4 +- 69 files changed, 413 insertions(+), 60 deletions(-) delete mode 100644 .changeset/bump-patch-1718743154258.md delete mode 100644 .changeset/dry-shoes-tap.md delete mode 100644 .changeset/nervous-wolves-collect.md diff --git a/.changeset/bump-patch-1718743154258.md b/.changeset/bump-patch-1718743154258.md deleted file mode 100644 index e1eaa7980afb..000000000000 --- a/.changeset/bump-patch-1718743154258.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Bump @rocket.chat/meteor version. diff --git a/.changeset/dry-shoes-tap.md b/.changeset/dry-shoes-tap.md deleted file mode 100644 index f5abf51c0df0..000000000000 --- a/.changeset/dry-shoes-tap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes the supported versions problem, where in most cases the data chosen was the oldest diff --git a/.changeset/nervous-wolves-collect.md b/.changeset/nervous-wolves-collect.md deleted file mode 100644 index e32377f54179..000000000000 --- a/.changeset/nervous-wolves-collect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes the issue not allowing users without edit-room-retention-policy permission try to edit the room with the retention policy enabled diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index 01f03feede53..568551d83efc 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,43 @@ # @rocket.chat/meteor +## 6.9.2 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- Bump @rocket.chat/meteor version. + +- ([#32621](https://github.com/RocketChat/Rocket.Chat/pull/32621) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixes the supported versions problem, where in most cases the data chosen was the oldest + +- ([#32622](https://github.com/RocketChat/Rocket.Chat/pull/32622) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixes the issue not allowing users without edit-room-retention-policy permission try to edit the room with the retention policy enabled + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/rest-typings@6.9.2 + - @rocket.chat/api-client@0.1.35 + - @rocket.chat/license@0.1.17 + - @rocket.chat/omnichannel-services@0.1.17 + - @rocket.chat/pdf-worker@0.0.41 + - @rocket.chat/presence@0.1.17 + - @rocket.chat/apps@0.0.8 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/cron@0.0.37 + - @rocket.chat/fuselage-ui-kit@7.0.2 + - @rocket.chat/gazzodown@7.0.2 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/ui-contexts@7.0.2 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.0.41 + - @rocket.chat/ui-theming@0.1.2 + - @rocket.chat/ui-avatar@3.0.2 + - @rocket.chat/ui-client@7.0.2 + - @rocket.chat/ui-video-conf@7.0.2 + - @rocket.chat/web-ui-registration@7.0.2 + - @rocket.chat/instance-status@0.0.41 +
+ ## 6.9.1 ### Patch Changes diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index 0d691fdac398..cc8e5187532e 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "6.9.1" + "version": "6.9.2" } diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 45f79ddff653..8f290fdfc02f 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.1.35 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/rest-typings@6.9.2 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/models@0.0.41 +
+ ## 1.1.34 ### Patch Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index d06f186c54d2..ef22c256b16a 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.1.34", + "version": "1.1.35", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 90fb64ffd9b2..a2e16b1fc2d3 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/meteor", "description": "The Ultimate Open Source WebChat Platform", - "version": "6.9.1", + "version": "6.9.2", "private": true, "author": { "name": "Rocket.Chat", diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 280a3aa42d85..671adfd9ce11 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.3.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/rest-typings@6.9.2 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/models@0.0.41 +
+ ## 0.3.15 ### Patch Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 4dfcfddf52f8..5eecfad9c85b 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.3.15", + "version": "0.3.16", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index 154195b03b36..c67b683c7de5 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.3.17 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/rest-typings@6.9.2 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/models@0.0.41 +
+ ## 0.3.16 ### Patch Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index fce4a93c8095..11dca4b9486a 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.3.16", + "version": "0.3.17", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index 9d873f7c8c5d..c1e756872a04 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/ddp-streamer +## 0.2.16 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/rest-typings@6.9.2 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/ui-contexts@7.0.2 + - @rocket.chat/models@0.0.41 + - @rocket.chat/instance-status@0.0.41 +
+ ## 0.2.15 ### Patch Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index 65f1c4c8771c..16e720c32f1a 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.2.15", + "version": "0.2.16", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 134f9f227233..2cc91503c175 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.3.17 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/omnichannel-services@0.1.17 + - @rocket.chat/pdf-worker@0.0.41 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/models@0.0.41 +
+ ## 0.3.16 ### Patch Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index ed1e72a2f255..1125b97465c8 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.3.16", + "version": "0.3.17", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index f7a1137542f3..7e91a67a33c9 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.3.17 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/presence@0.1.17 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/models@0.0.41 +
+ ## 0.3.16 ### Patch Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 6bb46c544f57..3cfc4e1f774b 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.3.16", + "version": "0.3.17", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index d277d3c9b4cb..68e08fc6f24d 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.3.17 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/omnichannel-services@0.1.17 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/models@0.0.41 +
+ ## 0.3.16 ### Patch Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index 8359965f43f8..5078bc7688a2 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.3.16", + "version": "0.3.17", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index bde0be97af7f..c99d7fe17a90 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.3.17 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/models@0.0.41 +
+ ## 0.3.16 ### Patch Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 920f0ed1a18e..c0d5d4c3a0c5 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.3.16", + "version": "0.3.17", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/api-client/CHANGELOG.md b/ee/packages/api-client/CHANGELOG.md index 2d8287498da8..9aedd3e31b8e 100644 --- a/ee/packages/api-client/CHANGELOG.md +++ b/ee/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.1.35 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/rest-typings@6.9.2 +
+ ## 0.1.34 ### Patch Changes diff --git a/ee/packages/api-client/package.json b/ee/packages/api-client/package.json index a31a69aed784..bf8b4a265633 100644 --- a/ee/packages/api-client/package.json +++ b/ee/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.1.34", + "version": "0.1.35", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/ddp-client/CHANGELOG.md b/ee/packages/ddp-client/CHANGELOG.md index 38c87b8b935b..8be607b752a7 100644 --- a/ee/packages/ddp-client/CHANGELOG.md +++ b/ee/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ddp-client +## 0.2.26 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/rest-typings@6.9.2 + - @rocket.chat/api-client@0.1.35 +
+ ## 0.2.25 ### Patch Changes diff --git a/ee/packages/ddp-client/package.json b/ee/packages/ddp-client/package.json index 53a4e54e45bc..eeea113b6d09 100644 --- a/ee/packages/ddp-client/package.json +++ b/ee/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.2.25", + "version": "0.2.26", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index 62511825e26d..36256098a621 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.1.17 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 +
+ ## 0.1.16 ### Patch Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index d2e88d8baaf7..110cc52e665c 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.1.16", + "version": "0.1.17", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 1e632412860d..53cc775f3078 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.1.17 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/rest-typings@6.9.2 + - @rocket.chat/pdf-worker@0.0.41 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/model-typings@0.4.3 + - @rocket.chat/models@0.0.41 +
+ ## 0.1.16 ### Patch Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 55abce301be6..f3742ae8cf28 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.1.16", + "version": "0.1.17", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index 6a48406ea25a..cc698cfe6eda 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.0.41 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 +
+ ## 0.0.40 ### Patch Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index fdb192d4ada8..6333076d7d92 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.0.40", + "version": "0.0.41", "private": true, "devDependencies": { "@storybook/addon-essentials": "~6.5.16", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index d3579b6166aa..2b95edf08955 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.1.17 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/core-services@0.3.17 + - @rocket.chat/models@0.0.41 +
+ ## 0.1.16 ### Patch Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 2367b5968e0f..2d2c0e0812e8 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.1.16", + "version": "0.1.17", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/package.json b/package.json index c4e0e5f88083..58b95aae2f5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket.chat", - "version": "6.9.1", + "version": "6.9.2", "description": "Rocket.Chat Monorepo", "main": "index.js", "private": true, diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index 2d1d944b1ad2..d02ee61e3287 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.0.8 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/model-typings@0.4.3 +
+ ## 0.0.7 ### Patch Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 23103ffe2a28..9e0e3fd50370 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.0.7", + "version": "0.0.8", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index 929bc8b3147c..0f4cbd1a25ee 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.3.17 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/rest-typings@6.9.2 + - @rocket.chat/models@0.0.41 +
+ ## 0.3.16 ### Patch Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 0d7dd248fa7e..dbe14d65b44e 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.3.16", + "version": "0.3.17", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index fed7f005f13f..d84b2e22394c 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.9.2 + ## 6.9.1 ## 6.9.0 diff --git a/packages/core-typings/package.json b/packages/core-typings/package.json index 0760888ba467..0cde77f14653 100644 --- a/packages/core-typings/package.json +++ b/packages/core-typings/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package", "name": "@rocket.chat/core-typings", - "version": "6.9.1", + "version": "6.9.2", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "eslint": "~8.45.0", diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index 472bc38c0b03..8c4de9eeb866 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.0.37 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/models@0.0.41 +
+ ## 0.0.36 ### Patch Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index 4d6d7c999fd3..196e5e0aff88 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.0.36", + "version": "0.0.37", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 21714d28c544..703f201c2e6d 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 7.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/gazzodown@7.0.2 + - @rocket.chat/ui-contexts@7.0.2 + - @rocket.chat/ui-avatar@3.0.2 + - @rocket.chat/ui-video-conf@7.0.2 +
+ ## 7.0.1 ### Patch Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 87fd209fc567..95ca5fb02e9d 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "7.0.1", + "version": "7.0.2", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "3.0.1", - "@rocket.chat/ui-contexts": "7.0.1", + "@rocket.chat/ui-avatar": "3.0.2", + "@rocket.chat/ui-contexts": "7.0.2", "@rocket.chat/ui-kit": "0.34.0", - "@rocket.chat/ui-video-conf": "7.0.1", + "@rocket.chat/ui-video-conf": "7.0.2", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" @@ -110,7 +110,7 @@ "typescript": "~5.3.3" }, "dependencies": { - "@rocket.chat/core-typings": "6.9.1", + "@rocket.chat/core-typings": "6.9.2", "@rocket.chat/gazzodown": "workspace:^", "@rocket.chat/ui-kit": "workspace:~", "tslib": "^2.5.3" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index bba54175bf43..e2e1d386e084 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 7.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/ui-contexts@7.0.2 + - @rocket.chat/ui-client@7.0.2 +
+ ## 7.0.1 ### Patch Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 023fa4975075..f7e9a0285e15 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "7.0.1", + "version": "7.0.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -71,8 +71,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "7.0.1", - "@rocket.chat/ui-contexts": "7.0.1", + "@rocket.chat/ui-client": "7.0.2", + "@rocket.chat/ui-contexts": "7.0.2", "katex": "*", "react": "*" }, diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index 6b7d85d501e2..b8573dd5266f 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.0.41 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.0.41 +
+ ## 0.0.40 ### Patch Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index d5a199a1b10c..4b6aa0e2ae69 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.0.40", + "version": "0.0.41", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index f7d7ed0299a9..3197453ab223 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.17.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@7.0.2 +
+ ## 1.17.1 ### Patch Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 123248dc3c17..5e81124af9e5 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.17.1", + "version": "1.17.2", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 7c6fe4aebaa7..9747271d17c2 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.4.3 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 +
+ ## 0.4.2 ### Patch Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index fdacc8878eff..79a30873f55b 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.4.2", + "version": "0.4.3", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index c572246539df..2c2b98e4782b 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.0.41 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.4.3 +
+ ## 0.0.40 ### Patch Changes diff --git a/packages/models/package.json b/packages/models/package.json index 5d2eae9a49bc..8478daa44a15 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.0.40", + "version": "0.0.41", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 87ea17ff0985..341eaba24b2e 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.9.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 +
+ ## 6.9.1 ### Patch Changes diff --git a/packages/rest-typings/package.json b/packages/rest-typings/package.json index 864b4264b383..e1aea379a724 100644 --- a/packages/rest-typings/package.json +++ b/packages/rest-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/rest-typings", - "version": "6.9.1", + "version": "6.9.2", "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", "@types/jest": "~29.5.7", diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index 9617d88d5efa..120c996ee337 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 3.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@7.0.2 +
+ ## 3.0.1 ### Patch Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index bb0c167de8d9..dceb7d4b4d19 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "3.0.1", + "version": "3.0.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "7.0.1", + "@rocket.chat/ui-contexts": "7.0.2", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 147cbf298895..b368d3282f18 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 7.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@7.0.2 +
+ ## 7.0.1 ### Patch Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 3c43d85aa0ef..a611a191d7cd 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "7.0.1", + "version": "7.0.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -63,7 +63,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "7.0.1", + "@rocket.chat/ui-contexts": "7.0.2", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index 5d3fb186fb4d..be571cce3c21 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 7.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.9.2 + - @rocket.chat/rest-typings@6.9.2 + - @rocket.chat/ddp-client@0.2.26 +
+ ## 7.0.1 ### Patch Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index 96d5d4bdf335..5e4f7ba63440 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "7.0.1", + "version": "7.0.2", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index b56b9e522d6d..a524dc81e307 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 7.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@7.0.2 + - @rocket.chat/ui-avatar@3.0.2 +
+ ## 7.0.1 ### Patch Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 5398fe901457..41532ca53714 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "7.0.1", + "version": "7.0.2", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -36,8 +36,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "3.0.1", - "@rocket.chat/ui-contexts": "7.0.1", + "@rocket.chat/ui-avatar": "3.0.2", + "@rocket.chat/ui-contexts": "7.0.2", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index 914f4a8c5941..5242d3ad96a9 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.2.25 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@7.0.2 + - @rocket.chat/ui-contexts@7.0.2 + - @rocket.chat/ui-avatar@3.0.2 +
+ ## 0.2.24 ### Patch Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 3a63ac38a3ec..a37f6bbd3d1d 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.2.24", + "version": "0.2.25", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index 955775cb3873..79c08ded7098 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 7.0.2 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@7.0.2 +
+ ## 7.0.1 ### Patch Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index 837e150bbb0f..95ee383c3c21 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "7.0.1", + "version": "7.0.2", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -51,7 +51,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.1", - "@rocket.chat/ui-contexts": "7.0.1", + "@rocket.chat/ui-contexts": "7.0.2", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", From 02dd87574bc0939fb38a428c1fb623c3b752d6ca Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Silva <36537004+matheusbsilva137@users.noreply.github.com> Date: Wed, 19 Jun 2024 08:13:21 -0300 Subject: [PATCH 36/94] feat: Use `application/octet-stream` as a fallback media type to avoid "Unknown media type" errors (#32471) --- .changeset/breezy-pens-sing.md | 6 +++ .../app/api/server/lib/getUploadFormData.ts | 6 ++- apps/meteor/app/utils/lib/mimeTypes.ts | 7 ++- .../body/hooks/useFileUploadDropTarget.ts | 7 ++- .../hooks/useFileUploadAction.ts | 6 +-- apps/meteor/server/settings/file-upload.ts | 1 + apps/meteor/tests/data/interactions.ts | 1 + apps/meteor/tests/e2e/file-upload.spec.ts | 21 +++++++++ .../tests/e2e/fixtures/files/diagram.drawio | 13 +++++ apps/meteor/tests/end-to-end/api/09-rooms.js | 47 ++++++++++++++++--- packages/i18n/src/locales/en.i18n.json | 1 + 11 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 .changeset/breezy-pens-sing.md create mode 100644 apps/meteor/tests/e2e/fixtures/files/diagram.drawio diff --git a/.changeset/breezy-pens-sing.md b/.changeset/breezy-pens-sing.md new file mode 100644 index 000000000000..0725999ef62b --- /dev/null +++ b/.changeset/breezy-pens-sing.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/i18n": minor +--- + +Removed "Unknown media type" errors on the client side by using `application/octet-stream` as a fallback media type (MIME type) for all files diff --git a/apps/meteor/app/api/server/lib/getUploadFormData.ts b/apps/meteor/app/api/server/lib/getUploadFormData.ts index 9b8f69fb3a66..85fc0658542d 100644 --- a/apps/meteor/app/api/server/lib/getUploadFormData.ts +++ b/apps/meteor/app/api/server/lib/getUploadFormData.ts @@ -5,6 +5,8 @@ import type { ValidateFunction } from 'ajv'; import busboy from 'busboy'; import type { Request } from 'express'; +import { getMimeType } from '../../../utils/lib/mimeTypes'; + type UploadResult = { file: Readable & { truncated: boolean }; fieldname: string; @@ -61,7 +63,7 @@ export async function getUploadFormData< function onFile( fieldname: string, file: Readable & { truncated: boolean }, - { filename, encoding, mimeType: mimetype }: { filename: string; encoding: string; mimeType: string }, + { filename, encoding }: { filename: string; encoding: string }, ) { if (options.field && fieldname !== options.field) { file.resume(); @@ -83,7 +85,7 @@ export async function getUploadFormData< file, filename, encoding, - mimetype, + mimetype: getMimeType(filename), fieldname, fields, fileBuffer: Buffer.concat(fileChunks), diff --git a/apps/meteor/app/utils/lib/mimeTypes.ts b/apps/meteor/app/utils/lib/mimeTypes.ts index f2da185f84ba..909a955d6724 100644 --- a/apps/meteor/app/utils/lib/mimeTypes.ts +++ b/apps/meteor/app/utils/lib/mimeTypes.ts @@ -12,4 +12,9 @@ const getExtension = (param: string): string => { return !extension || typeof extension === 'boolean' ? '' : extension; }; -export { mime, getExtension }; +const getMimeType = (fileName: string): string => { + const fileMimeType = mime.lookup(fileName); + return typeof fileMimeType === 'string' ? fileMimeType : 'application/octet-stream'; +}; + +export { mime, getExtension, getMimeType }; diff --git a/apps/meteor/client/views/room/body/hooks/useFileUploadDropTarget.ts b/apps/meteor/client/views/room/body/hooks/useFileUploadDropTarget.ts index 2427f7217401..414b91c52493 100644 --- a/apps/meteor/client/views/room/body/hooks/useFileUploadDropTarget.ts +++ b/apps/meteor/client/views/room/body/hooks/useFileUploadDropTarget.ts @@ -29,7 +29,7 @@ export const useFileUploadDropTarget = (): readonly [ const t = useTranslation(); - const fileUploadEnabled = useSetting('FileUpload_Enabled') as boolean; + const fileUploadEnabled = useSetting('FileUpload_Enabled'); const user = useUser(); const fileUploadAllowedForUser = useReactiveValue( useCallback(() => !roomCoordinator.readOnly(room._id, { username: user?.username }), [room._id, user?.username]), @@ -38,8 +38,7 @@ export const useFileUploadDropTarget = (): readonly [ const chat = useChat(); const onFileDrop = useMutableCallback(async (files: File[]) => { - const { mime } = await import('../../../../../app/utils/lib/mimeTypes'); - + const { getMimeType } = await import('../../../../../app/utils/lib/mimeTypes'); const getUniqueFiles = () => { const uniqueFiles: File[] = []; const st: Set = new Set(); @@ -55,7 +54,7 @@ export const useFileUploadDropTarget = (): readonly [ const uniqueFiles = getUniqueFiles(); const uploads = Array.from(uniqueFiles).map((file) => { - Object.defineProperty(file, 'type', { value: mime.lookup(file.name) }); + Object.defineProperty(file, 'type', { value: getMimeType(file.name) }); return file; }); diff --git a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useFileUploadAction.ts b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useFileUploadAction.ts index aba008a353a5..03229c5dceb3 100644 --- a/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useFileUploadAction.ts +++ b/apps/meteor/client/views/room/composer/messageBox/MessageBoxActionsToolbar/hooks/useFileUploadAction.ts @@ -9,7 +9,7 @@ const fileInputProps = { type: 'file', multiple: true }; export const useFileUploadAction = (disabled: boolean): GenericMenuItemProps => { const t = useTranslation(); - const fileUploadEnabled = useSetting('FileUpload_Enabled'); + const fileUploadEnabled = useSetting('FileUpload_Enabled'); const fileInputRef = useFileInput(fileInputProps); const chat = useChat(); @@ -23,10 +23,10 @@ export const useFileUploadAction = (disabled: boolean): GenericMenuItemProps => }; const handleUploadChange = async () => { - const { mime } = await import('../../../../../../../app/utils/lib/mimeTypes'); + const { getMimeType } = await import('../../../../../../../app/utils/lib/mimeTypes'); const filesToUpload = Array.from(fileInputRef?.current?.files ?? []).map((file) => { Object.defineProperty(file, 'type', { - value: mime.lookup(file.name), + value: getMimeType(file.name), }); return file; }); diff --git a/apps/meteor/server/settings/file-upload.ts b/apps/meteor/server/settings/file-upload.ts index 505520b73e57..90032266651c 100644 --- a/apps/meteor/server/settings/file-upload.ts +++ b/apps/meteor/server/settings/file-upload.ts @@ -23,6 +23,7 @@ export const createFileUploadSettings = () => type: 'string', public: true, i18nDescription: 'FileUpload_MediaTypeBlackListDescription', + alert: 'FileUpload_MediaTypeBlackList_Alert', }); await this.add('FileUpload_ProtectFiles', true, { diff --git a/apps/meteor/tests/data/interactions.ts b/apps/meteor/tests/data/interactions.ts index d14749181193..085d97d4ece3 100644 --- a/apps/meteor/tests/data/interactions.ts +++ b/apps/meteor/tests/data/interactions.ts @@ -1,5 +1,6 @@ export const targetUser = 'rocket.cat'; export const imgURL = './public/images/logo/1024x1024.png'; export const lstURL = './tests/e2e/fixtures/files/lst-test.lst'; +export const drawioURL = './tests/e2e/fixtures/files/diagram.drawio'; export const svgLogoURL = './public/images/logo/logo.svg'; export const svgLogoFileName = 'logo.svg'; diff --git a/apps/meteor/tests/e2e/file-upload.spec.ts b/apps/meteor/tests/e2e/file-upload.spec.ts index b382476c0a2f..0a5d1cfd2512 100644 --- a/apps/meteor/tests/e2e/file-upload.spec.ts +++ b/apps/meteor/tests/e2e/file-upload.spec.ts @@ -1,6 +1,7 @@ import { Users } from './fixtures/userStates'; import { HomeChannel } from './page-objects'; import { createTargetChannel } from './utils'; +import { setSettingValueById } from './utils/setSettingValueById'; import { expect, test } from './utils/test'; test.use({ storageState: Users.user1.state }); @@ -10,6 +11,7 @@ test.describe.serial('file-upload', () => { let targetChannel: string; test.beforeAll(async ({ api }) => { + await setSettingValueById(api, 'FileUpload_MediaTypeBlackList', 'image/svg+xml'); targetChannel = await createTargetChannel(api); }); @@ -21,6 +23,7 @@ test.describe.serial('file-upload', () => { }); test.afterAll(async ({ api }) => { + await setSettingValueById(api, 'FileUpload_MediaTypeBlackList', 'image/svg+xml'); expect((await api.post('/channels.delete', { roomName: targetChannel })).status()).toBe(200); }); @@ -54,4 +57,22 @@ test.describe.serial('file-upload', () => { await expect(poHomeChannel.content.getFileDescription).toHaveText('lst_description'); await expect(poHomeChannel.content.lastMessageFileName).toContainText('lst-test.lst'); }); + + test('expect send drawio (unknown media type) file succesfully', async ({ page }) => { + await page.reload(); + await poHomeChannel.content.sendFileMessage('diagram.drawio'); + await poHomeChannel.content.descriptionInput.fill('drawio_description'); + await poHomeChannel.content.btnModalConfirm.click(); + + await expect(poHomeChannel.content.getFileDescription).toHaveText('drawio_description'); + await expect(poHomeChannel.content.lastMessageFileName).toContainText('diagram.drawio'); + }); + + test('expect not to send drawio file (unknown media type) when the default media type is blocked', async ({ api, page }) => { + await setSettingValueById(api, 'FileUpload_MediaTypeBlackList', 'application/octet-stream'); + + await page.reload(); + await poHomeChannel.content.sendFileMessage('diagram.drawio'); + await expect(poHomeChannel.content.btnModalConfirm).not.toBeVisible(); + }); }); diff --git a/apps/meteor/tests/e2e/fixtures/files/diagram.drawio b/apps/meteor/tests/e2e/fixtures/files/diagram.drawio new file mode 100644 index 000000000000..a86c2673ab98 --- /dev/null +++ b/apps/meteor/tests/e2e/fixtures/files/diagram.drawio @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/apps/meteor/tests/end-to-end/api/09-rooms.js b/apps/meteor/tests/end-to-end/api/09-rooms.js index 72bd5819593e..0809d06b324d 100644 --- a/apps/meteor/tests/end-to-end/api/09-rooms.js +++ b/apps/meteor/tests/end-to-end/api/09-rooms.js @@ -7,7 +7,7 @@ import { after, afterEach, before, beforeEach, describe, it } from 'mocha'; import { sleep } from '../../../lib/utils/sleep'; import { getCredentials, api, request, credentials } from '../../data/api-data.js'; import { sendSimpleMessage, deleteMessage } from '../../data/chat.helper'; -import { imgURL, lstURL, svgLogoFileName, svgLogoURL } from '../../data/interactions'; +import { drawioURL, imgURL, lstURL, svgLogoFileName, svgLogoURL } from '../../data/interactions'; import { getSettingValueById, updateEEPermission, updatePermission, updateSetting } from '../../data/permissions.helper'; import { createRoom, deleteRoom } from '../../data/rooms.helper'; import { deleteTeam } from '../../data/teams.helper'; @@ -183,8 +183,8 @@ describe('[Rooms]', function () { }); }); - it('should upload a LST file to room', (done) => { - request + it('should upload a LST file to room', () => { + return request .post(api(`rooms.upload/${testChannel._id}`)) .set(credentials) .attach('file', lstURL) @@ -200,12 +200,33 @@ describe('[Rooms]', function () { expect(res.body.message).to.have.property('files'); expect(res.body.message.files).to.be.an('array').of.length(1); expect(res.body.message.files[0]).to.have.property('name', 'lst-test.lst'); - }) - .end(done); + expect(res.body.message.files[0]).to.have.property('type', 'text/plain'); + }); + }); + + it('should upload a DRAWIO file (unknown media type) to room', () => { + return request + .post(api(`rooms.upload/${testChannel._id}`)) + .set(credentials) + .attach('file', drawioURL) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('message'); + expect(res.body.message).to.have.property('attachments'); + expect(res.body.message.attachments).to.be.an('array').of.length(1); + expect(res.body.message.attachments[0]).to.have.property('format', 'DRAWIO'); + expect(res.body.message.attachments[0]).to.have.property('title', 'diagram.drawio'); + expect(res.body.message).to.have.property('files'); + expect(res.body.message.files).to.be.an('array').of.length(1); + expect(res.body.message.files[0]).to.have.property('name', 'diagram.drawio'); + expect(res.body.message.files[0]).to.have.property('type', 'application/octet-stream'); + }); }); it('should not allow uploading a blocked media type to a room', async () => { - await updateSetting('FileUpload_MediaTypeBlackList', 'application/octet-stream'); + await updateSetting('FileUpload_MediaTypeBlackList', 'text/plain'); await request .post(api(`rooms.upload/${testChannel._id}`)) .set(credentials) @@ -218,6 +239,20 @@ describe('[Rooms]', function () { }); }); + it('should not allow uploading an unknown media type to a room if the default one is blocked', async () => { + await updateSetting('FileUpload_MediaTypeBlackList', 'application/octet-stream'); + await request + .post(api(`rooms.upload/${testChannel._id}`)) + .set(credentials) + .attach('file', drawioURL) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-invalid-file-type'); + }); + }); + it('should be able to get the file', async () => { await request.get(fileNewUrl).set(credentials).expect('Content-Type', 'image/png').expect(200); await request.get(fileOldUrl).set(credentials).expect('Content-Type', 'image/png').expect(200); diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 836b534df601..1277a02375bf 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -2383,6 +2383,7 @@ "FileUpload_MediaType_NotAccepted": "Media Types Not Accepted", "FileUpload_MediaTypeBlackList": "Blocked Media Types", "FileUpload_MediaTypeBlackListDescription": "Comma-separated list of media types. This setting has priority over the Accepted Media Types.", + "FileUpload_MediaTypeBlackList_Alert": "The default media type for unknown file extensions is \"application/octet-stream\", to work only with known file extensions you can add it to the \"Blocked Media Types\" list.", "FileUpload_MediaTypeWhiteList": "Accepted Media Types", "FileUpload_MediaTypeWhiteListDescription": "Comma-separated list of media types. Leave it blank for accepting all media types.", "FileUpload_ProtectFiles": "Protect Uploaded Files", From 70e39680ab6736f4a254900f8e60829e242726cc Mon Sep 17 00:00:00 2001 From: Tiago Evangelista Pinto Date: Wed, 19 Jun 2024 11:40:03 -0300 Subject: [PATCH 37/94] fix(Omnichannel): Contact Center sort by date (#32566) --- .changeset/proud-coats-repair.md | 5 ++ .../directory/contacts/ContactTable.tsx | 10 +++- apps/meteor/tests/data/livechat/rooms.ts | 4 +- .../end-to-end/api/livechat/11-livechat.ts | 46 +++++++++++++++++-- 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 .changeset/proud-coats-repair.md diff --git a/.changeset/proud-coats-repair.md b/.changeset/proud-coats-repair.md new file mode 100644 index 000000000000..ba1e16b7e05d --- /dev/null +++ b/.changeset/proud-coats-repair.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fix the sorting by last chat in Contact Center table diff --git a/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx b/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx index 1238732edf66..76fdce05c9bb 100644 --- a/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx +++ b/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx @@ -26,7 +26,7 @@ import { useCurrentContacts } from './hooks/useCurrentContacts'; function ContactTable(): ReactElement { const { current, itemsPerPage, setItemsPerPage, setCurrent, ...paginationProps } = usePagination(); - const { sortBy, sortDirection, setSort } = useSort<'username' | 'phone' | 'name' | 'visitorEmails.address' | 'lastchat'>('username'); + const { sortBy, sortDirection, setSort } = useSort<'username' | 'phone' | 'name' | 'visitorEmails.address' | 'lastChat.ts'>('username'); const isCallReady = useIsCallReady(); const [term, setTerm] = useDebouncedState('', 500); @@ -90,7 +90,13 @@ function ContactTable(): ReactElement { > {t('Email')} - + {t('Last_Chat')} diff --git a/apps/meteor/tests/data/livechat/rooms.ts b/apps/meteor/tests/data/livechat/rooms.ts index ff7819a6365b..921e7bb08582 100644 --- a/apps/meteor/tests/data/livechat/rooms.ts +++ b/apps/meteor/tests/data/livechat/rooms.ts @@ -32,7 +32,7 @@ export const createLivechatRoom = async (visitorToken: string, extraRoomParams?: return response.body.room; }; -export const createVisitor = (department?: string): Promise => +export const createVisitor = (department?: string, visitorName?: string): Promise => new Promise((resolve, reject) => { const token = getRandomVisitorToken(); const email = `${token}@${token}.com`; @@ -46,7 +46,7 @@ export const createVisitor = (department?: string): Promise => .set(credentials) .send({ visitor: { - name: `Visitor ${Date.now()}`, + name: visitorName || `Visitor ${Date.now()}`, email, token, phone, diff --git a/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts b/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts index 3fa2b9f6b89e..09d90b7da8d1 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts +++ b/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts @@ -1,11 +1,18 @@ import { expect } from 'chai'; -import { before, describe, it } from 'mocha'; +import { after, before, describe, it } from 'mocha'; import { sleep } from '../../../../lib/utils/sleep'; import { getCredentials, api, request, credentials } from '../../../data/api-data'; import { createCustomField, deleteCustomField } from '../../../data/livechat/custom-fields'; import { addOrRemoveAgentFromDepartment, createDepartmentWithAnOnlineAgent } from '../../../data/livechat/department'; -import { createVisitor, createLivechatRoom, makeAgentUnavailable, closeOmnichannelRoom, sendMessage } from '../../../data/livechat/rooms'; +import { + createVisitor, + createLivechatRoom, + makeAgentUnavailable, + closeOmnichannelRoom, + sendMessage, + deleteVisitor, +} from '../../../data/livechat/rooms'; import { createBotAgent, getRandomVisitorToken } from '../../../data/livechat/users'; import { removePermissionFromAllRoles, restorePermissionToRoles, updatePermission, updateSetting } from '../../../data/permissions.helper'; import { IS_EE } from '../../../e2e/config/constants'; @@ -15,8 +22,9 @@ describe('LIVECHAT - Utils', function () { before((done) => getCredentials(done)); - before(async () => { + after(async () => { await updateSetting('Livechat_enabled', true); + await updateSetting('Livechat_offline_email', ''); }); describe('livechat/offline.message', () => { @@ -453,6 +461,38 @@ describe('LIVECHAT - Utils', function () { expect(body).to.have.property('token', visitor.token); }); }); + describe('livechat/visitors.search', () => { + it('should bring sorted data by last chat time', async () => { + const visitor1 = await createVisitor(undefined, 'VisitorInPast'); + const room1 = await createLivechatRoom(visitor1.token); + + const visitor2 = await createVisitor(undefined, 'VisitorInPresent'); + const room2 = await createLivechatRoom(visitor2.token); + + const { body: result1 } = await request + .get(api('livechat/visitors.search?term=VisitorIn&sort={"lastChat.ts":1}')) + .set(credentials) + .send(); + + expect(result1).to.have.property('visitors').that.is.an('array'); + expect(result1.visitors[0]).to.have.property('name'); + expect(result1.visitors[0].name).to.be.eq('VisitorInPast'); + + const { body: result2 } = await request + .get(api('livechat/visitors.search?term=VisitorIn&sort={"lastChat.ts":-1}')) + .set(credentials) + .send(); + + expect(result2).to.have.property('visitors').that.is.an('array'); + expect(result2.visitors[0]).to.have.property('name'); + expect(result2.visitors[0].name).to.be.eq('VisitorInPresent'); + + await closeOmnichannelRoom(room1._id); + await closeOmnichannelRoom(room2._id); + await deleteVisitor(visitor1.token); + await deleteVisitor(visitor2.token); + }); + }); describe('livechat/message', () => { it('should fail if no token', async () => { From c5edd0435268d3f813c6c256cefe80a06e34c31c Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Wed, 19 Jun 2024 14:49:46 -0300 Subject: [PATCH 38/94] fix: Settings code mirror broken on full screen mode (#32625) --- .changeset/odd-goats-fix.md | 5 +++++ .../CustomScrollbars/CustomScrollbars.tsx | 21 ++++++++++++------- .../CustomScrollbars/VirtuosoScrollbars.tsx | 10 +++------ .../inputs/CodeMirror/CodeMirrorBox.tsx | 4 +++- apps/meteor/tests/e2e/administration.spec.ts | 13 ++++++++++++ apps/meteor/tests/e2e/page-objects/admin.ts | 8 +++++++ 6 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 .changeset/odd-goats-fix.md diff --git a/.changeset/odd-goats-fix.md b/.changeset/odd-goats-fix.md new file mode 100644 index 000000000000..9178620391be --- /dev/null +++ b/.changeset/odd-goats-fix.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes an issue where settings code mirror is not being displayed correctly in full screen mode diff --git a/apps/meteor/client/components/CustomScrollbars/CustomScrollbars.tsx b/apps/meteor/client/components/CustomScrollbars/CustomScrollbars.tsx index 18bdbdead14e..ca718199076e 100644 --- a/apps/meteor/client/components/CustomScrollbars/CustomScrollbars.tsx +++ b/apps/meteor/client/components/CustomScrollbars/CustomScrollbars.tsx @@ -1,8 +1,8 @@ import { Palette } from '@rocket.chat/fuselage'; import type { ScrollValues } from 'rc-scrollbars'; import { Scrollbars } from 'rc-scrollbars'; -import type { MutableRefObject, CSSProperties, ReactNode, ReactElement } from 'react'; -import React, { memo, forwardRef, useCallback } from 'react'; +import type { MutableRefObject, CSSProperties, ReactNode } from 'react'; +import React, { memo, forwardRef, useCallback, useMemo } from 'react'; export type CustomScrollbarsProps = { overflowX?: boolean; @@ -14,10 +14,18 @@ export type CustomScrollbarsProps = { autoHide?: boolean; }; +const styleDefault: CSSProperties = { + flexGrow: 1, + willChange: 'transform', + overflowY: 'hidden', +}; + const CustomScrollbars = forwardRef(function CustomScrollbars( - { children, onScroll, overflowX, renderView, ...props }, + { children, style, onScroll, overflowX, renderView, ...props }, ref, ) { + const scrollbarsStyle = useMemo(() => ({ ...style, ...styleDefault }), [style]); + const refSetter = useCallback( (scrollbarRef) => { if (ref && scrollbarRef) { @@ -38,12 +46,11 @@ const CustomScrollbars = forwardRef(function autoHide autoHideTimeout={2000} autoHideDuration={500} + style={scrollbarsStyle} onScrollFrame={onScroll} renderView={renderView} - renderTrackHorizontal={ - overflowX ? undefined : (props): ReactElement =>
- } - renderThumbVertical={({ style, ...props }): JSX.Element => ( + renderTrackHorizontal={overflowX ? undefined : (props) =>
} + renderThumbVertical={({ style, ...props }) => (
)} children={children} diff --git a/apps/meteor/client/components/CustomScrollbars/VirtuosoScrollbars.tsx b/apps/meteor/client/components/CustomScrollbars/VirtuosoScrollbars.tsx index a7d0371e4ab8..b07083be1a03 100644 --- a/apps/meteor/client/components/CustomScrollbars/VirtuosoScrollbars.tsx +++ b/apps/meteor/client/components/CustomScrollbars/VirtuosoScrollbars.tsx @@ -1,4 +1,4 @@ -import type { ComponentProps, ReactElement, Ref } from 'react'; +import type { ComponentProps, Ref } from 'react'; import React, { forwardRef } from 'react'; import CustomScrollbars from './CustomScrollbars'; @@ -8,13 +8,9 @@ type VirtuosoScrollbarsProps = ComponentProps; const VirtuosoScrollbars = forwardRef(function VirtuosoScrollbars( { style, children, ...props }: VirtuosoScrollbarsProps, ref: Ref, -): ReactElement { +) { return ( -
} - > +
}> {children} ); diff --git a/apps/meteor/client/views/admin/settings/inputs/CodeMirror/CodeMirrorBox.tsx b/apps/meteor/client/views/admin/settings/inputs/CodeMirror/CodeMirrorBox.tsx index ce6d2dfd6000..3f61417e4fa6 100644 --- a/apps/meteor/client/views/admin/settings/inputs/CodeMirror/CodeMirrorBox.tsx +++ b/apps/meteor/client/views/admin/settings/inputs/CodeMirror/CodeMirrorBox.tsx @@ -39,7 +39,9 @@ const CodeMirrorBox = ({ label, children }: { label: ReactNode; children: ReactE {label} )} - {children} + + {children} +