Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Auto-enable autotranslate #30370

Merged
merged 8 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/large-pandas-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": minor
---

New setting to automatically enable autotranslate when joining rooms
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { IUser } from '@rocket.chat/core-typings';
import { Subscriptions, Rooms } from '@rocket.chat/models';

import { callbacks } from '../../../../lib/callbacks';
import { getSubscriptionAutotranslateDefaultConfig } from '../../../../server/lib/getSubscriptionAutotranslateDefaultConfig';

export const addUserToDefaultChannels = async function (user: IUser, silenced?: boolean): Promise<void> {
await callbacks.run('beforeJoinDefaultChannels', user);
Expand All @@ -11,6 +12,7 @@ export const addUserToDefaultChannels = async function (user: IUser, silenced?:
}).toArray();
for await (const room of defaultRooms) {
if (!(await Subscriptions.findOneByRoomIdAndUserId(room._id, user._id, { projection: { _id: 1 } }))) {
const autoTranslateConfig = await getSubscriptionAutotranslateDefaultConfig(user);
// Add a subscription to this user
await Subscriptions.createWithRoomAndUser(room, user, {
ts: new Date(),
Expand All @@ -20,6 +22,7 @@ export const addUserToDefaultChannels = async function (user: IUser, silenced?:
userMentions: 1,
groupMentions: 0,
...(room.favorite && { f: true }),
...autoTranslateConfig,
});

// Insert user joined message
Expand Down
6 changes: 5 additions & 1 deletion apps/meteor/app/lib/server/functions/addUserToRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Meteor } from 'meteor/meteor';
import { RoomMemberActions } from '../../../../definition/IRoomTypeConfig';
import { AppEvents, Apps } from '../../../../ee/server/apps';
import { callbacks } from '../../../../lib/callbacks';
import { getSubscriptionAutotranslateDefaultConfig } from '../../../../server/lib/getSubscriptionAutotranslateDefaultConfig';
import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator';

export const addUserToRoom = async function (
Expand All @@ -24,7 +25,7 @@ export const addUserToRoom = async function (
});
}

const userToBeAdded = typeof user !== 'string' ? user : await Users.findOneByUsername(user.replace('@', ''));
const userToBeAdded = typeof user === 'string' ? await Users.findOneByUsername(user.replace('@', '')) : await Users.findOneById(user._id);
const roomDirectives = roomCoordinator.getRoomDirectives(room.t);

if (!userToBeAdded) {
Expand Down Expand Up @@ -70,13 +71,16 @@ export const addUserToRoom = async function (
await callbacks.run('beforeJoinRoom', userToBeAdded, room);
}

const autoTranslateConfig = await getSubscriptionAutotranslateDefaultConfig(userToBeAdded);

await Subscriptions.createWithRoomAndUser(room, userToBeAdded as IUser, {
ts: now,
open: true,
alert: true,
unread: 1,
userMentions: 1,
groupMentions: 0,
...autoTranslateConfig,
});

if (!userToBeAdded.username) {
Expand Down
6 changes: 5 additions & 1 deletion apps/meteor/app/lib/server/functions/createRoom.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable complexity */
import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions';
import { Message, Team } from '@rocket.chat/core-services';
import type { ICreateRoomParams, ISubscriptionExtraData } from '@rocket.chat/core-services';
Expand All @@ -8,6 +9,7 @@ import { Meteor } from 'meteor/meteor';
import { Apps } from '../../../../ee/server/apps/orchestrator';
import { callbacks } from '../../../../lib/callbacks';
import { beforeCreateRoomCallback } from '../../../../lib/callbacks/beforeCreateRoomCallback';
import { getSubscriptionAutotranslateDefaultConfig } from '../../../../server/lib/getSubscriptionAutotranslateDefaultConfig';
import { addUserRolesAsync } from '../../../../server/lib/roles/addUserRoles';
import { getValidRoomName } from '../../../utils/server/lib/getValidRoomName';
import { createDirectRoom } from './createDirectRoom';
Expand Down Expand Up @@ -178,7 +180,9 @@ export const createRoom = async <T extends RoomType>(
extra.ls = now;
}

await Subscriptions.createWithRoomAndUser(room, member, extra);
const autoTranslateConfig = await getSubscriptionAutotranslateDefaultConfig(member);

await Subscriptions.createWithRoomAndUser(room, member, { ...extra, ...autoTranslateConfig });
}
}

Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,8 @@
"AutoTranslate_DeepL": "DeepL",
"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_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_Microsoft": "Microsoft",
"AutoTranslate_Microsoft_API_Key": "Ocp-Apim-Subscription-Key",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { IUser } from '@rocket.chat/core-typings';
import { Settings } from '@rocket.chat/models';

export const getSubscriptionAutotranslateDefaultConfig = async (
user: IUser,
): Promise<
| {
autoTranslate: boolean;
autoTranslateLanguage: string;
}
| undefined
> => {
const [autoEnableSetting, languageSetting] = await Promise.all([
Settings.findOneById('AutoTranslate_AutoEnableOnJoinRoom'),
Settings.findOneById('Language'),
]);
const { language: userLanguage } = user.settings?.preferences || {};

if (!autoEnableSetting?.value) {
return;
}

if (!userLanguage || userLanguage === 'default' || languageSetting?.value === userLanguage) {
return;
}

return { autoTranslate: true, autoTranslateLanguage: userLanguage };
};
3 changes: 3 additions & 0 deletions apps/meteor/server/methods/addAllUserToRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Meteor } from 'meteor/meteor';
import { hasPermissionAsync } from '../../app/authorization/server/functions/hasPermission';
import { settings } from '../../app/settings/server';
import { callbacks } from '../../lib/callbacks';
import { getSubscriptionAutotranslateDefaultConfig } from '../lib/getSubscriptionAutotranslateDefaultConfig';

