Recall CollectionFS file using Metadata (Meteor) - javascript

I am creating an application that allows uploading and displaying of images. The users can upload images and then all of the images are displayed on one page. The biggest issue is that all the images need to display under the name of the owner.
I am using CollectionFS to upload and store the files, this is my storeFile method:
Template.queueControl.events({
'change .fileUploader': function (e) {
var files = e.target.files;
for (var i = 0, f; f = files[i]; i++) {
console.log(Meteor.user().username);
ImageFS.storeFile(f, {username: Meteor.user().username});
}
}
});
I thought that I would be able to call the file back by using a query like this:
Template.studentModal.getImage = function(){
return ImageFS.find({username: Session.get("studentUsername")});
}
The setting and getting of the username work fine and as expected. It will not return any records though.
Thanks,
Skylar

You should convert the "file" to "FS.File" before calling "storeFile". Now you can add metadata like "owner" to an image.
This should work at least in Meteor 0.9:
Template.queueControl.events({
'change .fileUploader': function (e) {
var files = e.target.files;
for (var i = 0, f; f = files[i]; i++) {
var newFile = new FS.File(files[i]);
newFile.owner = Meteor.user().username;
Images.insert(newFile, function(err, fileObj) {});
}
}
});

You should store the userId and subscribe a publication that publishes the shown users, just with usernames.
I use https://github.com/englue/meteor-publish-composite for publication composition.

Related

Loop multiple files from input, save each file readAsDataURL data to array

I need your help with following problem:
I have HTML input which supports multiple files;
I upload let's say 5 files;
Each file is processed: it is readAsDataURL by FileReader and data of file is saved to object(there will be other params saved too, that is why object), which is pushed to array.
After I run flow I described, length of final array is NOT changed.
I believe problem is in async behaviour, but I cannot understand how should I change code to make it work, that is why I ask you for a help. Please find code below:
var controls = document.getElementById('controls');
function processUploadedFilesData(files) {
if (!files[0]) {
return;
};
var uploads = [];
for (var i = 0, length = files.length; i < length; i++) {
(function(file) {
var reader = new FileReader();
//I need object, as other params will be saved too in future;
var newFile = {};
reader.readAsDataURL(file);
reader.onloadend = function(e) {
newFile.data = e.target.result;
uploads.push(newFile);
}
})(files[i]);
}
return uploads;
}
controls.addEventListener('change', function(e) {
var uploadedFilesOfUser = processUploadedFilesData(e.target.files);
alert(uploadedFilesOfUser.length);
});
Codepen example - https://codepen.io/yodeco/pen/xWevRy

How to save uploaded image to IndexedDB Javascript

Am using file upload controller to browse images and the selected images should be previewed in the page as image thumbnails.
<input type="file" id="imageSelector" multiple="multiple" />
var uploadImageCtrl = document.querySelector('#imageSelector');
uploadImageCtrl.addEventListener('change', function () {
var files = this.files;
for(var i=0; i<files.length; i++){
preview(this.files[i]);
}
}, false);
After selecting few images, go to next page and do some action. And when going back from that page, all the image previews should be there. I thought of saving these images to IndexedDB, before going to next page. But am not sure how to code for IndexedDB in this case.
Can anyone help me?
File objects are cloneable and can be saved to Indexed DB, either as records on their own or as part of other records.
This example just saves an array of files as a single record (key is "key") to an object store named "images":
// Call with array of images; callback will be called when done.
function save(array_of_files, callback) {
openDB(function(db) {
var tx = db.transaction('images', 'readwrite');
tx.objectStore('images').put(array_of_files, 'key');
tx.oncomplete = function() { callback(); };
tx.onabort = function() { console.log(tx.error); };
});
}
// Callback will be called with array of images, or undefined
// if not previously saved.
function load(callback) {
openDB(function(db) {
var tx = db.transaction('images', 'readonly');
var req = tx.objectStore('images').get('key');
req.onsuccess = function() {
callback(req.result);
};
});
}
function openDB(callback) {
var open = indexedDB.open('my_db');
open.onupgradeneeded = function() {
var db = open.result;
db.createObjectStore('images');
};
open.onsuccess = function() {
var db = open.result;
callback(db);
};
open.onerror = function() { console.log(open.error); };
}
One possible gotcha: HTMLInputElement's files is not an Array itself but an array-like type called FileList. You can convert it to an array with e.g. Array.from(e.files), but a FileList can be cloned (and therefore stored in IDB) so this should "just work".

Disable the possibility to upload files for user

