Uploading multiple files to firebase and retrieving it's URL - javascript

i'm being able to upload the files but i don't know how i can get the URL links. I have the const fileArr which will receive each file, but i don't know how i can access it.
const fileUpload = (name: string) => {
let fileArr: { name: string; url: string; type: string }[] = [];
let objectArr: any[] = [];
Object.entries(file).forEach(([key, value]) => objectArr.push(value));
if (file !== null) {
const res = new Promise((resolve, reject) => {
objectArr.forEach((item: any) => {
const fileRef = ref(storage, `${name}/${item.name}`);
uploadBytes(fileRef, item).then(() => {
getDownloadURL(fileRef).then((url) => {
fileArr.push({ name: item.name, url, type: item.type });
});
});
if (!fileArr) {
reject("error");
} else {
resolve(fileArr);
}
});
});
res
.then((value) => {
return value;
})
.catch((error) => {
console.log(error);
});
}
};
I'm calling this function like this
const letsTry = () => {
const result = fileUpload("anyname");
console.log(result);
};
The console just logs 'undefined'. How should i do this?
EDIT
So, at the 'then catch' expression, before it returns i put a console.log. It's logging 'error', but the images are getting uploaded.
res
.then((value) => {
console.log(value);
return value;
})
.catch((error) => {
console.log(error);
return "error";
});

