[FIX] Filenames are incorrect in non-latin alphabets on upload (#2671)
* fix: filename on react-native-image-crop-picker * fix: use rn-fetch-blob to upload files * fix: FileUpload as a service * fix: cancel upload on iOS * fix: file upload from share extension Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
b0b9d62a91
commit
2403eb3857
|
@ -1,6 +1,7 @@
|
|||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
||||
|
||||
import FileUpload from '../../utils/fileUpload';
|
||||
import database from '../database';
|
||||
import log from '../../utils/log';
|
||||
|
||||
|
@ -12,7 +13,11 @@ export function isUploadActive(path) {
|
|||
|
||||
export async function cancelUpload(item) {
|
||||
if (uploadQueue[item.path]) {
|
||||
uploadQueue[item.path].abort();
|
||||
try {
|
||||
await uploadQueue[item.path].cancel();
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
try {
|
||||
const db = database.active;
|
||||
await db.action(async() => {
|
||||
|
@ -32,9 +37,6 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
|
||||
const uploadUrl = `${ server }/api/v1/rooms.upload/${ rid }`;
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
const formData = new FormData();
|
||||
|
||||
fileInfo.rid = rid;
|
||||
|
||||
const db = database.active;
|
||||
|
@ -56,31 +58,38 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
}
|
||||
}
|
||||
|
||||
uploadQueue[fileInfo.path] = xhr;
|
||||
xhr.open('POST', uploadUrl);
|
||||
|
||||
formData.append('file', {
|
||||
uri: fileInfo.path,
|
||||
const formData = [];
|
||||
formData.push({
|
||||
name: 'file',
|
||||
type: fileInfo.type,
|
||||
name: encodeURI(fileInfo.name) || 'fileMessage'
|
||||
filename: fileInfo.name || 'fileMessage',
|
||||
uri: fileInfo.path
|
||||
});
|
||||
|
||||
if (fileInfo.description) {
|
||||
formData.append('description', fileInfo.description);
|
||||
formData.push({
|
||||
name: 'description',
|
||||
data: fileInfo.description
|
||||
});
|
||||
}
|
||||
|
||||
if (tmid) {
|
||||
formData.append('tmid', tmid);
|
||||
formData.push({
|
||||
name: 'tmid',
|
||||
data: tmid
|
||||
});
|
||||
}
|
||||
|
||||
xhr.setRequestHeader('X-Auth-Token', token);
|
||||
xhr.setRequestHeader('X-User-Id', id);
|
||||
const { customHeaders } = RocketChatSettings;
|
||||
Object.keys(customHeaders).forEach((key) => {
|
||||
xhr.setRequestHeader(key, customHeaders[key]);
|
||||
});
|
||||
const headers = {
|
||||
...RocketChatSettings.customHeaders,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
'X-Auth-Token': token,
|
||||
'X-User-Id': id
|
||||
};
|
||||
|
||||
xhr.upload.onprogress = async({ total, loaded }) => {
|
||||
uploadQueue[fileInfo.path] = FileUpload.fetch('POST', uploadUrl, headers, formData);
|
||||
|
||||
uploadQueue[fileInfo.path].uploadProgress(async(loaded, total) => {
|
||||
try {
|
||||
await db.action(async() => {
|
||||
await uploadRecord.update((u) => {
|
||||
|
@ -90,15 +99,14 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
xhr.onload = async() => {
|
||||
if (xhr.status >= 200 && xhr.status < 400) { // If response is all good...
|
||||
uploadQueue[fileInfo.path].then(async(response) => {
|
||||
if (response.respInfo.status >= 200 && response.respInfo.status < 400) { // If response is all good...
|
||||
try {
|
||||
await db.action(async() => {
|
||||
await uploadRecord.destroyPermanently();
|
||||
});
|
||||
const response = JSON.parse(xhr.response);
|
||||
resolve(response);
|
||||
} catch (e) {
|
||||
log(e);
|
||||
|
@ -114,15 +122,14 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
log(e);
|
||||
}
|
||||
try {
|
||||
const response = JSON.parse(xhr.response);
|
||||
reject(response);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
xhr.onerror = async(error) => {
|
||||
uploadQueue[fileInfo.path].catch(async(error) => {
|
||||
try {
|
||||
await db.action(async() => {
|
||||
await uploadRecord.update((u) => {
|
||||
|
@ -133,9 +140,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
|||
log(e);
|
||||
}
|
||||
reject(error);
|
||||
};
|
||||
|
||||
xhr.send(formData);
|
||||
});
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
|
||||
class FileUpload {
|
||||
fetch = (method, url, headers, data) => {
|
||||
const formData = data.map((item) => {
|
||||
if (item.uri) {
|
||||
return {
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
filename: item.filename,
|
||||
data: RNFetchBlob.wrap(decodeURI(item.uri))
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
return RNFetchBlob.fetch(method, url, headers, formData);
|
||||
}
|
||||
}
|
||||
|
||||
const fileUpload = new FileUpload();
|
||||
export default fileUpload;
|
|
@ -0,0 +1,48 @@
|
|||
class FileUpload {
|
||||
_xhr = new XMLHttpRequest();
|
||||
|
||||
_formData = new FormData();
|
||||
|
||||
fetch = (method, url, headers, data) => {
|
||||
this._xhr.open(method, url);
|
||||
|
||||
Object.keys(headers).forEach((key) => {
|
||||
this._xhr.setRequestHeader(key, headers[key]);
|
||||
});
|
||||
|
||||
data.forEach((item) => {
|
||||
if (item.uri) {
|
||||
this._formData.append(item.name, {
|
||||
uri: item.uri,
|
||||
type: item.type,
|
||||
name: item.filename
|
||||
});
|
||||
} else {
|
||||
this._formData.append(item.name, item.data);
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
then = (callback) => {
|
||||
this._xhr.onload = () => callback({ respInfo: this._xhr });
|
||||
this._xhr.send(this._formData);
|
||||
}
|
||||
|
||||
catch = (callback) => {
|
||||
this._xhr.onerror = callback;
|
||||
}
|
||||
|
||||
uploadProgress = (callback) => {
|
||||
this._xhr.upload.onprogress = ({ total, loaded }) => callback(loaded, total);
|
||||
}
|
||||
|
||||
cancel = () => {
|
||||
this._xhr.abort();
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
const fileUpload = new FileUpload();
|
||||
export default fileUpload;
|
|
@ -74,7 +74,7 @@ class ShareListView extends React.Component {
|
|||
}
|
||||
const info = await Promise.all(data.filter(item => item.type === 'media').map(file => FileSystem.getInfoAsync(this.uriToPath(file.value), { size: true })));
|
||||
const attachments = info.map(file => ({
|
||||
filename: file.uri.substring(file.uri.lastIndexOf('/') + 1),
|
||||
filename: decodeURIComponent(file.uri.substring(file.uri.lastIndexOf('/') + 1)),
|
||||
description: '',
|
||||
size: file.size,
|
||||
mime: mime.lookup(file.uri),
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
diff --git a/node_modules/react-native-image-crop-picker/android/src/main/java/com/reactnative/ivpusic/imagepicker/PickerModule.java b/node_modules/react-native-image-crop-picker/android/src/main/java/com/reactnative/ivpusic/imagepicker/PickerModule.java
|
||||
index 3500542..94e45b6 100644
|
||||
--- a/node_modules/react-native-image-crop-picker/android/src/main/java/com/reactnative/ivpusic/imagepicker/PickerModule.java
|
||||
+++ b/node_modules/react-native-image-crop-picker/android/src/main/java/com/reactnative/ivpusic/imagepicker/PickerModule.java
|
||||
@@ -584,6 +584,7 @@ class PickerModule extends ReactContextBaseJavaModule implements ActivityEventLi
|
||||
image.putInt("height", options.outHeight);
|
||||
image.putString("mime", options.outMimeType);
|
||||
image.putInt("size", (int) new File(compressedImagePath).length());
|
||||
+ image.putString("filename", compressedImage.getName());
|
||||
image.putString("modificationDate", String.valueOf(modificationDate));
|
||||
|
||||
if (includeBase64) {
|
Loading…
Reference in New Issue