diff --git a/app/components/__snapshots__/attachment_button.test.js.snap b/app/components/__snapshots__/attachment_button.test.js.snap new file mode 100644 index 000000000..accd5a17b --- /dev/null +++ b/app/components/__snapshots__/attachment_button.test.js.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AttachmentButton should match snapshot 1`] = ` + + + +`; diff --git a/app/components/__snapshots__/profile_picture_button.test.js.snap b/app/components/__snapshots__/profile_picture_button.test.js.snap index 8f915b597..3cba2c9bd 100644 --- a/app/components/__snapshots__/profile_picture_button.test.js.snap +++ b/app/components/__snapshots__/profile_picture_button.test.js.snap @@ -53,5 +53,6 @@ exports[`profile_picture_button should match snapshot 1`] = ` } } uploadFiles={[MockFunction]} + validMimeTypes={Array []} /> `; diff --git a/app/components/attachment_button.js b/app/components/attachment_button.js index 4f39b0a2f..29bd3d0d0 100644 --- a/app/components/attachment_button.js +++ b/app/components/attachment_button.js @@ -17,6 +17,8 @@ import {DocumentPicker} from 'react-native-document-picker'; import ImagePicker from 'react-native-image-picker'; import Permissions from 'react-native-permissions'; +import {lookupMimeType} from 'mattermost-redux/utils/file_utils'; + import {PermissionTypes} from 'app/constants'; import {changeOpacity} from 'app/utils/theme'; import {t} from 'app/utils/i18n'; @@ -27,6 +29,7 @@ export default class AttachmentButton extends PureComponent { static propTypes = { blurTextBox: PropTypes.func.isRequired, browseFileTypes: PropTypes.string, + validMimeTypes: PropTypes.array, canBrowseFiles: PropTypes.bool, canBrowsePhotoLibrary: PropTypes.bool, canBrowseVideoLibrary: PropTypes.bool, @@ -39,6 +42,7 @@ export default class AttachmentButton extends PureComponent { navigator: PropTypes.object.isRequired, onShowFileMaxWarning: PropTypes.func, onShowFileSizeWarning: PropTypes.func, + onShowUnsupportedMimeTypeWarning: PropTypes.func, theme: PropTypes.object.isRequired, uploadFiles: PropTypes.func.isRequired, wrapper: PropTypes.bool, @@ -47,6 +51,7 @@ export default class AttachmentButton extends PureComponent { static defaultProps = { browseFileTypes: Platform.OS === 'ios' ? 'public.item' : '*/*', + validMimeTypes: [], canBrowseFiles: true, canBrowsePhotoLibrary: true, canBrowseVideoLibrary: true, @@ -321,7 +326,14 @@ export default class AttachmentButton extends PureComponent { file.fileName = fileInfo.filename; } - if (file.fileSize > this.props.maxFileSize) { + if (!file.type) { + file.type = lookupMimeType(file.fileName); + } + + const {validMimeTypes} = this.props; + if (validMimeTypes.length && !validMimeTypes.includes(file.type)) { + this.props.onShowUnsupportedMimeTypeWarning(); + } else if (file.fileSize > this.props.maxFileSize) { this.props.onShowFileSizeWarning(file.fileName); } else { this.props.uploadFiles(files); diff --git a/app/components/attachment_button.test.js b/app/components/attachment_button.test.js new file mode 100644 index 000000000..e0ef3694a --- /dev/null +++ b/app/components/attachment_button.test.js @@ -0,0 +1,71 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {shallow} from 'enzyme'; + +import Preferences from 'mattermost-redux/constants/preferences'; + +import AttachmentButton from './attachment_button'; + +jest.mock('react-intl'); + +describe('AttachmentButton', () => { + const baseProps = { + theme: Preferences.THEMES.default, + navigator: {}, + blurTextBox: jest.fn(), + maxFileSize: 10, + uploadFiles: jest.fn(), + }; + + test('should match snapshot', () => { + const wrapper = shallow( + + ); + + expect(wrapper.getElement()).toMatchSnapshot(); + }); + + test('should not upload file with invalid MIME type', () => { + const props = { + ...baseProps, + validMimeTypes: ['image/jpeg'], + onShowUnsupportedMimeTypeWarning: jest.fn(), + }; + + const wrapper = shallow( + + ); + + const file = { + type: 'image/gif', + fileSize: 10, + fileName: 'test', + }; + wrapper.instance().uploadFiles([file]); + expect(props.onShowUnsupportedMimeTypeWarning).toHaveBeenCalled(); + expect(props.uploadFiles).not.toHaveBeenCalled(); + }); + + test('should upload file with valid MIME type', () => { + const props = { + ...baseProps, + validMimeTypes: ['image/jpeg'], + onShowUnsupportedMimeTypeWarning: jest.fn(), + }; + + const wrapper = shallow( + + ); + + const file = { + type: 'image/jpeg', + fileSize: 10, + fileName: 'test', + }; + wrapper.instance().uploadFiles([file]); + expect(props.onShowUnsupportedMimeTypeWarning).not.toHaveBeenCalled(); + expect(props.uploadFiles).toHaveBeenCalled(); + }); +}); diff --git a/app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap b/app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap index c3f540b98..c2010d9ca 100644 --- a/app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap +++ b/app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap @@ -74,6 +74,7 @@ exports[`edit_profile should match snapshot 1`] = ` } } onShowFileSizeWarning={[Function]} + onShowUnsupportedMimeTypeWarning={[Function]} removeProfileImage={[Function]} theme={ Object { @@ -104,6 +105,13 @@ exports[`edit_profile should match snapshot 1`] = ` } } uploadFiles={[Function]} + validMimeTypes={ + Array [ + "image/jpeg", + "image/png", + "image/bmp", + ] + } wrapper={true} > { + const {formatMessage} = this.context.intl; + const fileTypeWarning = formatMessage({ + id: 'mobile.file_upload.unsupportedMimeType', + defaultMessage: 'Only files of the following MIME type can be uploaded: {mimeTypes}', + }, { + mimeTypes: VALID_MIME_TYPES.join('\n'), + }); + + Alert.alert('', fileTypeWarning); + }; + renderFirstNameSettings = () => { const {formatMessage} = this.context.intl; const {config, currentUser, theme} = this.props; @@ -500,6 +517,8 @@ export default class EditProfile extends PureComponent { uploadFiles={this.handleUploadProfileImage} removeProfileImage={this.handleRemoveProfileImage} onShowFileSizeWarning={this.onShowFileSizeWarning} + onShowUnsupportedMimeTypeWarning={this.onShowUnsupportedMimeTypeWarning} + validMimeTypes={VALID_MIME_TYPES} >