declare module '@rocket.chat/ui-contexts' {
// eslint-disable-next-line @typescript-eslint/naming-convention
Expand Down Expand Up @@ -55,13 +56,15 @@ Meteor.methods<ServerMethods>({
continue;
}
await callbacks.run('beforeJoinRoom', user, room);
const autoTranslateConfig = await getSubscriptionAutotranslateDefaultConfig(user);
await Subscriptions.createWithRoomAndUser(room, user, {
ts: now,
open: true,
alert: true,
unread: 1,
userMentions: 1,
groupMentions: 0,
...autoTranslateConfig,
});
await Message.saveSystemMessage('uj', rid, user.username || '', user, { ts: now });
await callbacks.run('afterJoinRoom', user, room);
Expand Down
8 changes: 8 additions & 0 deletions apps/meteor/server/settings/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ export const createMessageSettings = () =>
public: true,
});

await this.add('AutoTranslate_AutoEnableOnJoinRoom', false, {
type: 'boolean',
group: 'Message',
section: 'AutoTranslate',
public: true,
enableQuery: [{ _id: 'AutoTranslate_Enabled', value: true }],
});

await this.add('AutoTranslate_ServiceProvider', 'google-translate', {
type: 'select',
group: 'Message',
Expand Down
130 changes: 129 additions & 1 deletion apps/meteor/tests/end-to-end/api/00-autotranslate.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { expect } from 'chai';
import { before, describe, it } from 'mocha';
import { before, describe, after, it } from 'mocha';

import { getCredentials, api, request, credentials } from '../../data/api-data.js';
import { sendSimpleMessage } from '../../data/chat.helper';
import { updatePermission, updateSetting } from '../../data/permissions.helper';
import { createRoom } from '../../data/rooms.helper';
import { password } from '../../data/user';
import { createUser, login } from '../../data/users.helper.js';

describe('AutoTranslate', function () {
this.retries(0);
Expand Down Expand Up @@ -314,5 +317,130 @@ describe('AutoTranslate', function () {
.end(done);
});
});
describe('Autoenable setting', () => {
let userA;
let userB;
let credA;
let credB;
let channel;

const createChannel = async (members, cred) =>
(await createRoom({ type: 'c', members, name: `channel-test-${Date.now()}`, credentials: cred })).body.channel;

const setLanguagePref = async (language, cred) => {
await request
.post(api('users.setPreferences'))
.set(cred)
.send({ data: { language } })
.expect(200)
.expect('Content-Type', 'application/json')
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
};

const getSub = async (roomId, cred) =>
(
await request
.get(api('subscriptions.getOne'))
.set(cred)
.query({
roomId,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('subscription').and.to.be.an('object');
})
).body.subscription;

before(async () => {
await updateSetting('AutoTranslate_Enabled', true);
await updateSetting('AutoTranslate_AutoEnableOnJoinRoom', true);
await updateSetting('Language', 'pt-BR');

channel = await createChannel();
userA = await createUser();
userB = await createUser();

credA = await login(userA.username, password);
credB = await login(userB.username, password);

await setLanguagePref('en', credB);
});

after(async () => {
await updateSetting('AutoTranslate_AutoEnableOnJoinRoom', false);
await updateSetting('AutoTranslate_Enabled', false);
await updateSetting('Language', '');
});

it("should do nothing if the user hasn't changed his language preference", async () => {
const sub = await getSub(channel._id, credentials);
expect(sub).to.not.have.property('autoTranslate');
expect(sub).to.not.have.property('autoTranslateLanguage');
});

it("should do nothing if the user changed his language preference to be the same as the server's", async () => {
await setLanguagePref('pt-BR', credA);

const channel = await createChannel(undefined, credA);
const sub = await getSub(channel._id, credA);
expect(sub).to.not.have.property('autoTranslate');
expect(sub).to.not.have.property('autoTranslateLanguage');
});

it('should enable autotranslate with the correct language when creating a new room', async () => {
await setLanguagePref('en', credA);

const channel = await createChannel(undefined, credA);
const sub = await getSub(channel._id, credA);
expect(sub).to.have.property('autoTranslate');
expect(sub).to.have.property('autoTranslateLanguage').and.to.be.equal('en');
});

it('should enable autotranslate for all the members added to the room upon creation', async () => {
const channel = await createChannel([userA.username, userB.username]);
const subA = await getSub(channel._id, credA);
expect(subA).to.have.property('autoTranslate');
expect(subA).to.have.property('autoTranslateLanguage').and.to.be.equal('en');

const subB = await getSub(channel._id, credB);
expect(subB).to.have.property('autoTranslate');
expect(subB).to.have.property('autoTranslateLanguage').and.to.be.equal('en');
});

it('should enable autotranslate with the correct language when joining a room', async () => {
await request
.post(api('channels.join'))
.set(credA)
.send({
roomId: channel._id,
})
.expect('Content-Type', 'application/json')
.expect(200);

const sub = await getSub(channel._id, credA);
expect(sub).to.have.property('autoTranslate');
expect(sub).to.have.property('autoTranslateLanguage').and.to.be.equal('en');
});

it('should enable autotranslate with the correct language when added to a room', async () => {
await request
.post(api('channels.invite'))
.set(credentials)
.send({
roomId: channel._id,
userId: userB._id,
})
.expect('Content-Type', 'application/json')
.expect(200);

const sub = await getSub(channel._id, credB);
expect(sub).to.have.property('autoTranslate');
expect(sub).to.have.property('autoTranslateLanguage').and.to.be.equal('en');
});
});
});
});