Skip to content

Commit

Permalink
Merge branch 'develop' into chore/reportsPage-misaligned
Browse files Browse the repository at this point in the history
  • Loading branch information
rique223 authored Oct 11, 2023
2 parents 8672f9c + 223dce1 commit e5434d3
Show file tree
Hide file tree
Showing 23 changed files with 389 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changeset/eleven-gorillas-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fix trying to upload same file again and again.
6 changes: 6 additions & 0 deletions .changeset/popular-actors-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/model-typings": patch
---

Do not allow auto-translation to be enabled in E2E rooms
9 changes: 8 additions & 1 deletion apps/meteor/app/autotranslate/server/methods/saveSettings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Subscriptions } from '@rocket.chat/models';
import { Subscriptions, Rooms } from '@rocket.chat/models';
import type { ServerMethods } from '@rocket.chat/ui-contexts';
import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
Expand Down Expand Up @@ -46,6 +46,13 @@ Meteor.methods<ServerMethods>({

switch (field) {
case 'autoTranslate':
const room = await Rooms.findE2ERoomById(rid, { projection: { _id: 1 } });
if (room && value === '1') {
throw new Meteor.Error('error-e2e-enabled', 'Enabling auto-translation in E2E encrypted rooms is not allowed', {
method: 'saveAutoTranslateSettings',
});
}

await Subscriptions.updateAutoTranslateById(subscription._id, value === '1');
if (!subscription.autoTranslateLanguage && options.defaultLanguage) {
await Subscriptions.updateAutoTranslateLanguageById(subscription._id, options.defaultLanguage);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Message } from '@rocket.chat/core-services';
import type { IUser } from '@rocket.chat/core-typings';
import { isRegisterUser } from '@rocket.chat/core-typings';
import { Rooms } from '@rocket.chat/models';
import { Rooms, Subscriptions } from '@rocket.chat/models';
import { Match } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
import type { UpdateResult } from 'mongodb';
Expand All @@ -25,5 +25,9 @@ export const saveRoomEncrypted = async function (rid: string, encrypted: boolean

await Message.saveSystemMessage(type, rid, user.username, user);
}

if (encrypted) {
await Subscriptions.disableAutoTranslateByRoomId(rid);
}
return update;
};
22 changes: 19 additions & 3 deletions apps/meteor/client/hooks/roomActions/useE2EERoomAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { e2e } from '../../../app/e2e/client/rocketchat.e2e';
import { useRoom } from '../../views/room/contexts/RoomContext';
import { dispatchToastMessage } from '../../lib/toast';
import { useRoom, useRoomSubscription } from '../../views/room/contexts/RoomContext';
import type { RoomToolboxActionConfig } from '../../views/room/contexts/RoomToolboxContext';
import { useReactiveValue } from '../useReactiveValue';

export const useE2EERoomAction = () => {
const enabled = useSetting('E2E_Enable', false);
const room = useRoom();
const subscription = useRoomSubscription();
const readyToEncrypt = useReactiveValue(useCallback(() => e2e.isReady(), [])) || room.encrypted;
const permittedToToggleEncryption = usePermission('toggle-room-e2e-encryption', room._id);
const permittedToEditRoom = usePermission('edit-room', room._id);
Expand All @@ -21,8 +23,22 @@ export const useE2EERoomAction = () => {

const toggleE2E = useEndpoint('POST', '/v1/rooms.saveRoomSettings');

const action = useMutableCallback(() => {
void toggleE2E({ rid: room._id, encrypted: !room.encrypted });
const action = useMutableCallback(async () => {
const { success } = await toggleE2E({ rid: room._id, encrypted: !room.encrypted });
if (!success) {
return;
}

dispatchToastMessage({
type: 'success',
message: room.encrypted
? t('E2E_Encryption_disabled_for_room', { roomName: room.name })
: t('E2E_Encryption_enabled_for_room', { roomName: room.name }),
});

if (subscription?.autoTranslate) {
dispatchToastMessage({ type: 'success', message: t('AutoTranslate_Disabled_for_room', { roomName: room.name }) });
}
});

const enabledOnRoom = !!room.encrypted;
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/client/lib/chats/ChatAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export type ChatAPI = {
ActionManager: any;

readonly flows: {
readonly uploadFiles: (files: readonly File[]) => Promise<void>;
readonly uploadFiles: (files: readonly File[], resetFileInput?: () => void) => Promise<void>;
readonly sendMessage: ({ text, tshow }: { text: string; tshow?: boolean; previewUrls?: string[] }) => Promise<boolean>;
readonly processSlashCommand: (message: IMessage, userId: string | null) => Promise<boolean>;
readonly processTooLongMessage: (message: IMessage) => Promise<boolean>;
Expand Down
3 changes: 2 additions & 1 deletion apps/meteor/client/lib/chats/flows/uploadFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { imperativeModal } from '../../imperativeModal';
import { prependReplies } from '../../utils/prependReplies';
import type { ChatAPI } from '../ChatAPI';

export const uploadFiles = async (chat: ChatAPI, files: readonly File[]): Promise<void> => {
export const uploadFiles = async (chat: ChatAPI, files: readonly File[], resetFileInput?: () => void): Promise<void> => {
const replies = chat.composer?.quotedMessages.get() ?? [];

const msg = await prependReplies('', replies);
Expand Down Expand Up @@ -52,4 +52,5 @@ export const uploadFiles = async (chat: ChatAPI, files: readonly File[]): Promis
};

uploadNextFile();
resetFileInput?.();
};
19 changes: 15 additions & 4 deletions apps/meteor/client/views/room/Header/icons/Encrypted.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@ import type { IRoom } from '@rocket.chat/core-typings';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import colors from '@rocket.chat/fuselage-tokens/colors';
import { HeaderState } from '@rocket.chat/ui-client';
import { useSetting, usePermission, useMethod, useTranslation } from '@rocket.chat/ui-contexts';
import { useSetting, usePermission, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import React, { memo } from 'react';

import { dispatchToastMessage } from '../../../../lib/toast';

const Encrypted = ({ room }: { room: IRoom }) => {
const t = useTranslation();
const e2eEnabled = useSetting('E2E_Enable');
const toggleE2E = useMethod('saveRoomSettings');
const toggleE2E = useEndpoint('POST', '/v1/rooms.saveRoomSettings');
const canToggleE2E = usePermission('toggle-room-e2e-encryption');
const encryptedLabel = canToggleE2E ? t('Encrypted_key_title') : t('Encrypted');
const handleE2EClick = useMutableCallback(() => {
const handleE2EClick = useMutableCallback(async () => {
if (!canToggleE2E) {
return;
}
toggleE2E(room._id, 'encrypted', !room?.encrypted);

const { success } = await toggleE2E({ rid: room._id, encrypted: !room.encrypted });
if (!success) {
return;
}

dispatchToastMessage({
type: 'success',
message: t('E2E_Encryption_disabled_for_room', { roomName: room.name }),
});
});
return e2eEnabled && room?.encrypted ? (
<HeaderState title={encryptedLabel} icon='key' onClick={handleE2EClick} color={colors.s500} tiny />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ const FileUploadAction = ({ collapsed, chatContext, disabled, ...props }: FileUp
const fileInputRef = useRef<HTMLInputElement>(null);
const chat = useChat() ?? chatContext;

const resetFileInput = () => {
if (!fileInputRef.current) {
return;
}

fileInputRef.current.value = '';
};

const handleUploadChange = async (e: ChangeEvent<HTMLInputElement>) => {
const { mime } = await import('../../../../../../../app/utils/lib/mimeTypes');
const filesToUpload = Array.from(e.target.files ?? []).map((file) => {
Expand All @@ -26,8 +34,7 @@ const FileUploadAction = ({ collapsed, chatContext, disabled, ...props }: FileUp
});
return file;
});

chat?.flows.uploadFiles(filesToUpload);
chat?.flows.uploadFiles(filesToUpload, resetFileInput);
};

const handleUpload = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FieldGroup, Field, FieldLabel, FieldRow, ToggleSwitch, Select } from '@rocket.chat/fuselage';
import { Callout, FieldGroup, Field, FieldLabel, FieldRow, ToggleSwitch, Select } from '@rocket.chat/fuselage';
import type { SelectOption } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactElement, ChangeEvent } from 'react';
Expand All @@ -11,6 +11,7 @@ import {
ContextualbarIcon,
ContextualbarContent,
} from '../../../../components/Contextualbar';
import { useRoom } from '../../contexts/RoomContext';

type AutoTranslateProps = {
language: string;
Expand All @@ -30,6 +31,7 @@ const AutoTranslate = ({
handleClose,
}: AutoTranslateProps): ReactElement => {
const t = useTranslation();
const room = useRoom();

return (
<>
Expand All @@ -40,14 +42,24 @@ const AutoTranslate = ({
</ContextualbarHeader>
<ContextualbarContent pbs={24}>
<FieldGroup>
{room.encrypted && (
<Callout title={t('Automatic_translation_not_available')} type='warning'>
{t('Automatic_translation_not_available_info')}
</Callout>
)}
<Field>
<FieldRow>
<ToggleSwitch id='automatic-translation' onChange={handleSwitch} defaultChecked={translateEnable} />
<ToggleSwitch
id='automatic-translation'
onChange={handleSwitch}
defaultChecked={translateEnable}
disabled={room.encrypted && !translateEnable}
/>
<FieldLabel htmlFor='automatic-translation'>{t('Automatic_Translation')}</FieldLabel>
</FieldRow>
</Field>
<Field>
<FieldLabel htmlFor='language'>{t('Language')}</FieldLabel>
<FieldLabel htmlFor='translate-to'>{t('Translate_to')}</FieldLabel>
<FieldRow verticalAlign='middle'>
<Select
id='language'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useLanguage } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { useMemo, useEffect, useState, memo } from 'react';
import { useTranslation } from 'react-i18next';

import { useEndpointAction } from '../../../../hooks/useEndpointAction';
import { useEndpointData } from '../../../../hooks/useEndpointData';
import { dispatchToastMessage } from '../../../../lib/toast';
import { useRoom, useRoomSubscription } from '../../contexts/RoomContext';
import { useRoomToolbox } from '../../contexts/RoomToolboxContext';
import AutoTranslate from './AutoTranslate';
Expand All @@ -16,10 +18,12 @@ const AutoTranslateWithData = (): ReactElement => {
const userLanguage = useLanguage();
const [currentLanguage, setCurrentLanguage] = useState(subscription?.autoTranslateLanguage ?? '');
const saveSettings = useEndpointAction('POST', '/v1/autotranslate.saveSettings');
const { t } = useTranslation();

const { value: translateData } = useEndpointData('/v1/autotranslate.getSupportedLanguages', {
params: useMemo(() => ({ targetLanguage: userLanguage }), [userLanguage]),
});
const languagesDict = translateData ? Object.fromEntries(translateData.languages.map((lang) => [lang.language, lang.name])) : {};

const handleChangeLanguage = useMutableCallback((value) => {
setCurrentLanguage(value);
Expand All @@ -29,6 +33,10 @@ const AutoTranslateWithData = (): ReactElement => {
field: 'autoTranslateLanguage',
value,
});
dispatchToastMessage({
type: 'success',
message: t('AutoTranslate_language_set_to', { language: languagesDict[value] }),
});
});

const handleSwitch = useMutableCallback((event) => {
Expand All @@ -37,6 +45,18 @@ const AutoTranslateWithData = (): ReactElement => {
field: 'autoTranslate',
value: event.target.checked,
});
dispatchToastMessage({
type: 'success',
message: event.target.checked
? t('AutoTranslate_Enabled_for_room', { roomName: room.name })
: t('AutoTranslate_Disabled_for_room', { roomName: room.name }),
});
if (event.target.checked && currentLanguage) {
dispatchToastMessage({
type: 'success',
message: t('AutoTranslate_language_set_to', { language: languagesDict[currentLanguage] }),
});
}
});

useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/ee/app/livechat-enterprise/server/lib/units.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ async function hasUnits(): Promise<boolean> {
}

// Units should't change really often, so we can cache the result
const memoizedHasUnits = mem(hasUnits, { maxAge: 10000 });
const memoizedHasUnits = mem(hasUnits, { maxAge: process.env.TEST_MODE ? 1 : 10000 });

export async function getUnitsFromUser(): Promise<{ [k: string]: any }[] | undefined> {
if (!(await memoizedHasUnits())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ async function getDepartmentsFromUserRoles(user: string): Promise<string[]> {
return (await LivechatDepartmentAgents.findByAgentId(user).toArray()).map((department) => department.departmentId);
}

const memoizedGetUnitFromUserRoles = mem(getUnitsFromUserRoles, { maxAge: 10000 });
const memoizedGetDepartmentsFromUserRoles = mem(getDepartmentsFromUserRoles, { maxAge: 5000 });
const memoizedGetUnitFromUserRoles = mem(getUnitsFromUserRoles, { maxAge: process.env.TEST_MODE ? 1 : 10000 });
const memoizedGetDepartmentsFromUserRoles = mem(getDepartmentsFromUserRoles, { maxAge: process.env.TEST_MODE ? 1 : 10000 });

export const getUnitsFromUser = async (user: string): Promise<string[] | undefined> => {
if (!user || (await hasAnyRoleAsync(user, ['admin', 'livechat-manager']))) {
Expand Down
16 changes: 12 additions & 4 deletions apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,8 @@
"Authorization_URL": "Authorization URL",
"Authorize": "Authorize",
"Authorize_access_to_your_account": "Authorize access to your account",
"Automatic_translation_not_available": "Automatic translation not available",
"Automatic_translation_not_available_info": "This room has E2E encryption enabled, translation cannot work with encrypted messages",
"Auto_Load_Images": "Auto Load Images",
"Auto_Selection": "Auto Selection",
"Auto_Translate": "Auto-Translate",
Expand All @@ -715,11 +717,14 @@
"AutoTranslate_APIKey": "API Key",
"AutoTranslate_Change_Language_Description": "Changing the auto-translate language does not translate previous messages.",
"AutoTranslate_DeepL": "DeepL",
"AutoTranslate_Disabled_for_room": "Auto-translate disabled for #{{roomName}}",
"AutoTranslate_Enabled": "Enable Auto-Translate",
"AutoTranslate_Enabled_Description": "Enabling auto-translation will allow people with the `auto-translate` permission to have all messages automatically translated into their selected language. Fees may apply.",
"AutoTranslate_Enabled_for_room": "Auto-translate enabled for #{{roomName}}",
"AutoTranslate_AutoEnableOnJoinRoom": "Auto-Translate for non-default language members",
"AutoTranslate_AutoEnableOnJoinRoom_Description": "If enabled, whenever a user with a language preference different than the workspace default joins a room, it will be automatically translated for them.",
"AutoTranslate_Google": "Google",
"AutoTranslate_language_set_to": "Auto-translate language set to {{language}}",
"AutoTranslate_Microsoft": "Microsoft",
"AutoTranslate_Microsoft_API_Key": "Ocp-Apim-Subscription-Key",
"AutoTranslate_ServiceProvider": "Service Provider",
Expand Down Expand Up @@ -1676,7 +1681,7 @@
"Discussion": "Discussion",
"Discussion_Description": "Discussions are an additional way to organize conversations that allows inviting users from outside channels to participate in specific conversations.",
"Discussion_description": "Help keep an overview of what's going on! By creating a discussion, a sub-channel of the one you selected is created and both are linked.",
"Discussion_first_message_disabled_due_to_e2e": "You can start sending End-to-End encrypted messages in this discussion after its creation.",
"Discussion_first_message_disabled_due_to_e2e": "You can start sending End-to-end encrypted messages in this discussion after its creation.",
"Discussion_first_message_title": "Your message",
"Discussion_name": "Discussion name",
"Discussion_start": "Start a Discussion",
Expand Down Expand Up @@ -1739,6 +1744,8 @@
"Markdown_Marked_Tables": "Enable Marked Tables",
"duplicated-account": "Duplicated account",
"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}}",
"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.",
Expand All @@ -1751,7 +1758,7 @@
"E2E_Enabled_Default_DirectRooms": "Enable encryption for Direct Rooms by default",
"E2E_Enabled_Default_PrivateRooms": "Enable encryption for Private Rooms by default",
"E2E_Encryption_Password_Change": "Change Encryption Password",
"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.<br/><br/>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_Encryption_Password_Explanation": "You can now create encrypted private groups and direct messages. You may also change existing private groups or DMs to encrypted.<br/><br/>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. <br/>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.",
Expand Down Expand Up @@ -1876,7 +1883,7 @@
"Enable_unlimited_apps": "Enable unlimited apps",
"Enabled": "Enabled",
"Encrypted": "Encrypted",
"Encrypted_channel_Description": "End to end encrypted channel. Search will not work with encrypted channels and notifications may not show the messages content.",
"Encrypted_channel_Description": "End-to-end encrypted channel. Search will not work with encrypted channels and notifications may not show the messages content.",
"Encrypted_key_title": "Click here to disable end-to-end encryption for this channel (requires e2ee-permission)",
"Encrypted_message": "Encrypted message",
"Encrypted_setting_changed_successfully": "Encrypted setting changed successfully",
Expand Down Expand Up @@ -4986,7 +4993,7 @@
"Teams_New_Description_Label": "Topic",
"Teams_New_Description_Placeholder": "What is this team about",
"Teams_New_Encrypted_Description_Disabled": "Only available for private team",
"Teams_New_Encrypted_Description_Enabled": "End to end encrypted team. Search will not work with encrypted Teams and notifications may not show the messages content.",
"Teams_New_Encrypted_Description_Enabled": "End-to-end encrypted team. Search will not work with encrypted Teams and notifications may not show the messages content.",
"Teams_New_Encrypted_Label": "Encrypted",
"Teams_New_Private_Description_Disabled": "When disabled, anyone can join the team",
"Teams_New_Private_Description_Enabled": "Only invited people can join",
Expand Down Expand Up @@ -5185,6 +5192,7 @@
"Transferred": "Transferred",
"Translate": "Translate",
"Translated": "Translated",
"Translate_to": "Translate to",
"Translations": "Translations",
"Travel_and_Places": "Travel & Places",
"Trigger_removed": "Trigger removed",
Expand Down
Loading

0 comments on commit e5434d3

Please sign in to comment.