[FIX] Unify upload check (#1229)
This commit is contained in:
parent
ae7a9cba60
commit
319ca7f044
|
@ -5,6 +5,7 @@ import {
|
|||
} from 'react-native';
|
||||
import { AudioRecorder, AudioUtils } from 'react-native-audio';
|
||||
import { BorderlessButton } from 'react-native-gesture-handler';
|
||||
import FileSystem from 'expo-file-system';
|
||||
|
||||
import styles from './styles';
|
||||
import I18n from '../../i18n';
|
||||
|
@ -68,7 +69,7 @@ export default class extends React.PureComponent {
|
|||
//
|
||||
AudioRecorder.onFinished = (data) => {
|
||||
if (!this.recordingCanceled && isIOS) {
|
||||
this.finishRecording(data.status === 'OK', data.audioFileURL);
|
||||
this.finishRecording(data.status === 'OK', data.audioFileURL, data.audioFileSize);
|
||||
}
|
||||
};
|
||||
AudioRecorder.startRecording();
|
||||
|
@ -80,7 +81,7 @@ export default class extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
finishRecording = (didSucceed, filePath) => {
|
||||
finishRecording = (didSucceed, filePath, size) => {
|
||||
const { onFinish } = this.props;
|
||||
if (!didSucceed) {
|
||||
return onFinish && onFinish(didSucceed);
|
||||
|
@ -90,9 +91,11 @@ export default class extends React.PureComponent {
|
|||
}
|
||||
const fileInfo = {
|
||||
name: this.name,
|
||||
mime: 'audio/aac',
|
||||
type: 'audio/aac',
|
||||
store: 'Uploads',
|
||||
path: filePath
|
||||
path: filePath,
|
||||
size
|
||||
};
|
||||
return onFinish && onFinish(fileInfo);
|
||||
}
|
||||
|
@ -102,7 +105,8 @@ export default class extends React.PureComponent {
|
|||
this.recording = false;
|
||||
const filePath = await AudioRecorder.stopRecording();
|
||||
if (isAndroid) {
|
||||
this.finishRecording(true, filePath);
|
||||
const data = await FileSystem.getInfoAsync(decodeURIComponent(filePath));
|
||||
this.finishRecording(true, filePath, data.size);
|
||||
}
|
||||
} catch (err) {
|
||||
this.finishRecording(false);
|
||||
|
|
|
@ -2,7 +2,6 @@ import React, { Component } from 'react';
|
|||
import {
|
||||
View, Text, StyleSheet, Image, ScrollView, TouchableHighlight
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import Modal from 'react-native-modal';
|
||||
import { responsive } from 'react-native-responsive-ui';
|
||||
|
@ -13,9 +12,8 @@ import Button from '../Button';
|
|||
import I18n from '../../i18n';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import { isIOS } from '../../utils/deviceInfo';
|
||||
import { canUploadFile } from '../../utils/media';
|
||||
import {
|
||||
COLOR_PRIMARY, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE, COLOR_DANGER
|
||||
COLOR_PRIMARY, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE
|
||||
} from '../../constants/colors';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
|
||||
|
@ -75,23 +73,6 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
textAlign: 'center'
|
||||
},
|
||||
errorIcon: {
|
||||
color: COLOR_DANGER
|
||||
},
|
||||
fileMime: {
|
||||
...sharedStyles.textColorTitle,
|
||||
...sharedStyles.textBold,
|
||||
textAlign: 'center',
|
||||
fontSize: 20,
|
||||
marginBottom: 20
|
||||
},
|
||||
errorContainer: {
|
||||
margin: 20,
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
video: {
|
||||
flex: 1,
|
||||
borderRadius: 4,
|
||||
|
@ -110,9 +91,7 @@ class UploadModal extends Component {
|
|||
file: PropTypes.object,
|
||||
close: PropTypes.func,
|
||||
submit: PropTypes.func,
|
||||
window: PropTypes.object,
|
||||
FileUpload_MediaTypeWhiteList: PropTypes.string,
|
||||
FileUpload_MaxFileSize: PropTypes.number
|
||||
window: PropTypes.object
|
||||
}
|
||||
|
||||
state = {
|
||||
|
@ -154,79 +133,12 @@ class UploadModal extends Component {
|
|||
return false;
|
||||
}
|
||||
|
||||
canUploadFile = () => {
|
||||
const { FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize, file } = this.props;
|
||||
if (!(file && file.path)) {
|
||||
return true;
|
||||
}
|
||||
if (file.size > FileUpload_MaxFileSize) {
|
||||
return false;
|
||||
}
|
||||
// if white list is empty, all media types are enabled
|
||||
if (!FileUpload_MediaTypeWhiteList) {
|
||||
return true;
|
||||
}
|
||||
const allowedMime = FileUpload_MediaTypeWhiteList.split(',');
|
||||
if (allowedMime.includes(file.mime)) {
|
||||
return true;
|
||||
}
|
||||
const wildCardGlob = '/*';
|
||||
const wildCards = allowedMime.filter(item => item.indexOf(wildCardGlob) > 0);
|
||||
if (wildCards.includes(file.mime.replace(/(\/.*)$/, wildCardGlob))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
submit = () => {
|
||||
const { file, submit } = this.props;
|
||||
const { name, description } = this.state;
|
||||
submit({ ...file, name, description });
|
||||
}
|
||||
|
||||
renderError = () => {
|
||||
const { file, FileUpload_MaxFileSize, close } = this.props;
|
||||
const { window: { width } } = this.props;
|
||||
const errorMessage = (FileUpload_MaxFileSize < file.size)
|
||||
? 'error-file-too-large'
|
||||
: 'error-invalid-file-type';
|
||||
return (
|
||||
<View style={[styles.container, { width: width - 32 }]}>
|
||||
<View style={styles.titleContainer}>
|
||||
<Text style={styles.title}>{I18n.t(errorMessage)}</Text>
|
||||
</View>
|
||||
<View style={styles.errorContainer}>
|
||||
<CustomIcon name='circle-cross' size={120} style={styles.errorIcon} />
|
||||
</View>
|
||||
<Text style={styles.fileMime}>{ file.mime }</Text>
|
||||
<View style={styles.buttonContainer}>
|
||||
{
|
||||
(isIOS)
|
||||
? (
|
||||
<Button
|
||||
title={I18n.t('Cancel')}
|
||||
type='secondary'
|
||||
backgroundColor={cancelButtonColor}
|
||||
style={styles.button}
|
||||
onPress={close}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<TouchableHighlight
|
||||
onPress={close}
|
||||
style={[styles.androidButton, { backgroundColor: cancelButtonColor }]}
|
||||
underlayColor={cancelButtonColor}
|
||||
activeOpacity={0.5}
|
||||
>
|
||||
<Text style={[styles.androidButtonText, { ...sharedStyles.textBold, color: COLOR_PRIMARY }]}>{I18n.t('Cancel')}</Text>
|
||||
</TouchableHighlight>
|
||||
)
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
renderButtons = () => {
|
||||
const { close } = this.props;
|
||||
if (isIOS) {
|
||||
|
@ -288,10 +200,9 @@ class UploadModal extends Component {
|
|||
|
||||
render() {
|
||||
const {
|
||||
window: { width }, isVisible, close, file, FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize
|
||||
window: { width }, isVisible, close
|
||||
} = this.props;
|
||||
const { name, description } = this.state;
|
||||
const showError = !canUploadFile(file, { FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize });
|
||||
return (
|
||||
<Modal
|
||||
isVisible={isVisible}
|
||||
|
@ -304,37 +215,29 @@ class UploadModal extends Component {
|
|||
hideModalContentWhileAnimating
|
||||
avoidKeyboard
|
||||
>
|
||||
{(showError) ? this.renderError()
|
||||
: (
|
||||
<View style={[styles.container, { width: width - 32 }]}>
|
||||
<View style={styles.titleContainer}>
|
||||
<Text style={styles.title}>{I18n.t('Upload_file_question_mark')}</Text>
|
||||
</View>
|
||||
<View style={[styles.container, { width: width - 32 }]}>
|
||||
<View style={styles.titleContainer}>
|
||||
<Text style={styles.title}>{I18n.t('Upload_file_question_mark')}</Text>
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.scrollView}>
|
||||
{this.renderPreview()}
|
||||
<TextInput
|
||||
placeholder={I18n.t('File_name')}
|
||||
value={name}
|
||||
onChangeText={value => this.setState({ name: value })}
|
||||
/>
|
||||
<TextInput
|
||||
placeholder={I18n.t('File_description')}
|
||||
value={description}
|
||||
onChangeText={value => this.setState({ description: value })}
|
||||
/>
|
||||
</ScrollView>
|
||||
{this.renderButtons()}
|
||||
</View>
|
||||
)}
|
||||
<ScrollView style={styles.scrollView}>
|
||||
{this.renderPreview()}
|
||||
<TextInput
|
||||
placeholder={I18n.t('File_name')}
|
||||
value={name}
|
||||
onChangeText={value => this.setState({ name: value })}
|
||||
/>
|
||||
<TextInput
|
||||
placeholder={I18n.t('File_description')}
|
||||
value={description}
|
||||
onChangeText={value => this.setState({ description: value })}
|
||||
/>
|
||||
</ScrollView>
|
||||
{this.renderButtons()}
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList,
|
||||
FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize
|
||||
});
|
||||
|
||||
export default responsive(connect(mapStateToProps)(UploadModal));
|
||||
export default responsive(UploadModal);
|
||||
|
|
|
@ -30,6 +30,7 @@ import LeftButtons from './LeftButtons';
|
|||
import RightButtons from './RightButtons';
|
||||
import { isAndroid } from '../../utils/deviceInfo';
|
||||
import CommandPreview from './CommandPreview';
|
||||
import { canUploadFile } from '../../utils/media';
|
||||
|
||||
const MENTIONS_TRACKING_TYPE_USERS = '@';
|
||||
const MENTIONS_TRACKING_TYPE_EMOJIS = ':';
|
||||
|
@ -73,6 +74,8 @@ class MessageBox extends Component {
|
|||
roomType: PropTypes.string,
|
||||
tmid: PropTypes.string,
|
||||
replyWithMention: PropTypes.bool,
|
||||
FileUpload_MediaTypeWhiteList: PropTypes.string,
|
||||
FileUpload_MaxFileSize: PropTypes.number,
|
||||
getCustomEmoji: PropTypes.func,
|
||||
editCancel: PropTypes.func.isRequired,
|
||||
editRequest: PropTypes.func.isRequired,
|
||||
|
@ -435,6 +438,16 @@ class MessageBox extends Component {
|
|||
this.setShowSend(false);
|
||||
}
|
||||
|
||||
canUploadFile = (file) => {
|
||||
const { FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize } = this.props;
|
||||
const result = canUploadFile(file, { FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize });
|
||||
if (result.success) {
|
||||
return true;
|
||||
}
|
||||
Alert.alert(I18n.t('Error_uploading'), I18n.t(result.error));
|
||||
return false;
|
||||
}
|
||||
|
||||
sendMediaMessage = async(file) => {
|
||||
const {
|
||||
rid, tmid, baseUrl: server, user
|
||||
|
@ -458,7 +471,9 @@ class MessageBox extends Component {
|
|||
takePhoto = async() => {
|
||||
try {
|
||||
const image = await ImagePicker.openCamera(this.imagePickerConfig);
|
||||
this.showUploadModal(image);
|
||||
if (this.canUploadFile(image)) {
|
||||
this.showUploadModal(image);
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
@ -467,7 +482,9 @@ class MessageBox extends Component {
|
|||
takeVideo = async() => {
|
||||
try {
|
||||
const video = await ImagePicker.openCamera(this.videoPickerConfig);
|
||||
this.showUploadModal(video);
|
||||
if (this.canUploadFile(video)) {
|
||||
this.showUploadModal(video);
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
@ -476,7 +493,9 @@ class MessageBox extends Component {
|
|||
chooseFromLibrary = async() => {
|
||||
try {
|
||||
const image = await ImagePicker.openPicker(this.libraryPickerConfig);
|
||||
this.showUploadModal(image);
|
||||
if (this.canUploadFile(image)) {
|
||||
this.showUploadModal(image);
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
@ -487,12 +506,15 @@ class MessageBox extends Component {
|
|||
const res = await DocumentPicker.pick({
|
||||
type: [DocumentPicker.types.allFiles]
|
||||
});
|
||||
this.showUploadModal({
|
||||
const file = {
|
||||
filename: res.name,
|
||||
size: res.size,
|
||||
mime: res.type,
|
||||
path: res.uri
|
||||
});
|
||||
};
|
||||
if (this.canUploadFile(file)) {
|
||||
this.showUploadModal(file);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!DocumentPicker.isCancel(e)) {
|
||||
log(e);
|
||||
|
@ -560,11 +582,10 @@ class MessageBox extends Component {
|
|||
});
|
||||
if (fileInfo) {
|
||||
try {
|
||||
await RocketChat.sendFileMessage(rid, fileInfo, tmid, server, user);
|
||||
} catch (e) {
|
||||
if (e && e.error === 'error-file-too-large') {
|
||||
return Alert.alert(I18n.t(e.error));
|
||||
if (this.canUploadFile(fileInfo)) {
|
||||
await RocketChat.sendFileMessage(rid, fileInfo, tmid, server, user);
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
}
|
||||
|
@ -921,7 +942,9 @@ const mapStateToProps = state => ({
|
|||
id: state.login.user && state.login.user.id,
|
||||
username: state.login.user && state.login.user.username,
|
||||
token: state.login.user && state.login.user.token
|
||||
}
|
||||
},
|
||||
FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList,
|
||||
FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize
|
||||
});
|
||||
|
||||
const dispatchToProps = ({
|
||||
|
|
|
@ -30,14 +30,9 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
const serversDB = database.servers;
|
||||
const serversCollection = serversDB.collections.get('servers');
|
||||
const serverInfo = await serversCollection.find(server);
|
||||
const { FileUpload_MaxFileSize, id: Site_Url } = serverInfo;
|
||||
const { id: Site_Url } = serverInfo;
|
||||
const { id, token } = user;
|
||||
|
||||
// -1 maxFileSize means there is no limit
|
||||
if (FileUpload_MaxFileSize > -1 && fileInfo.size > FileUpload_MaxFileSize) {
|
||||
return reject({ error: 'error-file-too-large' }); // eslint-disable-line
|
||||
}
|
||||
|
||||
const uploadUrl = `${ Site_Url }/api/v1/rooms.upload/${ rid }`;
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
export const canUploadFile = (file, serverInfo) => {
|
||||
const { FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize } = serverInfo;
|
||||
if (!(file && file.path)) {
|
||||
return true;
|
||||
return { success: true };
|
||||
}
|
||||
if (file.size > FileUpload_MaxFileSize) {
|
||||
return false;
|
||||
if (FileUpload_MaxFileSize > -1 && file.size > FileUpload_MaxFileSize) {
|
||||
return { success: false, error: 'error-file-too-large' };
|
||||
}
|
||||
// if white list is empty, all media types are enabled
|
||||
if (!FileUpload_MediaTypeWhiteList) {
|
||||
return true;
|
||||
return { success: true };
|
||||
}
|
||||
const allowedMime = FileUpload_MediaTypeWhiteList.split(',');
|
||||
if (allowedMime.includes(file.mime)) {
|
||||
return true;
|
||||
return { success: true };
|
||||
}
|
||||
const wildCardGlob = '/*';
|
||||
const wildCards = allowedMime.filter(item => item.indexOf(wildCardGlob) > 0);
|
||||
if (wildCards.includes(file.mime.replace(/(\/.*)$/, wildCardGlob))) {
|
||||
return true;
|
||||
if (file.mime && wildCards.includes(file.mime.replace(/(\/.*)$/, wildCardGlob))) {
|
||||
return { success: true };
|
||||
}
|
||||
return false;
|
||||
return { success: false, error: 'error-invalid-file-type' };
|
||||
};
|
||||
|
|
|
@ -199,12 +199,14 @@ class ShareListView extends React.Component {
|
|||
this.servers = await serversCollection.query().fetch();
|
||||
this.chats = this.data.slice(0, LIMIT);
|
||||
const serverInfo = await serversCollection.find(server);
|
||||
const canUploadFileResult = canUploadFile(fileInfo || fileData, serverInfo);
|
||||
|
||||
this.internalSetState({
|
||||
chats: this.chats ? this.chats.slice() : [],
|
||||
servers: this.servers ? this.servers.slice() : [],
|
||||
loading: false,
|
||||
showError: !canUploadFile(fileInfo || fileData, serverInfo),
|
||||
showError: !canUploadFileResult.success,
|
||||
error: canUploadFileResult.error,
|
||||
serverInfo
|
||||
});
|
||||
this.forceUpdate();
|
||||
|
@ -378,12 +380,8 @@ class ShareListView extends React.Component {
|
|||
|
||||
renderError = () => {
|
||||
const {
|
||||
fileInfo: file, loading, searching, serverInfo
|
||||
fileInfo: file, loading, searching, error
|
||||
} = this.state;
|
||||
const { FileUpload_MaxFileSize } = serverInfo;
|
||||
const errorMessage = (FileUpload_MaxFileSize < file.size)
|
||||
? 'error-file-too-large'
|
||||
: 'error-invalid-file-type';
|
||||
|
||||
if (loading) {
|
||||
return <ActivityIndicator style={styles.loading} />;
|
||||
|
@ -400,7 +398,7 @@ class ShareListView extends React.Component {
|
|||
: null
|
||||
}
|
||||
<View style={[styles.container, styles.centered]}>
|
||||
<Text style={styles.title}>{I18n.t(errorMessage)}</Text>
|
||||
<Text style={styles.title}>{I18n.t(error)}</Text>
|
||||
<CustomIcon name='circle-cross' size={120} style={styles.errorIcon} />
|
||||
<Text style={styles.fileMime}>{ file.mime }</Text>
|
||||
</View>
|
||||
|
|
Loading…
Reference in New Issue