How to set file name and extension to the original when inserting a file with full url or URI in CollectionFS? - meteor

Model code:
ProfileImage = new FS.Collection('profileImage', {
stores: [
new FS.Store.FileSystem('profile-image')
],
filter: {
maxSize: 524288,
allow: {
extensions: ['png', 'jpg', 'jpeg'],
contentTypes: ['image/png', 'image/jpg', 'image/jpeg']
}
}
});
Insertion code:
ProfileImage.insert('http://graph.facebook.com/' + user.services.facebook.id + '/picture/?type=large', function(error, imageObj) {
console.log(imageObj);
});
with that code I get a file name like this: profileImage-iiGE2ouSifuu3iLjq-undefined .
the name is undefined and without extension at all.

Try this (copied from a project of mine. this works):
//this is the event for when you select an image
'change .yourfileinput': function (event, template) {
FS.Utility.eachFile(event, function (file) {
var yourFile = new FS.File(file);
Images.insert(yourFile, function (err, fileObj) {
var fileUrl = '/cfs/files/profile-image/'+fileObj._id;
Session.set('fileUrl', fileUrl);
});
});
},
//form submit event
"submit .your-form-class": function (event) {
var whichUser = Meteor.userId() //or you could just write this inside the method call instead of adding a variable
var profilePicture = Session.get('fileUrl');
Meteor.call("yourMethod", whichUser, profilePicture);
}
Of course, you need to play on it/customise to your needs. ^ is for default file path of cfs:filesystem.
I switched to gridfs though and I highly recommend it.
Edit your question with all your code if it doesn't work and we'll find a solution. File upload was the biggest problem I encountered along the way.

Related

How to insert a file, server-side, into images, fs.files and fs.chunks -GridFS (Ostrio/files)

I am using Ostrio/files also known as meteor-files (from VeliovGroup or keenethics) on the server-side to insert a file to db.images, db.fs.files and db.fs.chunks. My code only manages to insert a record only in db.images and nothing on fs.files and fs.chunks. My code is as follows:
Images.write(this.bodyParams.file, {
fileName: 'SignUpTermsAndConditions_' + this.bodyParams.name,
fielId: 'abc123myId', //optional
type: 'application/vnd.oasis.opendocument.text',
meta: {owner: this.userId,createdAt: new Date()}
}, function (error, fileRef) {
if (error) {
throw error;
} else {
console.log(fileRef.name + ' is successfully saved to FS. _id: ' + fileRef._id);
}
});
I am able to insert a file from the client into db.images, db.fs.files and db.fs.chunks using the following code:
Images.insert({
file: file, // where var file = e.currentTarget.files[0];
fileName: fileName + e.currentTarget.files[0].name,
onStart: function () {
},
onUploaded: function (error, fileObj) {
if (error) {
alert('Error during upload: ' + error);
} else {
}
},
streams: 'dynamic',
chunkSize: 'dynamic'
});
The server code as per the first snippet above is one that is not working correctly or as expected.Please help.
For info: how I setup my gridFS is as per
this link. My Images.write as per my second code snippet above is as per the code in
this link. In short I am following the documentation but my server Images.write is not working as expected.Please help!
I found the answer to my question. I set the fourth parameter to true i.e proceedAfterUpload=true and records are inserted in db.fs.files and db.fs.chunks. This is as per the write method documentation, it is slightly vague though. Here is the amended code:
Images.write(this.bodyParams.file, {
fileName: 'SignUpTermsAndConditions_' + this.bodyParams.name,
fielId: 'abc123myId', //optional
type: 'application/vnd.oasis.opendocument.text',
meta: {owner: this.userId,createdAt: new Date()}
}, function (error, fileRef) {
if (error) {
throw error;
} else {
console.log(fileRef.name + ' is successfully saved to FS. _id: ' + fileRef._id);
}
},proceedAfterUpload=true);
That's it.
PS: Make sure this.bodyParams.file is a buffer so that the inserted file is not corrupt - thanks to #dr.dimitru for advising me on inserting a buffer.

Meteor: collection helpers or transform on FS.Collection?

