Simple image uploading with collection fs - meteor

I have installed collection fs package to process my image uploads and so far,i have not uploaded a single image successfully.
I have this code in my event
'change .ip': function(event, template) {
FS.Utility.eachFile(event, function(file) {
var yourFile = new FS.File(file);
SchoolImages.insert(yourFile, function (err, fileObj) {
if (err){
// handle error
alert('error');
} else {
// handle success depending what you need to d
alert('success');
}
});
});
}
This is my html
<input type="file" class="ip form-control" name="sn_edit" value="">
This is my collections code
SchoolImages = new FS.Collection("SchoolImages", {
stores: [new FS.Store.FileSystem("SchoolImages", {path: "~/meteor_uploads"})]
});
if (Meteor.isServer) {
SchoolImages.allow({
insert: function (userId, doc) {
return false;
},
update: function (userId, doc, fieldNames, modifier) {
return false;
},
remove: function (userId, doc) {
return false;
}
});
SchoolImages.deny({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc, fieldNames, modifier) {
return true;
},
remove: function (userId, doc) {
return true;
}
});
}
When i try uploading an image,no image is uploaded and no collection is created. My code gives an error alert('error') - see the code above.
How should i rectify my code to upload an image successfully?.

You don't have to allow db operation inside in Meteor.isServer. You can directly write the collections code as follow.
SchoolImages = new FS.Collection("SchoolImages", {
stores: [new FS.Store.FileSystem("SchoolImages", {path: "~/meteor_uploads"})]
});
SchoolImages.allow({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc, fieldNames, modifier) {
return true;
},
remove: function (userId, doc) {
return true;
}
});
Generally I recommend to write this code inside the lib folder when you structure your project in different folders.

Related

ostrio:files with Dropbox on Meteor