The problem is on this line:
if (!fileArr) {
Since you initialize fileArray as let fileArr: { name: string; url: string; type: string }[] = [];, it always has a value - even if it is an empty array.
And since both uploadBytes and getDownloadURL are asynchronous operations, you resolve the promise before any upload has completed.
What you'll want to do is instead check at the end of getting a download URL whether you now have all download URLs that you expect.
You can do this with Promise.all(), but you can also simply compare the number of the original files you're uploading with the number of download URLs you have, each time you got a new download URL. That should be something like this:
objectArr.forEach((item: any) => {
const fileRef = ref(storage, `${name}/${item.name}`);
uploadBytes(fileRef, item).then(() => {
getDownloadURL(fileRef).then((url) => {
fileArr.push({ name: item.name, url, type: item.type });
if (fileArr.length === objectArr.length) {
resolve(fileArr);
}
});
});
});

The 4th line:
Object.entries(file).forEach(([key, value]) => objectArr.push(value));
I think the varible file is undefined in line 4.

Related

How to use localstorage in multiple async await?

I'm making multiple calls on an endpoint to get the image of a blob and I need to save it in localstorage so that if it exists there, it's not necessary to make the call again.
The way I'm doing it, it's not waiting for the keys to spread the setItem array.
What is the correct way to do this?
assetNameFiltered.forEach((assetName) => {
const ASSET_IMAGE = assetImageCached?.filter(({ id }) => id === assetName)[0];
if (ASSET_IMAGE) {
//
} else {
useOperationServiceHook.getAssetImageByName(assetName).then(({ data }) => {
if (data.size > 0) {
const READER = new window.FileReader();
READER.readAsDataURL(data);
READER.onloadend = () => createAssetImageCache({ id: assetName, image: READER.result });
} else {
createAssetImageCache({ id: assetName, image: '' });
}
});
}
});

Why API call no longer works since a refactor?

I made this useEffect code that works good in a screen:
useEffect(() => {
getDatasFromId(searchId)
.then((data) => {
const returnObject = {
next: data.next,
items: data.results.map(item => ({ name: item.name, url: item.url }))
};
setHasNext(returnObject.next);
setDataToDisplay(returnObject.items);
});
}, [searchId]);
But now, I made some modification and the API call is running without return (no error or whatever). My new code is this:
useEffect(() => {
const apiUrl = getApiUrl(searchId);
console.log("API URL : ", apiUrl);
getDatas(apiUrl)
.then((data) => {
console.log("We get some data : ", data.results );
const returnObject = buildDataObject(data);
console.log("returnObject : ", returnObject);
setDataToDisplay(returnObject.items);
returnObject.next !== null && loadMoreApiDatasIf(returnObject.next);
});
}, [searchId]);
I don't see the error in the new code.

Firebase Firestore writes only working on the first attempt of a fresh build

I've been building an app with Firebase & React Native primarily using Firestore. I started to use Firestore and its been great, but for some reason when writing to Firestore, it is only working on the first attempt (when i remove the app, rebuild, and perform my write).
I tried to do the exact same thing except write to Firestore and everything works as expected.
I am also receiving no error!
Here is what I am doing:
export const addBrandProduct = (postObj) => {
return () => {
firebase
.firestore()
.collection('brandProducts')
.add(postObj)
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
Actions.categories();
})
.catch(error => {
console.error("Error adding document: ", error);
});
};
};
For more of a reference, here is my component code that calls addBrandProduct()
onUploadImages = () => {
let photo =
Platform.OS === 'ios'
? this.state.images.map(img => img.uri.replace('file://', ''))
: this.state.images.map(img => img.uri);
photo.forEach((image, i) => {
const sessionId = new Date().getTime();
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
let uploadBlob = null;
let mime = 'image/jpg';
const imageRef = firebase
.storage()
.ref('brandProducts/')
.child(`${this.props.userData.uid}`)
.child(`${sessionId}-${i}`);
fs.readFile(image, 'base64')
.then(data => {
return Blob.build(data, {type: `${mime};BASE64`});
})
.then(blob => {
uploadBlob = blob;
return imageRef.put(blob, {contentType: mime});
})
.then(() => {
uploadBlob.close();
return imageRef.getDownloadURL();
})
.then(url => {
//if this is the last uploaded image, post data to db
if (i === this.state.images.length - 1) {
const urls = {
...this.state.urls,
[i]: url,
};
const postObj = {
...this.state.postObj,
urls: urls,
};
this.props.addBrandProduct(postObj);
} else {
this.setState({
urls: {
...this.state.urls,
[i]: url,
},
});
}
})
.catch(error => {
console.log(error);
});
});
};
Basically, I am uploading a maximum of 3 images along with some data for it. In order to ensure I am uploading them all prior to adding the post data (writing to firestore) I am using a forEach and on the last upload, when it completes, I am calling the action to write the post data.
Edition
Hum addBrandProduct is a function that create another function.
So when you call this.props.addBrandProduct(postObj) nothing is sent to firestore, you just create a new function that should be called.
Maybe you can go out this stuff and call firebase directly, ensuring that everything works and then go back to the redux way if you still want to use it. I also make it parallelized instead of sequentials. Hope it help, hard to find the real problem when it can come from anywhere.
onUploadImages = () => {
let photo = Platform.OS === 'ios'
? this.state.images.map(img => img.uri.replace('file://', ''))
: this.state.images.map(img => img.uri);
Promise.all( photo.map( image => {
const sessionId = new Date().getTime();
const Blob = RNFetchBlob.polyfill.Blob;
//This is kind useless
//const fs = RNFetchBlob.fs;
//This is not used
//window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
//This is not adviced
//window.Blob = Blob;
let uploadBlob = null;
let mime = 'image/jpg';
const imageRef = firebase
.storage()
.ref('brandProducts/')
.child(`${this.props.userData.uid}`)
.child(`${sessionId}-${i}`);
return fs.readFile(image, 'base64')
.then(data => {
return RNFetchBlob.polyfill.Blob.build(data, {type: `${mime};BASE64`});
})
.then(blob => {
uploadBlob = blob;
return imageRef.put(blob, {contentType: mime});
})
.then(() => {
uploadBlob.close();
return imageRef.getDownloadURL();
});
))
.then( results => {
//results is, here, [ urlFromFirst, urlFronSecond, ...]
const urls = { ...this.state.urls};
results.forEach( (r, i) => urls[i] = r );
const postObj = {
...this.state.postObj,
urls
};
return firebase
.firestore()
.collection('brandProducts')
.add(postObj)
})
.then( docRef => {
console.log("Document written with ID: ", docRef.id);
})
.catch(error => {
console.error(error);
});
};

Incorrect response mime type (Expected 'application/wasm) PSPDFKIT and the reserved size is not enough to contain the signature issue oracle apex?

I followed the PSPDFKit Standalone Integration steps ,and all file in public directory (folder "i" in Apache tomcat),
I get the "PSPDFKit for Web successfully loaded!" message but it hangs up and the console gives me a single error :-
Failed to execute 'compile' on 'WebAssembly': Incorrect response MIME type. Expected 'application/wasm'.
also when i try to add digital signature faced this issue
Cannot add the container structure because the reserved size is not enough to contain the signature. Available size 8193, actual size 89694
I am tried that by below code
PSPDFKit.load({
container: "#pspdfkit",
document: 'f?p=&APP_ID.:0:&APP_SESSION.:APPLICATION_PROCESS=PREVIEW_FILE:::FILE_ID:' + apex.item('P6_ID').getValue(),
licenseKey: "",
initialViewState: new PSPDFKit.ViewState({
showSignatureValidationStatus:
PSPDFKit.ShowSignatureValidationStatusMode.IF_SIGNED
}),
async trustedCAsCallback() {
const response = await fetch("http://localhost:90/i/certs/ca.pem");
const cert = await response.text();
return [cert];
}
})
.then(function(instance) {
var item = {
type: "custom",
id: "my-button",
title: "digital sign",
onPress: function(event) {
instance
.signDocument(null, generatePKCS7)
.then(() => {
console.log("document signed.");
})
.catch(error => {
console.error("The document could not be signed.", error);
});
}
};
if (app_user =="aaaa") {
instance.setToolbarItems(function(items) {
items.push(item);
return items;
});
}
function generatePKCS7({ fileContents }) {
const certificatePromise = fetch("http://localhost:90/i/certs/certificate.pem").then(response =>
response.text()
);
const privateKeyPromise = fetch("http://localhost:90/i/certs/private-key.pem").then(response =>
response.text()
);
return new Promise((resolve, reject) => {
Promise.all([certificatePromise, privateKeyPromise])
.then(([certificatePem, privateKeyPem]) => {
const certificate = forge.pki.certificateFromPem(certificatePem);
const privateKey = forge.pki.privateKeyFromPem(privateKeyPem);
const p7 = forge.pkcs7.createSignedData();
p7.content = new forge.util.ByteBuffer(fileContents);
p7.addCertificate(certificate);
p7.addSigner({
key: privateKey,
certificate: certificate,
digestAlgorithm: forge.pki.oids.sha256,
authenticatedAttributes: [
{
type: forge.pki.oids.contentType,
value: forge.pki.oids.data
},
{
type: forge.pki.oids.messageDigest
},
{
type: forge.pki.oids.signingTime,
Value: new Date()
}
]
}
);
p7.sign({ detached: true })
const result = stringToArrayBuffer(
forge.asn1.toDer(p7.toAsn1()).getBytes()
);
resolve(result);
})
.catch(reject);
});
}
function stringToArrayBuffer(binaryString) {
const buffer = new ArrayBuffer(binaryString.length);
let bufferView = new Uint8Array(buffer);
for (let i = 0, len = binaryString.length; i < len; i++) {
bufferView[i] = binaryString.charCodeAt(i);
}
return buffer;
}
})
.catch(function(error) {
console.error(error.message);
})
apex version 19.2
tomcat 8.5 ,
ords
It looks like the WASM file is not served with the correct content type. The solution is either to fix your server to return the correct content type or disable streaming instantiation for WebAssembly when loading PSPDFKit, as described here: https://pspdfkit.com/guides/web/current/troubleshooting/common-issues/#response-has-unsupported-mime-type-error
In the future, please reach out to https://pspdfkit.com/support/request and our support team will help you in there.

Does anyone know why res.download is giving my download file a random name each time?

I'm using express 4.17.1. When I try to use res.download to send a csv file to the browser, the file is downloaded but the file name is something like this: 3d6a8bc1-696c-40f2-bae8-29ca69658534.csv
Then, when I attempt to download the same file again, it will send the file under this name: c1cd40ff-ea9d-4327-9389-9768fb53384a.csv
Each time it is a different random string of characters.
My code is simply this:
res.download(filePath, 'list.csv');
The filePath is this: ./downloadables/mail-list-14da.csv
I've tried using sendFile but got the same result. I recently updated from a previous version of express to see if it would automagically resolve this issue but it is still doing this.
EDIT: More Code Below as Requested
Here is the entirety of the request endpoint:
/*
* Download the list specified by the list_id with the appropriate fields as specified by the
* list_type parameter.
*/
router.get('/download/:list_type/:list_id', authCheck('list'), function(
req,
res,
next
) {
let listData = {};
Voter.aggregate(aggrPipelineList(req.params.list_type, req.params.list_id))
.allowDiskUse(true)
.exec()
.then(voterDocs => {
if (voterDocs && voterDocs.length === 0) {
res.status(404).json({
message: `list_id ${req.params.list_id} not found`
});
} else {
listData.voter_docs = voterDocs;
return req.params.list_type;
}
})
.then(listType => {
if (listType === 'mail') {
return generateMailExportFile(req.params.list_id, listData);
} else if (listType == 'phone') {
return generateCallExportFile(req.params.list_id, listData);
} else {
return generateFacebookExportFile(req.params.list_id, listData);
}
})
.then(filePath => {
console.log('FP: ' + filePath);
res.download(filePath, 'list.csv');
})
.catch(err => {
res.status(500).json({ message: err.message }); // #note: added message
});
});
Also including the generateMailExportFile function for completeness. Yes, I know I can refactor the three generate export file functions. It's on my list... I originally wrote this before I knew what the hell I was doing.
generateMailExportFile = function(listID, listData) {
let fields = [
'First Name',
'Last Name',
'Suffix',
'Street Address 1',
'Street Address 2',
'City',
'State',
'Zip'
];
let fileName = 'mail-list-' + listID.substr(listID.length - 4) + '.csv';
let voterRows = buildVoterRowsForMailList(listData.voter_docs);
let csv = json2csv({ data: voterRows, fields: fields });
let tempServerFilePath = './downloadables/' + fileName;
return new Promise((resolve, reject) => {
fs.writeFile(tempServerFilePath, csv, function(err) {
if (err) {
reject(err);
} else {
resolve(tempServerFilePath);
}
});
});
};
Here is the redux/thunk function that requests the file download:
export const downloadList = (listId, type) => {
return (dispatch, getState) => {
const rshttp = new RSHttp(getState);
rshttp
.get('/list/download/' + type + '/' + listId)
.then(response => {
let file = new Blob([response.data], { type: 'text/csv' }),
url = window.URL.createObjectURL(file);
window.open(url);
})
.catch(error => {
console.log('Error Downloading File: ' + JSON.stringify(error));
});
};
};
I hadn't before thought about the problem being on the react side. If I find an answer, I'll update this question. Any thoughts are still greatly appreciated!
The problem is you are recreating the file on your front-end. You can simply change your React code to:
export const downloadList = (listId, type) => {
return (dispatch, getState) => {
window.open('http://localhost:8080/list/download/' + type + '/' + listId', '_blank')
// Replace with your backend URL :)
};
};
and it will download the file with the correct filename.

Categories