Multi upload files with input - vue.js

How to multi upload files with tied input block?
And store this in an array of objects

This link may help you with the multiupload part, the only thing that you need to change is the addFile part. We just need to modify it a bit.
First of all, modify the state to be const state = reactive({files, fileName: ''}) and then the addFiles function to this:
const addFiles = (event) => {
const file = event.target.files[0]
const blob = file.slice(0, file.size, file.type);
const newFile = new File([blob], state.fileName, {type: file.type});
state.files.push(newFile)
}
If you want several inputs, then just modify the addFiles state.fileName to change it to an array and use state.fileNames[index] to use that name.

Related

How to send multiple byteIO files from Flask endpoint to Vue using axios and file encoding [duplicate]

This question already has answers here:
Creating a BLOB from a Base64 string in JavaScript
(15 answers)
Closed 11 months ago.
TL;DR
Flask:
docx --> bytesIO --encodebytes()--> bytes --decode()--> string --> array containing multiple of those string.
Vue:
array containing those strings --?--> blob
Question
I am trying to return multiple byteIO files from Flask endpoint to my Vue application at once.
Based on this SO question, it may be done by converting the byteIO files to string using bytesencode() and .decode().
Then the string is attached to an array and json serialized.
I don't know how it can be done however to reverse the convestion in Vue back to a necessary blob object (which will be downloaded).
Any suggestions on how to accomplish this?
How I create my bytesIO document files from docx template (my code is heavily inspired by snakecharmerb's answer in this post):
def from_template_multiple(context): # context is a dict containing custom attributes to be rendered in the document
template = DocxTemplate(template_document.docx')
# Create in-memory buffer
target_file = BytesIO()
# Render template and save to the buffer
template.render(context)
template.save(target_file)
# Reset the buffer's file-pointer to the beginning of the file
target_file.seek(0)
# return target file instead of send_file directly
return target_file
My flask route that receives the axios call that receives the context attributes from Vue. The part with the file encoding is from this answer.
#hagis_api_bp.route('/docx/multiple', methods=['POST'])
def generate_word_multiple():
request_json = request.get_json()
# array to store blob derivations
blob_array = []
for item in request_json['body']:
context = json.loads(item)
target_file = process.from_template_multiple(context)
# encode as base64
from base64 import encodebytes
encoded_file = encodebytes(target_file.getvalue()).decode('ascii')
# append target file to blob array
blob_array.append(encoded_file)
return jsonify({'result': blob_array})
And finally the Vue part. This axios call is used to send the context information (json) and here I want to return the blob_array and then revert the encoding process to receive the "raw" blob files.
// axios request + file download
axios({
url: 'docx/multiple',
data: {body: body_array},
method: 'POST',
}).then((response) => {
// looping over each element in response.data (each converted bytesIO string)
response.data['result'].forEach((element) => {
// convert string to blob here ?
// download blob as docx file
const url = window.URL.createObjectURL(new Blob([converted_element])); // --> using result from missing conversion above
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'title.docx');
document.body.appendChild(link);
link.click();
});
});
I was able to solve the problem. The following axios request does the trick.
This question was very helpful: Creating a BLOB from a Base64 string in JavaScript
// axios request + file download
axios({
url: 'docx/multiple',
data: {body: body_array},
method: 'POST',
}).then((response) => {
response.data['result'].forEach((element) => {
console.log(element)
// decode string to blob --> solution to question
const byteCharacters = atob(element);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
console.log(byteArray)
const url = window.URL.createObjectURL(new Blob([byteArray]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'test.docx');
document.body.appendChild(link);
link.click();
});
});

Agora.io Record Audio from LiveStream

I try to make a group Audio recorder with Agora.io, so I first need to create an empty .aac audio file so that I can record the audio on this File.
I use the react-native-fetch-blob library to handle the File System.
Here is my code for Recording:
const handleAudio = async () => {
const fs = RNFetchBlob.fs;
const dirs = fs.dirs;
if (!startAudio) {
fs.createFile(dirs.DocumentDir + '/record.aac', 'foo', 'utf8').then(() => {
_engine?.startAudioRecording(
dirs.DocumentDir + '/record.aac',
AudioSampleRateType.Type44100,
AudioRecordingQuality.Medium,
);
setStartAudio(true);
});
} else {
_engine?.stopAudioRecording();
}
};
The problem is that the file 'record.aac' always stays the same and the Agora.io recorder does not update this new file, it remains with 'foo'...
The startAudioRecording function expect a directory instead of a file.
Example: /sdcard/emulated/0/audio/aac.
It also returns a promise that you can check for the result.

How to use the sharp library to resize a Parse file img?

I have a Parse Cloud afterSave trigger from where I can access the obj and inside the obj a field that has a store parse file img.
I want to use sharp to resize it and save it in another field but I'm struggling and getting an error when I use sharp. Here is a summary of the code I already have inside the cloud trigger:
let file = obj.get("photo");
sharp(file)
.resize(250, 250)
.then((data) => {
console.log("img-----", data);
})
.catch((err) => {
console.log("--Error--", err);
});
After some research, I managed to figure out how to create Parse Cloud afterSave trigger which resizes and then saves the img, I couldn't find much information on it so ill post my solution so others can use it if it's helpful.
Parse.Cloud.afterSave("Landmarks", async (req) => {
const obj = req.object;
const objOriginal = req.original;
const file = obj.get("photo");
const condition = file && !file.equals(objOriginal.get("photo"));
if (condition) {
Parse.Cloud.httpRequest({ url: file.url() })
.then((res) => {
sharp(res.buffer)
.resize(250, 250, {
fit: "fill",
})
.toBuffer()
.then(async (dataBuffer) => {
const data = { base64: dataBuffer.toString("base64") };
const parseFile = new Parse.File(
"photo_thumbnail",
data
);
await parseFile.save();
await obj.save({ photo_thumb: parseFile });
})
.catch((err) => {
console.log("--Sharp-Error--", err);
});
})
.catch((err) => {
console.log("--HTTP-Request-Error--", err);
});
} else {
console.log("--Photo was deleted or did not change--");
}
});
So to break this down a bit, what i did first was get the obj and the objOriginal so i can compare them and check for a change in a specific field. This condition is necessery since in my case i wanted to save the resized img in parse which would cause an infinite loop otherwise.
After that i did a Parse.Cloud.httpRequest({ url: file.url()}).then() which is the way i found to get the buffer from the photo. The buffer is stored inside res.buffer and we need it for sharp.
Next i use sharp(res.buffer) since sharp also accepts buffers and resize it to the desired dimensions (i used the fit config for it). Then we turn the resulted img into another buffer using .toBuffer(). Furthermore, i use a .then().catch() blocks and if sharp is succesful i turned the outputed buffer into a base64 and passed it in Parse.File(), note that the specific syntax { base64: 'insert buffer here' } is important.
And finally i just save the file and the obj. Is this the best way to do it, absolytely not, but its the one i found that works. Another possible solution is instead of using buffers and base64 is to create a temporary dir which you save the images there, use them and then delete the directory. I tried this as well but had issues making it work.

Getting Undefined while fetching particular key value from get method using Lodash

I have following array of data.
const filterToolTips = [{
remember_tip: 'some remember tip data.'
},
{
background_tip: 'some background tip data'
},
{
remember_on: 'some remember on tip data'
},
{
remember_off: 'some remember off data.'
},
{
background_on: 'some background on data '
}
];
I am trying to get each key text for different use case.
So, I am using lodash, But, It is showing undefined.
const toolText = get(filterToolTips,'remember_tip');
console.log('toolTipText', toolTipText); // 'toolTipText', undefined
Even I tried find too.
Any suggestions?
Use _.find() with _.has() to find an object with the requested key, and then use _.get() to take the value:
const filterToolTips = [{"remember_tip":"some remember tip data."},{"background_tip":"some background tip data"},{"remember_on":"some remember on tip data"},{"remember_off":"some remember off data."},{"background_on":"some background on data "}];
const key = 'remember_tip';
const toolText = _.get(
_.find(filterToolTips, o => _.has(o, key)),
key
);
console.log(toolText);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
However, this is a really weird data structure, and you should transform it (or ask the server guys to send you something more usable). This solution converts the data structure to a Map, and then gets the value:
const filterToolTips = [{"remember_tip":"some remember tip data."},{"background_tip":"some background tip data"},{"remember_on":"some remember on tip data"},{"remember_off":"some remember off data."},{"background_on":"some background on data "}];
const tipsMap = new Map(Object.entries(Object.assign({}, ...filterToolTips)));
const key = 'remember_tip';
const toolText = tipsMap.get(key);
console.log(toolText);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Remove / clear all entities from a contentState

I'm trying to remove all entities from a contentState.
What would be the prefered way to do that?
Not sure what the canonical way is, but I've been able to do it by using Modifier.applyEntity(): https://draftjs.org/docs/api-reference-modifier#applyentity.
You basically need to loop through all the blocks, and use that method on the entire range of text in each block. So something like this:
import {Modifier, SelectionState} from 'draft-js';
function clearEntityRanges(contentState){
contentState.getBlockMap().forEach(block => {
const blockKey = block.getKey();
const blockText = block.getText();
// You need to create a selection for entire length of text in the block
const selection = SelectionState.createEmpty(blockKey);
const updatedSelection = selection.merge({
//anchorOffset is the start of the block
anchorOffset: 0,
// focustOffset is the end
focusOffset: blockText.length
})
Modifier.applyEntity(contentState, updatedSelection, null);
});
return contentState
}