With dburles:collection-helpers package you can add collection helpers on any Mongo.collection. But I can't do that on FS.Collection. I get TypeError: Object [object Object] has no method 'helpers'. Transform function doesn't work either.
var createUploader = function(fileObj, readStream, writeStream) {
fileObj.uploadedBy = Meteor.users.find({_id: fileObj.uploader});
readStream.pipe(writeStream);
};
Photos = new FS.Collection("photos", {
stores: [
new FS.Store.GridFS("photos", {transformWrite: createUploader})
],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
Can't do this? Notice when a photo is inserted from the client FS.File gets userId, hence fileObj.uploadedBy = Meteor.users.find({_id: fileObj.uploader});
Ok I know this is not the not-so-easy solution I was looking for. Since I am using publish-composite package. I can just publish users' data(only profile field) with photos. And on the client I can do template helper like this:
Template.photo.helpers({
photoUploader: function() {
var currentPhoto = Photos.findOne();
var user = Meteor.users.findOne({_id: currentPhoto.uploader});
return user.profile.name;
},
});
and
<template name="photos">
{{#each photos}}
{{> photo}}
{{/each}}
...
then
<template name="photo">
{{photoUploader}}
...
matb33-collection-helpers package works by applying a transform function to a collection. CollectionFS already has its own transform function applied, therefore you cannot overwrite that with ones from the collection helpers package.
As suggested at the issue tracker
Since CFS already applies a transform, it would not be a good idea to use collection helpers. You should be able to do pretty much the same thing by extending the FS.File prototype with your own functions, though.
You could define custom functions on the prototype. The prototype will have access to other properties of the doc through this so you would basically have the same functionality with collection helpers.
Another option would be to store the file related information on the individual file object during the insert as metadata such as:
Template.photoUploadForm.events({
'change .photoInput': function(event, template) {
FS.Utility.eachFile(event, function(file) {
var newPhoto = new FS.File(file);
newPhoto.metadata = {uploadedBy: Meteor.user().profile.name};
Photos.insert(newPhoto, function (err, fileObj) {
if (!err) console.log(fileObj._id + " inserted!")
});
});
}
});
Your code can also be rewritten to implement a beforeWrite filter instead of a transformWrite as in
Photos = new FS.Collection("photos", {
stores: [
new FS.Store.GridFS("photos", {
beforeWrite: function (fileObj) {
fileObj.metadata = {uploadedBy: Meteor.user().profile.name};
}
})
],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
Finally, you can opt to storing the ID of the user and publishing a reactive join
Photos = new FS.Collection("photos", {
stores: [
new FS.Store.GridFS("photos", {
beforeWrite: function (fileObj) {
fileObj.metadata = {
uploadedBy: Meteor.userId()
};
}
})
],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
And for the publication, you can use reywood:publish-composite
Meteor.publishComposite('photosWithUsers', function() {
return {
find: function() {
return Photos.find();
},
children: [
{
find: function(photo) {
return Meteor.users.find(photo.uploadedBy, {
fields: {username: 1, 'profile.name': 1}
});
}
}
]
};
});
Of course on the client, you need to subscribe to the photosWithUsers publication.
Now to access that information in the client, since you cannot apply a transform or a helper on the collectionFS documents, you can create a global template helper:
Template.registerHelper('getUsername', function(userId) {
check(userId, String);
var user = Meteor.users.findOne(userId);
return user && user.profile.name + ' (' + user.username + ')';
});
Now you can use that helper in your templates:
<template name="somePhoto">
{{#with FS.GetFile "Photos" photo}}
<img src="{{url}}" alt="This photo has been uploaded by {{getUsername uploadedBy}}">
{{/with}}
</template>
Template.somePhoto.helpers({
photo: function() {
return Photos.findOne();
}
})

Meteor GridFS 403 forbidden

Possible duplicate: Meteor collectionfs insert server side
I have multiple image collections using GridFS to store files. If I use "Images" as name for the collection everything works fine, but as soon as I change the name I'm getting GET http://localhost:3000/cfs/files/PlayerImages/zo4Z7rnYLb32MLYkM/taylor.jpg 403 (Forbidden)
(And for example, this one does work: http://localhost:3000/cfs/files/Images/7j9XAEebGctuivGhz/see-more.png)
This is how I defined my collections:
function createImageCollection(name,transform){
var collectionName = name + 's';
var storeName = name + 'Store';
var options = {
filter: {
allow: {
contentTypes: ['image/*'],
extensions: ['png', 'PNG', 'jpg', 'JPG', 'jpeg', 'JPEG']
}
}
};
if (Meteor.isServer) {
storeOptions = {
path: process.env.PWD + "/public"
};
// only add the transform when graphicsmagick is available
if(gm.isAvailable && typeof transform === 'function'){
storeOptions.transformWrite = transform;
}
options.stores = [new FS.Store.GridFS(storeName,storeOptions)];
} else {
options.stores = [new FS.Store.GridFS(storeName)];
}
return new FS.Collection(collectionName,options);
}
// and finally create them
// THIS FIRST ONE WORKS JUST FINE
Images = createImageCollection('Image',imageResizeTimeline); // default resize is timeline, nothing bigger then that?
BackgroundImages = createImageCollection('BackgroundImage',imageResizeBackground);
PlayerImages = createImageCollection('PlayerImage',imageResizePlayer);
LogoImages = createImageCollection('LogoImage',imageResizeLogo);
And I also added allow/deny rules for each collection:
var ImagePermissions = {
insert: function () {
return true;
},
update: function () {
return true;
},
download: function () {
return true;
},
remove: function () {
return false;
},
fetch: null
};
Images.allow(ImagePermissions);
PlayerImages.allow(ImagePermissions);
BackgroundImages.allow(ImagePermissions);
LogoImages.allow(ImagePermissions);
On a sidenote, I am using autoform to generate forms, but I don't think the problem is located in there because "Images" works.
Must I add this path to some "routing" or "config" files? Maybe "Images" is added by default? (This project is set-up by someone else, but I don't think I missed anything he did.)

How to get file url for specific store using collectionFS in meteor

How to get file url for specific store using collectionFS in meteor?
I need to retrieve it in my onrendered code:
var url = Images.findOne(filesList[index].id).url();
This return me default store for Images, but in Images i have two store:
Images = new FS.Collection("images", {
stores: [fullImage, previewImage],
filter: {
allow: {
contentTypes: ['image/*']
},
onInvalid: function (message) {
if (Meteor.isClient) {
toastr.warning("Impossibile salvare l'immagine a causa di: " + message);
} else {
console.log(message);
}
}
}
});
I need to retrieve previewImage, i cannot use tag code because i need to download it in background on the client..
Just found a simple solution:
Images.findOne(filesList[index].id).url({store: 'preview'});

How can I save an image to a temporary file to use later?

Here is my simple script to see if the image exists. Is there is any way I can save the image using the selector to see if it exists? This is my code:
var casper = require('casper').create();
casper.start('https://example.ws/', function() {
this.echo(this.getTitle());
});
casper.thenOpen('https://example.ws/login.html', function() {
this.echo(this.getTitle());
if (this.exists('img#cpt_img')) {
this.echo('the heading exists');
}
});
casper.run();
You can use the download() method:
this.download(
this.getElementAttribute('img#cpt_img', 'src'),
"my_image.png"
);

Resources