I'm trying to setup ostrio:files to work with dropbox. Can someone please explain me how to do it?
I've registered on dropbox and generated token using ostrio:files manual but I don't know how to upload files to dropbox.
After upload, when I check local Images db there are all images information but I don't know how to send it to Dropbox.
After file select, it says “upload successful” but there are no files uploaded on Dropbox.
dropbox.js
import { Meteor } from 'meteor/meteor';
import { FilesCollection } from 'meteor/ostrio:files';
var Dropbox,
Request,
bound,
client,
fs,
Images = {};
if (Meteor.isServer) {
Dropbox = require("dropbox").Dropbox;
const fetch = require("node-fetch");
bound = Meteor.bindEnvironment(function (callback) {
return callback();
});
client = new Dropbox({
accessToken: "mytoken", // Use your token here
fetch: fetch,
});
}
Request = require("request");
fs = require("fs");
Images.files = new FilesCollection({
debug: false, // Change to `true` for debugging
storagePath: "assets/app/uploads/uploadedFiles",
collectionName: "uploadedFiles",
allowClientCode: false,
onAfterUpload: function (fileRef) {
// In onAfterUpload callback we will move file to DropBox
try {
var self = this;
var makeUrl = function (path, fileRef, version) {
client
.sharingCreateSharedLink({ path: path, short_url: false })
.then(function (response) {
bound(function () {
const url = response.url.replace("dl=0", "raw=1");
var upd = {
$set: {},
};
upd["$set"]["versions." + version + ".meta.pipeFrom"] = url;
upd["$set"]["versions." + version + ".meta.pipePath"] = path;
self.collection.update(
{
_id: fileRef._id,
},
upd,
function (error) {
if (error) {
return console.error(error);
}
// Unlink original files from FS after successful upload to DropBox
self.unlink(self.collection.findOne(fileRef._id), version);
}
);
});
})
.catch(function (error) {
console.error(error);
});
};
var writeToDB = function (fileRef, version, data) {
// DropBox already uses random URLs
// No need to use random file names
client
.filesUpload({
path: "/" + fileRef._id + "-" + version + "." + fileRef.extension,
contents: data,
autorename: false,
})
.then(function (response) {
bound(function () {
// The file was successfully uploaded, generating a downloadable link
makeUrl(response.path_display, fileRef, version);
});
})
.catch(function (error) {
bound(function () {
console.error(error);
});
});
};
var readFile = function (fileRef, vRef, version) {
fs.readFile(vRef.path, function (error, data) {
bound(function () {
if (error) {
return console.error(error);
}
writeToDB(fileRef, version, data);
});
});
};
var sendToStorage = function (fileRef) {
_.each(fileRef.versions, function (vRef, version) {
readFile(fileRef, vRef, version);
});
};
sendToStorage(fileRef);
} catch (error) {
// There was an error while uploading the file to Dropbox, displaying the concerned file
console.log(
"The following error occurred while removing " + fileRef.path
);
// Removing the file from the file system
fs.unlink(fileRef.path, function (error) {
if (error) {
console.error(error);
}
});
// Removing the file from the collection
Images.files.remove(
{
_id: fileRef._id,
},
function (error) {
if (error) {
console.error(error);
}
}
);
}
},
onBeforeRemove: function (cursor) {
return false;
},
interceptDownload: function (http, fileRef, version) {
// Files are stored in Dropbox, intercepting the download to serve the file from Dropbox
var path, ref, ref1, ref2;
path =
(ref = fileRef.versions) != null
? (ref1 = ref[version]) != null
? (ref2 = ref1.meta) != null
? ref2.pipeFrom
: void 0
: void 0
: void 0;
if (path) {
// If file is moved to DropBox
// We will pipe request to DropBox
// So, original link will stay always secure
Request({
url: path,
headers: _.pick(
http.request.headers,
"range",
"accept-language",
"accept",
"cache-control",
"pragma",
"connection",
"upgrade-insecure-requests",
"user-agent"
),
})
.on("response", function (response) {
if (response.statusCode == 200) {
response.headers = _.pick(
response.headers,
"accept-ranges",
"cache-control",
"connection",
"content-disposition",
"content-length",
"content-type",
"date",
"etag"
);
response.headers["Cache-control"] =
"only-if-cached, public, max-age=2592000";
}
})
.pipe(http.response);
return true;
} else {
// While file is not yet uploaded to DropBox
// We will serve file from FS
return false;
}
},
});
// if (Meteor.isServer) {
// // Intercept File's collection remove method to remove file from DropBox
// var _origRemove = Images.files.remove; // Catching the original remove method to call it after
// Images.files.remove = function (search) {
// var cursor = this.collection.find(search);
// cursor.forEach(function (fileRef) {
// _.each(fileRef.versions, function (vRef) {
// var ref;
// if (
// vRef != null
// ? (ref = vRef.meta) != null
// ? ref.pipePath
// : void 0
// : void 0
// ) {
// client
// .filesDeleteV2({ path: vRef.meta.pipePath })
// .catch(function (error) {
// bound(function () {
// console.error(error);
// });
// });
// }
// });
// });
// // Call original method
// _origRemove.call(this, search);
// };
// }
export default Images; // import in other files
uploadForm.js
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import Images from '/lib/dropbox.js';
Template.uploadForm.onCreated(function () {
this.currentUpload = new ReactiveVar(false);
});
Template.uploadForm.helpers({
currentUpload() {
return Template.instance().currentUpload.get();
}
});
Template.uploadForm.events({
'change #fileInput'(e, template) {
console.log("file opened");
if (e.currentTarget.files && e.currentTarget.files[0]) {
// We upload only one file, in case
// multiple files were selected
const upload = Images.files.insert({
file: e.currentTarget.files[0],
streams: 'dynamic',
chunkSize: 'dynamic'
}, false);
upload.on('start', function () {
template.currentUpload.set(this);
console.log("start upload");
});
upload.on('end', function (error, fileObj) {
if (error) {
alert(`Error during upload: ${error}`);
} else {
alert(`File "${fileObj.name}" successfully uploaded`);
}
template.currentUpload.set(false);
});
upload.start();
}
}
});
uploadForm.html
<template name="uploadForm">
{{#with currentUpload}}
Uploading <b>{{file.name}}</b>:
<span id="progress">{{progress.get}}%</span>
{{else}}
<input id="fileInput" type="file" />
{{/with}}
</template>
when i try to upload I get this in server console
[FilesCollection] [File Start Method] img.png - ms75Ah76svrFEGh2f
[FilesCollection] [Upload] [DDP Start Method] Got #-1/1 chunks, dst: img.png
[FilesCollection] [Upload] [DDP] Got #1/1 chunks, dst: img.png
[FilesCollection] [Upload] [DDP] Got #-1/1 chunks, dst: img.png
[FilesCollection] [Upload] [finish(ing)Upload] -> tmp\ms75Ah76svrFEGh2f.png
[FilesCollection] [Upload] [finish(ed)Upload] -> tmp\ms75Ah76svrFEGh2f.png
The following error occurred while removing tmp\ms75Ah76svrFEGh2f.png
[FilesCollection] [remove({"_id":"ms75Ah76svrFEGh2f"})]
[FilesCollection] [unlink(ms75Ah76svrFEGh2f, undefined)]
[FilesCollection] [_preCollectionCursor.observe] [changed]: ms75Ah76svrFEGh2f
[FilesCollection] [_preCollectionCursor.observe] [removed]: ms75Ah76svrFEGh2f

How to save to /public in Meteor with cfs:filesystem and collectionfs?

/lib/collections/images.js
var imageStore = new FS.Store.FileSystem("images", {
// what should the path be if I want to save to /public/assets?
// this does not work
path: "/assets/images/",
maxTries: 1
});
Images = new FS.Collection("images", {
stores: [imageStore]
});
Images.deny({
insert: function() {
return false;
},
update: function() {
return false;
},
remove: function() {
return false;
},
download: function() {
return false;
}
});
Images.allow({
insert: function() {
return true;
},
update: function() {
return true;
},
remove: function() {
return true;
},
download: function() {
return true;
}
});
/client/test.html
<template name="test">
<input type="file" name="myFileInput" class="myFileInput">
</template>
/client/test.js
Template.test.events({
'change .myFileInput': function(event, template) {
FS.Utility.eachFile(event, function(file) {
Images.insert(file, function (err, fileObj) {
if (err){
// handle error
} else {
// handle success
}
});
});
},
});
For the path, if I use:
path: "/public/assets/images",
Error: EACCES, permission denied '/public'
path: "/assets/images",
Error: EACCES, permission denied '/assets'
path: "~/assets/images",
This works, but it saves the image to /home/assets/images on my Linux machine. The path isn't relative to the Meteor project at all.
I have resolved this issue using meteor-root package:
https://atmospherejs.com/ostrio/meteor-root
Files = new FS.Collection("files", {
stores: [new FS.Store.FileSystem("images", {path: Meteor.absolutePath + '/public/uploads'})]
});
So now it stores files in app/public/uploads/
Hope this helps!
/ doesn't stand for root of your site. / stands for root of your system. The meteor app runs as your user.
What you'll want do, is use a relative path. It's possible that the collectionFS fs.write operation isn't done from the apps root. So alternatively you could use path: process.env.PWD + '/public/assets/images'
You can use
var homeDir = process.env.HOMEPATH;
tmpDir: homeDir + '/uploads/tmp'

Cannot insert relationship ID into Aldeed's Autoform MeteorJS framework

New to MeteorJS. I started making a novel Clan/Samurai app to see if I could understand how mongo/meteor and Autoforms handle relationships. I'm trying to make clans and samurai relate to each other so that each Samurai has a specific clan.
I'm attempting to insert the clan data into the Samurai identity. I seem to not be able to.
I've read the following and still seem generally confused on how to implement this. I've tried before, onsuccess, onsubmit hooks. I've attempted to set the schema up so that it works. I mostly get AutoForm undefined or Schema undefined...tons of errors it seems. I've read that it should be client.
I can console log and get it to render but I can't add the new items to the collection.
Random Github made for viewing pleasure
https://github.com/qtheninja/SamuraiAttack
https://github.com/aldeed/meteor-collection2/issues/31
How to add a relationship or reference with AutoForm in Meteor?
Meteor Autoform package with collection2 does not submit the form
//lib/collections/clans.js
Clans = new Mongo.Collection('clans');
Clans.attachSchema(new SimpleSchema({
name: {
type: String,
label: "Clan Name",
max: 100
}
}));
if (Meteor.isServer) {
Clans.allow({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc, fieldNames, modifier) {
return true;
},
remove: function (userId, doc) {
return true;
}
});
}
//lib/collections/samurais.js
Samurais = new Mongo.Collection('samurais');
Samurais.attachSchema(new SimpleSchema({
title: {
type: String,
label: "Title",
max: 100
},
description: {
type: String,
label: "Description",
optional: true
},
clan: {
type: Clans
}
}));
if (Meteor.isServer) {
Samurais.allow({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc, fieldNames, modifier) {
return true;
},
remove: function (userId, doc) {
return true;
}
});
}
//client/template/clans/createClan.html
<template name="CreateClan">
<h1>Create New Clan</h1>
{{> quickForm
collection="Clans"
id="insertClanForm"
type="insert"
buttonContent="Create"
}}
<div>
{{> ListClans }}
</div>
</template>
//client/main.js
AutoForm.addHooks('insertSamuraiForm', {
before: {
insert: function(doc, template) {
//modify the document here
doc.clanid= 45;
doc.dance ="start again";
console.log("running after hook");
return true;
}
}
});
AutoForm.hooks({
insertSamuraiForm: {
before: {
insert: function(doc, template) {
//modify the document here
doc.projectid= "random";
doc.dance ="start again";
console.log('this is asecond form');
}
}
}
});
I was able to resolve this issue by doing the following.
Return on object using 'before' hook
Router.current().params._id
a. I was using iron router and in my url was clans/_id/samurai/new
added 'dance' and 'clanid' as apart of the simpleschema. I had neglected to include them as apart of the schema so I was getting the console.log to work but not the data to be apart of the object.
//client/lib/main.js (alterations)
before: {
insert: function(doc, template) {
//modify the document here
doc.clanid= Router.current().params._id;
doc.dance ="start again";
console.log("running after hook");
return doc;
}
}
//lib/collections/samurais.js
Samurais = new Mongo.Collection('samurais');
Samurais.attachSchema(new SimpleSchema({
title: {
type: String,
label: "Title",
max: 100
},
description: {
type: String,
label: "Description",
optional: true
},
clanid: {
type: String,
label: "ignore this",
optional: true
},
dance: {
type: String,
optional: true
}
}));
if (Meteor.isServer) {
Samurais.allow({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc, fieldNames, modifier) {
return true;
},
remove: function (userId, doc) {
return true;
}
});
}