I'm building a service for users where I must have private files.
Actually, with Cloud Code, I can control the download flux, through a function. But, how I can prevent a hacker to use the javascript console and upload his files ? He will get a link, which he can share with anyone without restriction and at my charges.
const file = Parse.File('hackerFile', hackerFileArray);
file.save().then(() => console.log(file.url)) // Now, he have a free file hosting.
Is there a way to completely remove this feature for everyone, except the master key ?
Example of hosting a file on http://todolist.parseapp.com/
Open the console in your browser then
var script = document.createElement('script');
script.src = '//www.parsecdn.com/js/parse-1.6.14.min.js'; // Because of their version.
document.head.appendChild(script);
Parse.initialize("0Oq3tTp9JMvd72LOrGN25PiEq9XgVHCxo57MQbpT", "vUFy2o7nFx3eeKVlZneYMPI2MBoxT5LhWNoIWPja"); // Found in their sources
var reader = new FileReader();
var input = document.createElement('input');
input.type = 'file';
document.body.appendChild(input);
// Then choose a file from the browser. I choosen a picture.
reader.onloadend = function() {
var file = new Parse.File('hackFile', {base64: reader.result});
file.save().then(function() {
console.log(file.url());
})
};
reader.readAsDataURL(input.files[0]);
Then you have a link. I got http://files.parsetfss.com/ae2ddbce-9cc0-4e1a-a16d-52ec5fdb7570/tfss-8fccfba0-ccf7-41cd-8f42-75f0a3478262-hackFile
Haven't tried this, but think it could work:
1) Add a beforeSave function on whatever class you're looking to prevent this behavior on.
2) In the beforeSave, check request.object.dirtyKeys() and iterate through each of those keys on the newly created object.
3) If the value associated with one of those dirtyKeys is a file, don't allow the file to save: response.error
Parse.Cloud.beforeSave(Parse.User, function(request, response) {
var dirtyKeys = request.object.dirtyKeys();
for (var i = 0; i < dirtyKeys.length; ++i) {
var dirtyKey = dirtyKeys[i];
if (isUnwantedFile(request.object, dirtyKey)) {
response.error("User is not allowed to store files");
return;
}
}
response.success();
});
//note this function is untested -- I'm not sure what type a user-created file would be,
//but basically if you can figure that out, substitute it in here
function isUnwantedFile(obj, key){
return typeof obj[dirtyKey] === Parse.File
}

Drag & drop - getData() returns empty string

I'm trying to create a simple web app that could read and display a plain text file. I want it to open the files just by dragging and dropping them on a div.
This is my code that handles the drop event:
dropHere.addEventListener('drop', function(e) {
e.preventDefault();
var data = e.dataTransfer.getData('text');
console.log(data);
});
Pretty straightforward, huh? Only... it logs an empty string.
I'm really confused. Am I missing some trivial thing?
e.dataTransfer.files[0] returns a File object, with the correct filename, size, and even file type.
OK, so I went through a few pages that allow drag & drop file uploading and found a solution to this problem. Use FileReader instead of getData().
This is how the code looks now (generated from CoffeeScript):
var loadFile;
empty.addEventListener('drop', function(e) {
var file, files, i, len, results;
e.preventDefault();
files = e.dataTransfer.files;
results = [];
for (i = 0, len = files.length; i < len; i++) {
file = files[i];
results.push(loadFile(file));
}
return results;
});
loadFile = function(file) {
var reader;
reader = new window.FileReader;
reader.onload = function(e) {
return content.innerHTML = reader.result;
};
return reader.readAsText(file);
};
Everything works fine now.

Is Parse's Javascript file upload broken?

I've been trying to save a user-uploaded image to parse for the longest time, and nothing seems to work -- even when following their documentation.
Below is the handler I use for the onChange() on a multiple file upload. At first I was concerned about multiple file uploads, but at this point just saving one image doesn't work.
function fileHandler(event) {
var files = event.target.files;
stopPictures = [];
$("#stop-img-container").empty();
if (files[0] != null) {
$("#stop-img-container").show();
for (var i = 0; i < files.length; i++) {
var file = files[i];
var picReader = new FileReader();
picReader.addEventListener("load",function(event){
var picFile = event.target;
var image = $("<img/>",{
"title": picFile.name,
"class": "stop-image",
"src": picFile.result
}).appendTo("#stop-img-container");
var name = picFile.name;
var dataFile = picFile.result;
var base64str = dataFile.substring(dataFile.indexOf("base64,")+7,dataFile.length);
var parseFile = new Parse.File(name,{base64:base64str}); // saving logs 404 Not Found from POST to "http://api.parse.com/1/files"
var parseFile = new Parse.File(name,dataFile); // saving logs "Uncaught Creating a Parse.File from a String is not yet supported."
var parseFile = new Parse.File(name,file); // saving logs 404 Not Found from POST to "http://api.parse.com/1/files"
var parseFile = new Parse.File(name,base64str); // saving logs "Uncaught Creating a Parse.File from a String is not yet supported."
parseFile.save().then(function (savedFile) {
stopPictures.push(savedFile);
alert("worked");
});
});
picReader.readAsDataURL(file);
}
} else {
$("#stop-img-container").hide();
}
}
There's some extraneous stuff here, but basically it collects the user's selected files, displays them for them once they've finished loading, and then creates them as a Parse file. I've left it in to show that at least something is working as it properly locally stores and previews the user's selected files.
I have included three different ways of creating the same Parse file. However, all of them fail when I try to save to Parse in any way.
Parse's Javascript API docs says that any of these should work fine. But they lie, or I'm an idiot.
Anyone have any idea why this doesn't seem to work? Seems like a pretty critical aspect of their API is broken completely -- which I find hard to imagine.
EDIT: I'm also positive I'm properly parsing (lower case p) the base64 string as this site confirms the appropriate image and works.
I experienced the same problem.
Finally I found what causes the problem.
It's a "file name".
I suspect the file name in tuckerchapin's example is null.
var name = picFile.name;
I wrote the example with React.
this code works fine.
class ImageUpload extends React.Component {
onChange(e) {
var file = e.target.files[0];
var parseFile = new Parse.File(file.name, file);
Parse.User.current().set("icon",parseFile);
Parse.User.current().save();
}
handleSubmit(e) {
e.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="file" onChange={this.onChange.bind(this)} />
</form>
);
}
}

Categories

Resources