diff --git a/app/components/files/index.ts b/app/components/files/index.ts index 2f034ab4b7..5945f9b62f 100644 --- a/app/components/files/index.ts +++ b/app/components/files/index.ts @@ -3,11 +3,11 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; -import {combineLatest, of as of$, from as from$} from 'rxjs'; -import {map, switchMap} from 'rxjs/operators'; +import {of as of$, from as from$} from 'rxjs'; +import {switchMap} from 'rxjs/operators'; import {queryFilesForPost} from '@queries/servers/file'; -import {observeConfigBooleanValue, observeLicense} from '@queries/servers/system'; +import {observeCanDownloadFiles, observeConfigBooleanValue} from '@queries/servers/system'; import {fileExists} from '@utils/file'; import Files from './files'; @@ -37,23 +37,14 @@ const filesLocalPathValidation = async (files: FileModel[], authorId: string) => }; const enhance = withObservables(['post'], ({database, post}: EnhanceProps) => { - const enableMobileFileDownload = observeConfigBooleanValue(database, 'EnableMobileFileDownload'); const publicLinkEnabled = observeConfigBooleanValue(database, 'EnablePublicLink'); - const complianceDisabled = observeLicense(database).pipe( - switchMap((lcs) => of$(lcs?.IsLicensed === 'false' || lcs?.Compliance === 'false')), - ); - - const canDownloadFiles = combineLatest([enableMobileFileDownload, complianceDisabled]).pipe( - map(([download, compliance]) => compliance || download), - ); - const filesInfo = queryFilesForPost(database, post.id).observeWithColumns(['local_path']).pipe( switchMap((fs) => from$(filesLocalPathValidation(fs, post.userId))), ); return { - canDownloadFiles, + canDownloadFiles: observeCanDownloadFiles(database), postId: of$(post.id), publicLinkEnabled, filesInfo, diff --git a/app/queries/servers/system.test.ts b/app/queries/servers/system.test.ts new file mode 100644 index 0000000000..63ff693b3d --- /dev/null +++ b/app/queries/servers/system.test.ts @@ -0,0 +1,254 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {SYSTEM_IDENTIFIERS} from '@constants/database'; +import DatabaseManager from '@database/manager'; + +import {observeCanDownloadFiles, observeCanUploadFiles} from './system'; + +import type ServerDataOperator from '@database/operator/server_data_operator'; +import type {Database} from '@nozbe/watermelondb'; + +describe('observeCanUploadFiles', () => { + const serverUrl = 'baseHandler.test.com'; + let database: Database; + let operator: ServerDataOperator; + beforeEach(async () => { + await DatabaseManager.init([serverUrl]); + const serverDatabaseAndOperator = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + database = serverDatabaseAndOperator.database; + operator = serverDatabaseAndOperator.operator; + }); + afterEach(async () => { + await DatabaseManager.destroyServerDatabase(serverUrl); + }); + + it('should return true if no file attachment config value', (done) => { + operator.handleConfigs({configs: [{id: 'EnableMobileFileUpload', value: 'true'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + observeCanUploadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }, 1500); + + it('should return false if file attachment config value is false', (done) => { + operator.handleConfigs({configs: [{id: 'EnableFileAttachments', value: 'false'}, {id: 'EnableMobileFileUpload', value: 'true'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + observeCanUploadFiles(database).subscribe((data) => { + if (data === false) { + done(); + } else { + done.fail(); + } + }); + }); + }, 1500); + + it('should return true if file attachment config value is true and there is no license', (done) => { + operator.handleConfigs({configs: [{id: 'EnableFileAttachments', value: 'true'}, {id: 'EnableMobileFileUpload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + observeCanUploadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }, 1500); + + it('should return true if file attachment config value is true and server is not licensed', (done) => { + operator.handleConfigs({configs: [{id: 'EnableFileAttachments', value: 'true'}, {id: 'EnableMobileFileUpload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {isLicensed: false}}], prepareRecordsOnly: false}).then(() => { + observeCanUploadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); + + it('should return true if file attachment config value is true and server is licensed, but no compliance is set', (done) => { + operator.handleConfigs({configs: [{id: 'EnableFileAttachments', value: 'true'}, {id: 'EnableMobileFileUpload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true'}}], prepareRecordsOnly: false}).then(() => { + observeCanUploadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); + + it('should return true if file attachment config value is true and server is licensed, but compliance is set to false', (done) => { + operator.handleConfigs({configs: [{id: 'EnableFileAttachments', value: 'true'}, {id: 'EnableMobileFileUpload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true', Compliance: 'false'}}], prepareRecordsOnly: false}).then(() => { + observeCanUploadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); + + it('should return true if file attachment config value is true and server is licensed and compliance is set to true, but EnableMobileFileUpload is not set', (done) => { + operator.handleConfigs({configs: [{id: 'EnableFileAttachments', value: 'true'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true', Compliance: 'true'}}], prepareRecordsOnly: false}).then(() => { + observeCanUploadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); + + it('should return false if file attachment config value is true and server is licensed and compliance is set to true, but EnableMobileFileUpload is set to false', (done) => { + operator.handleConfigs({configs: [{id: 'EnableFileAttachments', value: 'true'}, {id: 'EnableMobileFileUpload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true', Compliance: 'true'}}], prepareRecordsOnly: false}).then(() => { + observeCanUploadFiles(database).subscribe((data) => { + if (data === false) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); + + it('should return true if file attachment config value is true and server is licensed and compliance is set to true, but EnableMobileFileUpload is set to true', (done) => { + operator.handleConfigs({configs: [{id: 'EnableFileAttachments', value: 'true'}, {id: 'EnableMobileFileUpload', value: 'true'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true', Compliance: 'true'}}], prepareRecordsOnly: false}).then(() => { + observeCanUploadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); +}); + +describe('observeCanDownloadFiles', () => { + const serverUrl = 'baseHandler.test.com'; + let database: Database; + let operator: ServerDataOperator; + beforeEach(async () => { + await DatabaseManager.init([serverUrl]); + const serverDatabaseAndOperator = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + database = serverDatabaseAndOperator.database; + operator = serverDatabaseAndOperator.operator; + }); + afterEach(async () => { + await DatabaseManager.destroyServerDatabase(serverUrl); + }); + + it('should return true if there is no license', (done) => { + operator.handleConfigs({configs: [{id: 'EnableMobileFileDownload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + observeCanDownloadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }, 1500); + + it('should return true if server is not licensed', (done) => { + operator.handleConfigs({configs: [{id: 'EnableMobileFileDownload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {isLicensed: false}}], prepareRecordsOnly: false}).then(() => { + observeCanDownloadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); + + it('should return true if server is licensed, but no compliance is set', (done) => { + operator.handleConfigs({configs: [{id: 'EnableMobileFileDownload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true'}}], prepareRecordsOnly: false}).then(() => { + observeCanDownloadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); + + it('should return true if server is licensed, but compliance is set to false', (done) => { + operator.handleConfigs({configs: [{id: 'EnableMobileFileDownload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true', Compliance: 'false'}}], prepareRecordsOnly: false}).then(() => { + observeCanDownloadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); + + it('should return true if is licensed and compliance is set to true, but EnableMobileFileDownload is not set', (done) => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true', Compliance: 'true'}}], prepareRecordsOnly: false}).then(() => { + observeCanDownloadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }, 1500); + + it('should return false if server is licensed and compliance is set to true, but EnableMobileFileDownload is set to false', (done) => { + operator.handleConfigs({configs: [{id: 'EnableMobileFileDownload', value: 'false'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true', Compliance: 'true'}}], prepareRecordsOnly: false}).then(() => { + observeCanDownloadFiles(database).subscribe((data) => { + if (data === false) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); + + it('should return true if server is licensed and compliance is set to true, but EnableMobileFileDownload is set to true', (done) => { + operator.handleConfigs({configs: [{id: 'EnableMobileFileDownload', value: 'true'}], prepareRecordsOnly: false, configsToDelete: []}).then(() => { + operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.LICENSE, value: {IsLicensed: 'true', Compliance: 'true'}}], prepareRecordsOnly: false}).then(() => { + observeCanDownloadFiles(database).subscribe((data) => { + if (data === true) { + done(); + } else { + done.fail(); + } + }); + }); + }); + }, 1500); +}); diff --git a/app/queries/servers/system.ts b/app/queries/servers/system.ts index e17bc40cce..76cfa9ae79 100644 --- a/app/queries/servers/system.ts +++ b/app/queries/servers/system.ts @@ -226,9 +226,9 @@ export const observeIsCustomStatusExpirySupported = (database: Database) => { ); }; -export const observeConfigBooleanValue = (database: Database, key: keyof ClientConfig) => { +export const observeConfigBooleanValue = (database: Database, key: keyof ClientConfig, defaultValue = false) => { return observeConfigValue(database, key).pipe( - switchMap((v) => of$(v === 'true')), + switchMap((v) => of$(v ? v === 'true' : defaultValue)), distinctUntilChanged(), ); }; @@ -511,16 +511,24 @@ export const observeLastDismissedAnnouncement = (database: Database) => { }; export const observeCanUploadFiles = (database: Database) => { - const enableFileAttachments = observeConfigBooleanValue(database, 'EnableFileAttachments'); - const enableMobileFileUpload = observeConfigBooleanValue(database, 'EnableMobileFileUpload'); + const enableFileAttachments = observeConfigBooleanValue(database, 'EnableFileAttachments', true); + const enableMobileFileUpload = observeConfigBooleanValue(database, 'EnableMobileFileUpload', true); const license = observeLicense(database); return combineLatest([enableFileAttachments, enableMobileFileUpload, license]).pipe( switchMap(([efa, emfu, l]) => of$( - efa || - (l?.IsLicensed !== 'true' && l?.Compliance !== 'true' && emfu), - ), - ), + efa && + (l?.IsLicensed !== 'true' || l?.Compliance !== 'true' || emfu), + )), + ); +}; + +export const observeCanDownloadFiles = (database: Database) => { + const enableMobileFileDownload = observeConfigBooleanValue(database, 'EnableMobileFileDownload', true); + const license = observeLicense(database); + + return combineLatest([enableMobileFileDownload, license]).pipe( + switchMap(([emfd, l]) => of$((l?.IsLicensed !== 'true' || l?.Compliance !== 'true' || emfd))), ); }; diff --git a/app/screens/gallery/document_renderer/index.ts b/app/screens/gallery/document_renderer/index.ts index df8ffefa02..e54326142b 100644 --- a/app/screens/gallery/document_renderer/index.ts +++ b/app/screens/gallery/document_renderer/index.ts @@ -3,26 +3,16 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; -import {combineLatest, of as of$} from 'rxjs'; -import {switchMap} from 'rxjs/operators'; -import {observeConfigBooleanValue, observeLicense} from '@queries/servers/system'; +import {observeCanDownloadFiles} from '@queries/servers/system'; import DocumentRenderer from './document_renderer'; import type {WithDatabaseArgs} from '@typings/database/database'; const enhanced = withObservables([], ({database}: WithDatabaseArgs) => { - const enableMobileFileDownload = observeConfigBooleanValue(database, 'EnableMobileFileDownload'); - const complianceDisabled = observeLicense(database).pipe( - switchMap((lcs) => of$(lcs?.IsLicensed === 'false' || lcs?.Compliance === 'false')), - ); - const canDownloadFiles = combineLatest([enableMobileFileDownload, complianceDisabled]).pipe( - switchMap(([download, compliance]) => of$(compliance || download)), - ); - return { - canDownloadFiles, + canDownloadFiles: observeCanDownloadFiles(database), }; }); diff --git a/app/screens/gallery/footer/index.ts b/app/screens/gallery/footer/index.ts index a7561289a8..42f86358f2 100644 --- a/app/screens/gallery/footer/index.ts +++ b/app/screens/gallery/footer/index.ts @@ -9,7 +9,7 @@ import {switchMap} from 'rxjs/operators'; import {General} from '@constants'; import {observeChannel} from '@queries/servers/channel'; import {observePost} from '@queries/servers/post'; -import {observeConfigBooleanValue, observeCurrentChannelId, observeCurrentUserId, observeLicense} from '@queries/servers/system'; +import {observeCanDownloadFiles, observeConfigBooleanValue, observeCurrentChannelId, observeCurrentUserId} from '@queries/servers/system'; import {observeTeammateNameDisplay, observeUser} from '@queries/servers/user'; import Footer from './footer'; @@ -27,7 +27,6 @@ const enhanced = withObservables(['item'], ({database, item}: FooterProps) => { const currentChannelId = observeCurrentChannelId(database); const currentUserId = observeCurrentUserId(database); - const license = observeLicense(database); const teammateNameDisplay = observeTeammateNameDisplay(database); const author = post.pipe( @@ -50,17 +49,12 @@ const enhanced = withObservables(['item'], ({database, item}: FooterProps) => { const enablePostUsernameOverride = observeConfigBooleanValue(database, 'EnablePostUsernameOverride'); const enablePostIconOverride = observeConfigBooleanValue(database, 'EnablePostIconOverride'); const enablePublicLink = observeConfigBooleanValue(database, 'EnablePublicLink'); - const enableMobileFileDownload = observeConfigBooleanValue(database, 'EnableMobileFileDownload'); - const complianceDisabled = license.pipe(switchMap((l) => of$(l?.IsLicensed === 'false' || l?.Compliance === 'false'))); - const canDownloadFiles = combineLatest([enableMobileFileDownload, complianceDisabled]).pipe( - switchMap(([download, compliance]) => of$(compliance || download)), - ); const channelName = channel.pipe(switchMap((c: ChannelModel) => of$(c.displayName))); const isDirectChannel = channel.pipe(switchMap((c: ChannelModel) => of$(c.type === General.DM_CHANNEL))); return { author, - canDownloadFiles, + canDownloadFiles: observeCanDownloadFiles(database), channelName, currentUserId, enablePostIconOverride, diff --git a/app/screens/home/search/results/file_options/option_menus/index.tsx b/app/screens/home/search/results/file_options/option_menus/index.tsx index 117a2b9b04..5412631b6f 100644 --- a/app/screens/home/search/results/file_options/option_menus/index.tsx +++ b/app/screens/home/search/results/file_options/option_menus/index.tsx @@ -4,28 +4,16 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; import compose from 'lodash/fp/compose'; -import {combineLatest, of as of$} from 'rxjs'; -import {map, switchMap} from 'rxjs/operators'; -import {observeLicense, observeConfigBooleanValue} from '@queries/servers/system'; +import {observeConfigBooleanValue, observeCanDownloadFiles} from '@queries/servers/system'; import OptionMenus from './option_menus'; import type {WithDatabaseArgs} from '@typings/database/database'; const enhance = withObservables([], ({database}: WithDatabaseArgs) => { - const enableMobileFileDownload = observeConfigBooleanValue(database, 'EnableMobileFileDownload'); - - const complianceDisabled = observeLicense(database).pipe( - switchMap((lcs) => of$(lcs?.IsLicensed === 'false' || lcs?.Compliance === 'false')), - ); - - const canDownloadFiles = combineLatest([enableMobileFileDownload, complianceDisabled]).pipe( - map(([download, compliance]) => compliance || download), - ); - return { - canDownloadFiles, + canDownloadFiles: observeCanDownloadFiles(database), enablePublicLink: observeConfigBooleanValue(database, 'EnablePublicLink'), }; }); diff --git a/app/screens/home/search/results/index.tsx b/app/screens/home/search/results/index.tsx index 2e0a9167c2..39d3eccb69 100644 --- a/app/screens/home/search/results/index.tsx +++ b/app/screens/home/search/results/index.tsx @@ -4,12 +4,12 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; import compose from 'lodash/fp/compose'; -import {combineLatest, of as of$} from 'rxjs'; -import {map, switchMap} from 'rxjs/operators'; +import {of as of$} from 'rxjs'; +import {switchMap} from 'rxjs/operators'; import {queryChannelsById} from '@queries/servers/channel'; import {queryAllCustomEmojis} from '@queries/servers/custom_emoji'; -import {observeLicense, observeConfigBooleanValue} from '@queries/servers/system'; +import {observeConfigBooleanValue, observeCanDownloadFiles} from '@queries/servers/system'; import {observeCurrentUser} from '@queries/servers/user'; import {mapCustomEmojiNames} from '@utils/emoji/helpers'; import {getTimezone} from '@utils/user'; @@ -26,16 +26,6 @@ const enhance = withObservables(['fileChannelIds'], ({database, fileChannelIds}: const fileChannels = queryChannelsById(database, fileChannelIds).observeWithColumns(['displayName']); const currentUser = observeCurrentUser(database); - const enableMobileFileDownload = observeConfigBooleanValue(database, 'EnableMobileFileDownload'); - - const complianceDisabled = observeLicense(database).pipe( - switchMap((lcs) => of$(lcs?.IsLicensed === 'false' || lcs?.Compliance === 'false')), - ); - - const canDownloadFiles = combineLatest([enableMobileFileDownload, complianceDisabled]).pipe( - map(([download, compliance]) => compliance || download), - ); - return { appsEnabled: observeConfigBooleanValue(database, 'FeatureFlagAppsEnabled'), currentTimezone: currentUser.pipe((switchMap((user) => of$(getTimezone(user?.timezone))))), @@ -44,7 +34,7 @@ const enhance = withObservables(['fileChannelIds'], ({database, fileChannelIds}: ), isTimezoneEnabled: observeConfigBooleanValue(database, 'ExperimentalTimezone'), fileChannels, - canDownloadFiles, + canDownloadFiles: observeCanDownloadFiles(database), publicLinkEnabled: observeConfigBooleanValue(database, 'EnablePublicLink'), }; });