Weird undefined error on server

I have the following meteor method
hasNoPendingPayments: function() {
var userId = Meteor.userId();
console.log(userId); <---------------------- correctly logs userId
var user = Users.findOne({_id: userId }, { fields: { services: 0 } });
console.log(user); <-------------------------- logs 'undefined'
return hasNoPendingPayments(user);
},
This private helper I call from the above
hasNoPendingPayments = function(user) {
// console.log('hasNoPendingPayments ');
// console.log(user);
var payments = Payments.find({ userId: user._id, status: {
$in: [Payments.States.PENDING, Payments.States.PROCESSING]}
});
return payments.count() === 0;
};
And I call it from the client here
Template.payments.created = function() {
this.hasNoPendingPayments = new ReactiveVar(false);v
};
Template.payments.rendered = function () {
Session.set('showPaymentRequestForm', false);
var self = this;
Meteor.call('hasNoPendingPayments', function(error, result) {
if (result === true) { self.hasNoPendingPayments.set(true); }
});
...
However, I get an undefined error on the server when I load the template initially (I marked where in code). Although, when I try call the same query on the client with the same userId, i correctly gets the user record
Any idea as to why this is?
Try with this.
Template.payments.rendered = function () {
Session.set('showPaymentRequestForm', false);
var self = this;
if(Meteor.userId()){
Meteor.call('hasNoPendingPayments', function(error, result) {
if (result === true) { self.hasNoPendingPayments.set(true); }
});
}else{
console.log("Seems like user its not logged in at the moment")
}
Maybe when you make the Meteor.call, the data its not ready
Also just to be sure, when you run Users.findOne({_id: userId }, { fields: { services: 0 } }); on console.log what you get?
Maybe the find is wrong or have some typo
update
Router.map(function()
{
this.route('payments',
{
action: function()
{
if (Meteor.userId())
this.render();
} else{
this.render('login') // we send the user to login Template
}
}
}
or waitOn
Router.map(function () {
this.route('payments', {
path: '/payments',
waitOn: function(){
return Meteor.subscribe("userData"); //here we render template until the subscribe its ready
}
});
});
Meteor stores all the user records in Meteor.users collection
so try Meteor.users.findOne({_id: userId }....)
Instead of Users.findOne({_id: userId }, { fields: { services: 0 } });
in your server method

Meteor autoform, async callback in before hook

I am using Autoform and Slingshot for my S3 interaction. When the user submits the form, i want to intercept the process, upload the file to S3 through Slingshot, extend the doc object with the returned downloadUrl and then at that point, return the new updated doc, and continue the autoform process
I have the following code:
{{#autoForm collection="Tabs" id="newTabForm" type="method" meteormethod="createTab"}}
...
<div class="modal-body">
<fieldset>
{{> afFormGroup name='downloadUrl' type='file' class='file-bag'}}
...
AutoForm.hooks({
newTabForm: {
before: {
insert: function(doc, template) {
console.log(doc);
var file = $('.file-bag')[0].files[0];
var self = this;
uploader.send(file, function(error, downloadUrl) {
if (error) { throw new Meteor.Error(error); }
doc = _.extend(doc, { downloadUrl: downloadUrl });
self.result(doc);
});
}
},
....
Meteor.methods({
createTab: function(doc) {
check(doc, TabSchema);
var priceInCents = doc.price * 100;
var extraTabAttributes = {
userId: Meteor.userId(),
price: priceInCents
};
_.extend(doc, extraTabAttributes);
Tabs.insert(doc, function(error, result) {
if (error) { return error; }
});
}
Which correctly stores url (however looks weird, C://fakepath/filename..) on the document, but fails to upload it to the S3 server
Also side question, why doesnt the console.log(doc); in the before hooks log anything to the client/server?
I'm not familiar with auto form but I think your before hook is incorrect.
From https://github.com/aldeed/meteor-autoform#callbackshooks , it said
before: {
// Replace `formType` with the form `type` attribute to which this hook applies
formType: function(doc) {}
}
So in your case,
insert: function(doc, template)
Should be replaced with
method: function(doc, template)

Resources