* [MM-67253] Add support for DMs and GMs for autotranslations
* Address copilot comments
(cherry picked from commit 1db5cd456c)
Co-authored-by: Daniel Espino García <larkox@gmail.com>
This commit is contained in:
parent
f9d1bca05c
commit
c6caf7571f
9 changed files with 469 additions and 27 deletions
|
|
@ -159,4 +159,8 @@ export default {
|
|||
EDIT_BOOKMARK_PRIVATE_CHANNEL: 'edit_bookmark_private_channel',
|
||||
DELETE_BOOKMARK_PUBLIC_CHANNEL: 'delete_bookmark_public_channel',
|
||||
DELETE_BOOKMARK_PRIVATE_CHANNEL: 'delete_bookmark_private_channel',
|
||||
|
||||
// Autotranslations
|
||||
MANAGE_PUBLIC_CHANNEL_AUTO_TRANSLATION: 'manage_public_channel_auto_translation',
|
||||
MANAGE_PRIVATE_CHANNEL_AUTO_TRANSLATION: 'manage_private_channel_auto_translation',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ import {prepareChannels,
|
|||
observeIsChannelAutotranslated,
|
||||
} from './channel';
|
||||
import {queryRoles} from './role';
|
||||
import {getCurrentChannelId, observeConfigBooleanValue, observeCurrentChannelId, observeCurrentUserId} from './system';
|
||||
import {getCurrentChannelId, observeCurrentChannelId, observeCurrentUserId} from './system';
|
||||
import {observeTeammateNameDisplay} from './user';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
|
|
@ -79,7 +79,15 @@ import type ChannelInfoModel from '@typings/database/models/servers/channel_info
|
|||
import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership';
|
||||
|
||||
jest.mock('./role');
|
||||
jest.mock('./system');
|
||||
jest.mock('./system', () => {
|
||||
const actual = jest.requireActual<typeof import('./system')>('./system');
|
||||
return {
|
||||
...actual,
|
||||
getCurrentChannelId: jest.fn(),
|
||||
observeCurrentChannelId: jest.fn(),
|
||||
observeCurrentUserId: jest.fn(),
|
||||
};
|
||||
});
|
||||
jest.mock('./user');
|
||||
jest.mock('@utils/role');
|
||||
|
||||
|
|
@ -1669,7 +1677,14 @@ describe('queryMyChannelsByChannelIds and queryMyChannelsWithAutotranslation', (
|
|||
const channelId = 'ch_observe';
|
||||
|
||||
it('should emit true when EnableAutoTranslation is true and channel has autotranslation', async () => {
|
||||
jest.mocked(observeConfigBooleanValue).mockReturnValue(of$(true));
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({id: channelId, team_id: 'team1', autotranslation: true});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
|
||||
|
|
@ -1681,7 +1696,14 @@ describe('queryMyChannelsByChannelIds and queryMyChannelsWithAutotranslation', (
|
|||
});
|
||||
|
||||
it('should emit false when EnableAutoTranslation is false', async () => {
|
||||
jest.mocked(observeConfigBooleanValue).mockReturnValue(of$(false));
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'false'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({id: channelId, team_id: 'team1', autotranslation: true});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
|
||||
|
|
@ -1693,7 +1715,14 @@ describe('queryMyChannelsByChannelIds and queryMyChannelsWithAutotranslation', (
|
|||
});
|
||||
|
||||
it('should emit false when channel has autotranslation false', async () => {
|
||||
jest.mocked(observeConfigBooleanValue).mockReturnValue(of$(true));
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({id: channelId, team_id: 'team1', autotranslation: false});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
|
||||
|
|
@ -1705,20 +1734,80 @@ describe('queryMyChannelsByChannelIds and queryMyChannelsWithAutotranslation', (
|
|||
});
|
||||
|
||||
it('should emit false when channel is not found', async () => {
|
||||
jest.mocked(observeConfigBooleanValue).mockReturnValue(of$(true));
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeChannelAutotranslation(database, 'nonexistent');
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should emit false when channel is DM and RestrictDMAndGMAutotranslation is true', async () => {
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'true'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({
|
||||
id: channelId,
|
||||
type: General.DM_CHANNEL,
|
||||
autotranslation: true,
|
||||
});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeChannelAutotranslation(database, channelId);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should emit true when channel is DM and RestrictDMAndGMAutotranslation is false', async () => {
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({
|
||||
id: channelId,
|
||||
type: General.DM_CHANNEL,
|
||||
autotranslation: true,
|
||||
});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeChannelAutotranslation(database, channelId);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('observeIsChannelAutotranslated', () => {
|
||||
const channelId = 'ch_is_autotranslated';
|
||||
|
||||
it('should emit true when config and channel has autotranslation true and myChannel has autotranslation disabled false', async () => {
|
||||
jest.mocked(observeConfigBooleanValue).mockReturnValue(of$(true));
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({id: channelId, team_id: 'team1', autotranslation: true});
|
||||
const myChannel = TestHelper.fakeChannelMember({id: channelId, channel_id: channelId, autotranslation_disabled: false});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
|
|
@ -1732,7 +1821,14 @@ describe('queryMyChannelsByChannelIds and queryMyChannelsWithAutotranslation', (
|
|||
});
|
||||
|
||||
it('should emit false when channel autotranslation is false', async () => {
|
||||
jest.mocked(observeConfigBooleanValue).mockReturnValue(of$(true));
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({id: channelId, team_id: 'team1', autotranslation: false});
|
||||
const myChannel = TestHelper.fakeChannelMember({id: channelId, channel_id: channelId, autotranslation_disabled: false});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
|
|
@ -1746,7 +1842,14 @@ describe('queryMyChannelsByChannelIds and queryMyChannelsWithAutotranslation', (
|
|||
});
|
||||
|
||||
it('should emit false when myChannel autotranslation disabled is true', async () => {
|
||||
jest.mocked(observeConfigBooleanValue).mockReturnValue(of$(true));
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({id: channelId, team_id: 'team1', autotranslation: true});
|
||||
const myChannel = TestHelper.fakeChannelMember({id: channelId, channel_id: channelId, autotranslation_disabled: true});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
|
|
@ -1758,5 +1861,55 @@ describe('queryMyChannelsByChannelIds and queryMyChannelsWithAutotranslation', (
|
|||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should emit false when channel is DM and RestrictDMAndGMAutotranslation is true', async () => {
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'true'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({
|
||||
id: channelId,
|
||||
type: General.DM_CHANNEL,
|
||||
autotranslation: true,
|
||||
});
|
||||
const myChannel = TestHelper.fakeChannelMember({id: channelId, channel_id: channelId, autotranslation_disabled: false});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
await operator.handleMyChannel({channels: [channel], myChannels: [myChannel], prepareRecordsOnly: false});
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeIsChannelAutotranslated(database, channelId);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should emit true when channel is DM and RestrictDMAndGMAutotranslation is false', async () => {
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
const channel = TestHelper.fakeChannel({
|
||||
id: channelId,
|
||||
type: General.DM_CHANNEL,
|
||||
autotranslation: true,
|
||||
});
|
||||
const myChannel = TestHelper.fakeChannelMember({id: channelId, channel_id: channelId, autotranslation_disabled: false});
|
||||
await operator.handleChannel({channels: [channel], prepareRecordsOnly: false});
|
||||
await operator.handleMyChannel({channels: [channel], myChannels: [myChannel], prepareRecordsOnly: false});
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeIsChannelAutotranslated(database, channelId);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {General, Permissions} from '@constants';
|
|||
import {MM_TABLES} from '@constants/database';
|
||||
import {sanitizeLikeString} from '@helpers/database';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
import {isDefaultChannel} from '@utils/channel';
|
||||
import {isDefaultChannel, isDMorGM} from '@utils/channel';
|
||||
import {hasPermission} from '@utils/role';
|
||||
import {isSystemAdmin} from '@utils/user';
|
||||
|
||||
|
|
@ -287,9 +287,24 @@ export const observeMyChannelRoles = (database: Database, channelId: string) =>
|
|||
|
||||
export const observeChannelAutotranslation = (database: Database, channelId: string) => {
|
||||
const enableAutoTranslation = observeConfigBooleanValue(database, 'EnableAutoTranslation');
|
||||
const restrictDMAndGMAutotranslation = observeConfigBooleanValue(database, 'RestrictDMAndGMAutotranslation');
|
||||
const channel = observeChannel(database, channelId);
|
||||
return combineLatest([enableAutoTranslation, channel]).pipe(
|
||||
switchMap(([et, c]) => of$(Boolean(et && c?.autotranslation))),
|
||||
return combineLatest([enableAutoTranslation, restrictDMAndGMAutotranslation, channel]).pipe(
|
||||
map$(([et, r, c]) => {
|
||||
if (!et) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!c?.autotranslation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDMorGM(c) && r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
};
|
||||
|
|
@ -798,7 +813,26 @@ export const observeIsReadOnlyChannel = (database: Database, channelId: string)
|
|||
|
||||
export const observeIsChannelAutotranslated = (database: Database, channelId: string) => {
|
||||
const enableAutoTranslation = observeConfigBooleanValue(database, 'EnableAutoTranslation');
|
||||
const restrictDMAndGMAutotranslation = observeConfigBooleanValue(database, 'RestrictDMAndGMAutotranslation');
|
||||
const channel = observeChannel(database, channelId);
|
||||
const myChannel = observeMyChannel(database, channelId);
|
||||
return combineLatest([enableAutoTranslation, channel, myChannel]).pipe(map(([et, c, mc]) => Boolean(et && c?.autotranslation && !mc?.autotranslationDisabled)));
|
||||
return combineLatest([enableAutoTranslation, restrictDMAndGMAutotranslation, channel, myChannel]).pipe(map(([et, r, c, mc]) => {
|
||||
if (!et) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!c?.autotranslation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mc?.autotranslationDisabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDMorGM(c) && r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
observePermissionForPost,
|
||||
observeCanManageChannelMembers,
|
||||
observeCanManageChannelSettings,
|
||||
observeCanManageChannelAutotranslations,
|
||||
} from './role';
|
||||
|
||||
import type ServerDataOperator from '@database/operator/server_data_operator';
|
||||
|
|
@ -427,4 +428,221 @@ describe('Role Queries', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('observeCanManageChannelAutotranslations', () => {
|
||||
it('should emit false when EnableAutoTranslation is false', async () => {
|
||||
const mockUser = TestHelper.fakeUserModel({id: 'user1', roles: 'system_user'});
|
||||
|
||||
await Promise.all([
|
||||
operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'false'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
operator.handleChannel({
|
||||
channels: [TestHelper.fakeChannel({
|
||||
id: 'channel1',
|
||||
type: General.OPEN_CHANNEL,
|
||||
delete_at: 0,
|
||||
})],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeCanManageChannelAutotranslations(database, 'channel1', mockUser);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should emit false when channel is not found', async () => {
|
||||
const mockUser = TestHelper.fakeUserModel({id: 'user1', roles: 'system_user'});
|
||||
|
||||
await operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeCanManageChannelAutotranslations(database, 'nonexistent', mockUser);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should emit false when channel is deleted', async () => {
|
||||
const mockUser = TestHelper.fakeUserModel({id: 'user1', roles: 'system_user'});
|
||||
|
||||
await Promise.all([
|
||||
operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
operator.handleChannel({
|
||||
channels: [TestHelper.fakeChannel({
|
||||
id: 'channel1',
|
||||
type: General.OPEN_CHANNEL,
|
||||
delete_at: 123,
|
||||
})],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeCanManageChannelAutotranslations(database, 'channel1', mockUser);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should emit false when channel is DM and RestrictDMAndGMAutotranslation is true', async () => {
|
||||
const mockUser = TestHelper.fakeUserModel({id: 'user1', roles: 'system_user'});
|
||||
|
||||
await Promise.all([
|
||||
operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'true'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
operator.handleChannel({
|
||||
channels: [TestHelper.fakeChannel({
|
||||
id: 'channel1',
|
||||
type: General.DM_CHANNEL,
|
||||
delete_at: 0,
|
||||
})],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeCanManageChannelAutotranslations(database, 'channel1', mockUser);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should emit true when channel is DM and RestrictDMAndGMAutotranslation is false', async () => {
|
||||
const mockUser = TestHelper.fakeUserModel({id: 'user1', roles: 'system_user'});
|
||||
|
||||
await Promise.all([
|
||||
operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
operator.handleChannel({
|
||||
channels: [TestHelper.fakeChannel({
|
||||
id: 'channel1',
|
||||
type: General.DM_CHANNEL,
|
||||
delete_at: 0,
|
||||
})],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeCanManageChannelAutotranslations(database, 'channel1', mockUser);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('should emit true for open channel when user has MANAGE_PUBLIC_CHANNEL_AUTO_TRANSLATION', async () => {
|
||||
const mockUser = TestHelper.fakeUserModel({
|
||||
id: 'user1',
|
||||
roles: 'channel_admin',
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
operator.handleChannel({
|
||||
channels: [TestHelper.fakeChannel({
|
||||
id: 'channel1',
|
||||
type: General.OPEN_CHANNEL,
|
||||
delete_at: 0,
|
||||
})],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
operator.handleRole({
|
||||
roles: [{
|
||||
id: 'channel_admin',
|
||||
name: 'channel_admin',
|
||||
permissions: [Permissions.MANAGE_PUBLIC_CHANNEL_AUTO_TRANSLATION],
|
||||
}],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeCanManageChannelAutotranslations(database, 'channel1', mockUser);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('should emit true for private channel when user has MANAGE_PRIVATE_CHANNEL_AUTO_TRANSLATION', async () => {
|
||||
const mockUser = TestHelper.fakeUserModel({
|
||||
id: 'user1',
|
||||
roles: 'channel_admin',
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
operator.handleConfigs({
|
||||
configs: [
|
||||
{id: 'EnableAutoTranslation', value: 'true'},
|
||||
{id: 'RestrictDMAndGMAutotranslation', value: 'false'},
|
||||
],
|
||||
configsToDelete: [],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
operator.handleChannel({
|
||||
channels: [TestHelper.fakeChannel({
|
||||
id: 'channel1',
|
||||
type: General.PRIVATE_CHANNEL,
|
||||
delete_at: 0,
|
||||
})],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
operator.handleRole({
|
||||
roles: [{
|
||||
id: 'channel_admin',
|
||||
name: 'channel_admin',
|
||||
permissions: [Permissions.MANAGE_PRIVATE_CHANNEL_AUTO_TRANSLATION],
|
||||
}],
|
||||
prepareRecordsOnly: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
const subscriptionNext = jest.fn();
|
||||
const result = observeCanManageChannelAutotranslations(database, 'channel1', mockUser);
|
||||
result.subscribe({next: subscriptionNext});
|
||||
|
||||
expect(subscriptionNext).toHaveBeenCalledWith(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {isDefaultChannel, isDMorGM} from '@utils/channel';
|
|||
import {hasPermission} from '@utils/role';
|
||||
|
||||
import {observeChannel, observeMyChannelRoles} from './channel';
|
||||
import {observeConfigBooleanValue} from './system';
|
||||
import {observeMyTeam, observeMyTeamRoles} from './team';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
|
|
@ -115,3 +116,28 @@ export function observeCanManageChannelSettings(database: Database, channelId: s
|
|||
distinctUntilChanged(),
|
||||
);
|
||||
}
|
||||
|
||||
export function observeCanManageChannelAutotranslations(database: Database, channelId: string, user: UserModel) {
|
||||
const featureEnabled = observeConfigBooleanValue(database, 'EnableAutoTranslation');
|
||||
const channel = observeChannel(database, channelId);
|
||||
const restrictDMAndGMAutotranslation = observeConfigBooleanValue(database, 'RestrictDMAndGMAutotranslation');
|
||||
return combineLatest([featureEnabled, channel, restrictDMAndGMAutotranslation]).pipe(
|
||||
switchMap(([enabled, c, isDmGmRestricted]) => {
|
||||
if (!enabled) {
|
||||
return of$(false);
|
||||
}
|
||||
|
||||
if (!c || c.deleteAt !== 0) {
|
||||
return of$(false);
|
||||
}
|
||||
|
||||
if (isDMorGM(c)) {
|
||||
return of$(!isDmGmRestricted);
|
||||
}
|
||||
|
||||
const permission = c.type === General.OPEN_CHANNEL ? Permissions.MANAGE_PUBLIC_CHANNEL_AUTO_TRANSLATION : Permissions.MANAGE_PRIVATE_CHANNEL_AUTO_TRANSLATION;
|
||||
return observePermissionForChannel(database, c, user, permission, false);
|
||||
}),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {withServerUrl} from '@context/server';
|
|||
import {observeIsPlaybooksEnabled} from '@playbooks/database/queries/version';
|
||||
import {observeChannelAutotranslation, observeCurrentChannel} from '@queries/servers/channel';
|
||||
import {observeCanAddBookmarks} from '@queries/servers/channel_bookmark';
|
||||
import {observeCanManageChannelMembers, observeCanManageChannelSettings, observePermissionForChannel, observePermissionForTeam} from '@queries/servers/role';
|
||||
import {observeCanManageChannelAutotranslations, observeCanManageChannelMembers, observeCanManageChannelSettings, observePermissionForChannel, observePermissionForTeam} from '@queries/servers/role';
|
||||
import {
|
||||
observeConfigBooleanValue,
|
||||
observeConfigValue,
|
||||
|
|
@ -137,7 +137,10 @@ const observeHasChannelSettingsActions = (
|
|||
switchMap((version) => of$(isMinimumServerVersion(version || '', 9, 1))),
|
||||
);
|
||||
|
||||
const isChannelAutotranslateEnabled = observeConfigBooleanValue(database, 'EnableAutoTranslation');
|
||||
const canManageChannelAutotranslations = combineLatest([channelId, currentUser]).pipe(
|
||||
switchMap(([cId, u]) => (u ? observeCanManageChannelAutotranslations(database, cId, u) : of$(false))),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
|
||||
const team = observeCurrentTeam(database);
|
||||
const isArchived = channel.pipe(switchMap((c) => of$((c?.deleteAt || 0) > 0)));
|
||||
|
|
@ -206,16 +209,16 @@ const observeHasChannelSettingsActions = (
|
|||
canUnarchive,
|
||||
canEnableDisableCalls,
|
||||
convertGMOptionAvailable,
|
||||
isChannelAutotranslateEnabled,
|
||||
canManageChannelAutotranslations,
|
||||
]).pipe(
|
||||
switchMap(([manageSettings, convert, archive, unarchive, enableCalls, convertGM, autotranslateEnabled]) => {
|
||||
switchMap(([manageSettings, convert, archive, unarchive, enableCalls, convertGM, manageAutotranslations]) => {
|
||||
return of$(
|
||||
manageSettings || // Channel info or Channel autotranslations
|
||||
convert || // Convert to private
|
||||
archive || unarchive || // Archive channel
|
||||
enableCalls || // Enable/Disable calls
|
||||
convertGM || // Convert GM to channel
|
||||
(manageSettings && autotranslateEnabled), // Channel autotranslations
|
||||
manageAutotranslations, // Channel autotranslations
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ type Props = {
|
|||
convertGMOptionAvailable: boolean;
|
||||
displayName: string;
|
||||
isCallsEnabledInChannel: boolean;
|
||||
isChannelAutotranslateEnabled: boolean;
|
||||
canManageAutotranslations: boolean;
|
||||
type?: ChannelType;
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ const ChannelSettings = ({
|
|||
convertGMOptionAvailable,
|
||||
displayName,
|
||||
isCallsEnabledInChannel,
|
||||
isChannelAutotranslateEnabled,
|
||||
canManageAutotranslations,
|
||||
type,
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
|
|
@ -116,7 +116,7 @@ const ChannelSettings = ({
|
|||
{convertGMOptionAvailable &&
|
||||
<ConvertToChannelLabel channelId={channelId}/>
|
||||
}
|
||||
{canManageSettings && isChannelAutotranslateEnabled &&
|
||||
{canManageAutotranslations &&
|
||||
<ChannelAutotranslation channelId={channelId}/>
|
||||
}
|
||||
{(canArchive || canUnarchive) &&
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@ import {observeCallsConfig} from '@calls/state';
|
|||
import {General, Permissions} from '@constants';
|
||||
import {withServerUrl} from '@context/server';
|
||||
import {observeChannel} from '@queries/servers/channel';
|
||||
import {observePermissionForChannel, observePermissionForTeam, observeCanManageChannelSettings} from '@queries/servers/role';
|
||||
import {observePermissionForChannel, observePermissionForTeam, observeCanManageChannelSettings, observeCanManageChannelAutotranslations} from '@queries/servers/role';
|
||||
import {
|
||||
observeConfigBooleanValue,
|
||||
observeConfigValue,
|
||||
observeCurrentTeamId,
|
||||
} from '@queries/servers/system';
|
||||
|
|
@ -175,7 +174,9 @@ const enhanced = withObservables(['channelId'], ({channelId, serverUrl, database
|
|||
);
|
||||
|
||||
// Channel autotranslation observable
|
||||
const isChannelAutotranslateEnabled = observeConfigBooleanValue(database, 'EnableAutoTranslation');
|
||||
const canManageAutotranslations = currentUser.pipe(
|
||||
switchMap((u) => (u ? observeCanManageChannelAutotranslations(database, channelId, u) : of$(false))),
|
||||
);
|
||||
|
||||
return {
|
||||
canArchive,
|
||||
|
|
@ -186,7 +187,7 @@ const enhanced = withObservables(['channelId'], ({channelId, serverUrl, database
|
|||
convertGMOptionAvailable,
|
||||
displayName: channel.pipe(switchMap((c) => of$(c?.displayName || ''))),
|
||||
isCallsEnabledInChannel,
|
||||
isChannelAutotranslateEnabled,
|
||||
canManageAutotranslations,
|
||||
isGuestUser,
|
||||
type,
|
||||
};
|
||||
|
|
|
|||
7
types/api/config.d.ts
vendored
7
types/api/config.d.ts
vendored
|
|
@ -13,7 +13,6 @@ interface ClientConfig {
|
|||
AndroidMinVersion: string;
|
||||
AppDownloadLink: string;
|
||||
AsymmetricSigningPublicKey: string;
|
||||
AutoTranslationLanguages: string;
|
||||
AvailableLocales: string;
|
||||
BannerColor: string;
|
||||
BannerText: string;
|
||||
|
|
@ -48,7 +47,6 @@ interface ClientConfig {
|
|||
EmailLoginButtonTextColor: string;
|
||||
EmailNotificationContentsType: string;
|
||||
EnableBanner: string;
|
||||
EnableAutoTranslation: string;
|
||||
EnableBotAccountCreation: string;
|
||||
EnableBurnOnRead: string;
|
||||
EnableChannelViewedMessages: string;
|
||||
|
|
@ -218,6 +216,11 @@ interface ClientConfig {
|
|||
WebsocketSecurePort: string;
|
||||
WebsocketURL: string;
|
||||
BurnOnReadDurationSeconds: string;
|
||||
|
||||
// Autotranslations
|
||||
AutoTranslationLanguages: string;
|
||||
EnableAutoTranslation: string;
|
||||
RestrictDMAndGMAutotranslation: string;
|
||||
}
|
||||
|
||||
type SecurityClientConfig = Pick<ClientConfig, 'MobileEnableBiometrics' | 'MobileJailbreakProtection' | 'MobilePreventScreenCapture' | 'SiteName'>
|
||||
|
|
|
|||
Loading…
Reference in a new issue