CollectionsFS File is not uploaded to server - javascript

i am working myself through the discover meteor project (microscope) and tried to add a file upload, which i wanted to do by CollectionFS. My microscope implementation is quite minimal. I am trying to rebuild a minimal dribbble or Workdesk show and tell website.
I installed:
cfs:standard-packages
cfs:filesystem
cfs:ui
Next I am having a collection called rooms which stores a room with a name, for a user (lib/collections/rooms.js):
Rooms = new Mongo.Collection("rooms");
And a roomImages CollectionFS Collection (lib/collections/roomImages.js):
var imageStore = new FS.Store.FileSystem("roomImageStore", {
path: "upload",
maxTries: 5 //optional, default 5
});
RoomFS = new FS.Collection('roomImages', {
stores: [imageStore],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
RoomFS.allow({
insert: function () {
return true;
},
update: function () {
return true;
},
remove: function () {
return true;
},
download: function () {
return true;
}
});
As I have removed referencing for reducing the debug effort I have this publications.js
Meteor.publish('rooms', function() {
return Rooms.find();
});
Meteor.publish('singleRoom', function(id) {
check(id, String);
return Rooms.find(id);
});
Meteor.publish('roomImages', function(){
return RoomFS.find();
});
Inserting a room works. After the room initially is created, the user then is routed to the rooms editing page.
<template name="roomEdit">
<form class="main form">
<input name="files" type="file" class="fileUploader" multiple>
{{#each images}}
{{#unless this.isUploaded}}
{{> FS.UploadProgressBar bootstrap=true}}
{{/unless}}
{{/each}}
</form>
</template>
I took the function off the documentation in the readme:
Template.roomEdit.events({
'change .fileUploader': function (event, template) {
FS.Utility.eachFile(event, function(file) {
RoomFS.insert(file, function (err, fileObj) {
//Inserted new doc with ID fileObj._id, and kicked off the data upload using HTTP
});
});
});
Now in my collections there are
cfs._tempstore.chunks
cfs.roomImages.filerecord
after trying to upload one image (the progress bar is not showing) cfs.roomImages.filerecord has the file as collection item, but the uploads folder keeps being empty, therefore I think the file is not uploaded, also if I don't give a path, the default folder is not generated.
I have already read both documentations (website and github) and tried different examples, but most of them seem to be outdated.
Am I missing something? I have no real idea why the file is not uploaded to the server.

If you have the subscription on the client, try this code.
First on the /lib/collection.js folder declare the FSCollection like this
var imageStore = new FS.Store.FileSystem("roomImageStore", {
path: "upload",
maxTries: 5 //optional, default 5
});
roomImages = new FS.Collection('roomImages', {
stores: [imageStore]
});
And not the Same file subscribe to the FSCollection.
if(Meteor.isClient) {
Meteor.subscribe('RoomFS');
}
Now on the /server/collections.js make the same publish you have.
Meteor.publish('roomImages', function(){
return roomImages.find();
});
roomImages.allow({
insert:function(userId,doc){
if(Meteor.userId()){
return true; //if user is logged we return true
} else{
console.log("some foreign user try to upload a file take care"); //server log
return false
}
}
})
we create and subscribe the FSCollection on the /lib folder.. why? because the lib folder its the firs thing meteor loads, so with that we have the fsCollection available on both server/client.
Now we need to upload a new file, so lets create a example template
First we don't want the file to load when we click "accept" on the file input so lets put a submit file button, so the html looks like this.
on Client/exampleUpload.html
<template name="example">
<div class="form-group">
<label>Upload the Image</label>
<input id="testImage" type="file">
</div>
<button type="submit" id="uploadTest"> Click to upload</button>
</template>
on Client/exampleUpload.js
//events
Template.example.events({
'click #uploadTest':function(){
var file $('#testImage').get(0).files[0] / here we store the file
var fsFile = new fsFile(file); // here we add to the fsFile instance
fsFile.metadata = {
coolTextToImage:"this is a cool text" // here we add some metadata to the fs file
}
if(file === undefined){
alert("IF NOT IMAGE NOT INSER") //here we add some validation
} else{
roomImages.insert(fsFile,function(err,result){
if(err){
console.log(err.reason) // here we check if some error occurs when inserting
} else{
console.log(result) // if everything ok, wee should see a console.log with some like [Fs.file] object
}
})
}
}
})
Edit
I recommend you to use gridFS,check at this gitHub issue and also if you use FSfileSystem on production on each deploy the files will be deleted(i think Modulus.io respect the Path).
How to fix it? use the other 2 adapter gridFs or s3, in my case i use GridFS, and GraphicsMagic Package
So first Install the GM package
meteor add cfs:graphicsmagick
With this package you can control the size, type, etc of the file(image)
And declare the new FsCollection like this
imageStore = new FS.Collection("imageStores", {
stores: [new FS.Store.GridFS("imageStore",{
beforeWrite:function(fileObj){
return {
extension: 'png',
type: 'image/png'
};
},
transformWrite:function(fileObj, readStream, writeStream){
// Aqui la convierte en una imagen segun de 10x10 seguuuun
gm(readStream).resize(400).stream('PNG').pipe(writeStream); //resize depends your needs
}
})]
});
this is just a recommendation if you are planning deploy the app
Tell me if works, GL

Related

Make a 'common' login.js include; with nightwatch.js tests

When writing tests for my web app; I have to first simulate login before the rest of my tests can run and see inner pages. Right now I'm working on modulating the code, so that way I can just make an 'include' for the common function; such as my login. But as soon as I move the below code in a separate file, and call the include via require - it no longer runs as expected.
ie. the below logs in and allows my other functions, if, included in the same file. above my other inner screen functions.
// Login screen, create opportunity
this.LoginScreen = function(browser) {
browser
.url(Data.urls.home)
.waitForElementVisible('#login', 2000, false)
.click('#login')
.waitForElementVisible('div.side-panel.open', 4000, false)
.waitForElementVisible('input#email', 2000, false)
.waitForElementVisible('input#password', 2000, false)
.click('input#email')
.pause(500)
.setValue('input#email', Data.ProjMan.username)
.click('input#password')
.pause(500)
.setValue('input#password', Data.ProjMan.password)
.click('input#email')
.pause(500)
.click('div.form.login-form .btn')
.pause(5000)
Errors.checkForErrors(browser);
};
// Inner functions run after here, sequentially
But as soon as I move the above in a separate file, for instance; Logins.js, then call it at the top of the original test file with. (yes, correct path).
var Logins = require("../../lib/Logins.js");
It just doesn't simulate the login anymore. Any thoughts? Should I remove the this.LoginScreen function wrapper, and call it differently to execute from the external file, or do I need to fire it from the original file again, aside from the external require path?
I have also tried wrapping 'module.exports = {' around the login function from separate file, but still failing.
Nightwatch allows you to run your Page object based tests i.e you can externalize your common test functions and use them in your regular tests. This can be achieved using 'page_objects_path' property. I have added the common 'login' functionality and used it in sample 'single test' in the project here.
Working:
Place your common function in .js file and place it under a folder(ex: tests/pages/login.js) and pass the folder path in nighwatch config file as below:
nightwatch_config = {
src_folders : [ 'tests/single' ],
page_objects_path: ['tests/pages'],
Below is an example of common login function (login.js):
var loginCommands = {
login: function() {
return this.waitForElementVisible('body', 1000)
.verify.visible('#userName')
.verify.visible('#password')
.verify.visible('#submit')
.setValue('#userName', 'Enter Github user name')
.setValue('#password', 'Enter Github password')
.waitForElementVisible('body', 2000)
}
};
module.exports = {
commands: [loginCommands],
url: function() {
return 'https://github.com/login';
},
elements: {
userName: {
selector: '//input[#name=\'login\']',
locateStrategy: 'xpath'
},
password: {
selector: '//input[#name=\'password\']',
locateStrategy: 'xpath'
},
submit: {
selector: '//input[#name=\'commit\']',
locateStrategy: 'xpath'
}
}
};
Now, in your regular test file, create an object for the common function as below and use it.
module.exports = {
'Github login Functionality' : function (browser) {
//create an object for login
var login = browser.page.login();
//execute the login method from //tests/pages/login.js file
login.navigate().login();
//You can continue with your tests below:
// Also, you can use similar Page objects to increase reusability
browser
.pause(3000)
.end();
}
};
The above answer is absolutly correct however I did struggle with how to supply login user details.
This is what I ended up using:
var loginCommands = {
login: function() {
return this.waitForElementVisible('body', 1000)
.setValue("#email", "<some rnd email address>")
.setValue('#password', "<some rnd password>")
.click('button[type=submit]')
.pause(1000)
}
};
module.exports = {
commands: [loginCommands],
url: function() {
return 'https://example.com/login';
}
};
This can be used in the same way as the accepted answer just posting for others who come searching.

Meteor Files Storing a image url in Mongo collection

I'm really lost when it comes to file uploading in meteor and manage the data between client and server.
I'm using Meteor Files from Veliov Group to upload multiple images on the client side. They're getting stored in a FilesCollection called Images and I have my Mongo.Collection called Adverts.
collections.js:
Adverts = new Mongo.Collection('adverts');
Images = new FilesCollection({
collectionName: 'Images',
storagePath: () => {
return `~/public/uploads/`;
},
allowClientCode: true, // Required to let you remove uploaded file
onBeforeUpload(file) {
// Allow upload files under 10MB, and only in png/jpg/jpeg formats
if (file.size <= 10485760 && /png|jpg|jpeg/i.test(file.ext)) {
return true;
} else {
return 'Limit 10mb';
}
}
});
// if client subscribe images
if (Meteor.isClient) {
Meteor.subscribe('files.images.all');
};
// if server publish images
if (Meteor.isServer) {
Images.allowClient();
Meteor.publish('files.images.all', () => {
return Images.collection.find();
});
};
What I'm trying to achieve is, when I upload the images, I wanna store the URLs on the document in Adverts that I'm working with (I'm using iron:router to access those documents _id).
I managed to get the URL but only for the first image uploaded, my code for what I saw on the docs:
Template.imageUpload.helpers({
imageFile: function () {
return Images.collection.findOne();
},
myImage: () => {
console.log(Images.findOne({}).link())
}
})
Template.imageUpload.events({
'change #fileInput': function (e, template) {
if (e.currentTarget.files) {
_.each(e.currentTarget.files, function (file) {
Images.insert({
file: file
});
});
}
}
})
I was using a Meteor.Call to send the URL to the server, but I couldn't manage to update the document with a new property pic and the value url of the image
server.js:
imageUpload: (actDoc, imgURL) => { // actDoc is the document id that I'm working on the client
Adverts.update({'reference': actDoc}, {$set: {'pic': imgURL}})
},
This is probably a dumb question and everything might in the docs, but I've readed those docs back and forth and I can't manage to understand what I need to do.
The answer for my problem was to do it server side
main.js server
FSCollection.on('afterUpload'), function (fileRef) {
var url = 'http://localhost:3000/cdn/storage/images/' + fileRef._id + '/original/' + fileRef._id + fileRef.extensionWithDot;
}
MongoCollection.update({'_id': docId}, { $set: {url: imgUrl }}})

Uploading file to PouchDB/CouchDB

I'm building a mobile app with Cordova. I am using PouchDB for local storage so the app works without internet. PouchDB syncs with a CouchDB server so you can access your data everywere.
Now, i've got to the point where I need to add a function to upload (multiple) files to a document. (files like .png .jpg .mp3 .mp4 all the possible file types).
My original code without the file upload:
locallp = new PouchDB('hbdblplocal-'+loggedHex);
function addItem() {
//get info
var itemTitle = document.getElementById('itemTitle').value;
var itemDesc = document.getElementById('itemDesc').value;
var itemDate = document.getElementById('itemDate').value;
var itemTime = document.getElementById('itemTime').value;
//get correct database
console.log(loggedHex);
console.log(loggedInUsername);
//add item to database
var additem = {
_id: new Date().toISOString(),
title: itemTitle,
description: itemDesc,
date: itemDate,
time: itemTime
};
locallp.put(additem).then(function (result){
console.log("Added to the database");
location.href = "listfunction.html";
}).catch(function (err){
console.log("someting bad happened!");
console.log(err);
});
}
I'll add a link to a JSfiddle where I show my attempt to add the file upload. i've also included the html part.
link to jsfiddle: click here
I've noticed an error in the console about there not being a content-type.
Is there someone who can help me?
I think you're not setting the content_type of your attachment right. Try changing type to content_type like so:
var additem = {
_id: new Date().toISOString(),
title: itemTitle,
description: itemDesc,
date: itemDate,
time: itemTime,
_attachments: {
"file": {
content_type: getFile.type,
data: getFile
}
}
};
Also see the docs for working with attachments.

Meteor CollectionFS Collection is Undefined?

I am trying to use CollectionFS and GridFS to upload some images to my app and serve them back.
I have the following definitions:
ImageStore.js:
var imageStore = new FS.Store.GridFS("images", {
mongoUrl: 'mongodb://127.0.0.1:27017/test/',
transformWrite: myTransformWriteFunction,
transformRead: myTransformReadFunction,
maxTries: 1,
chunkSize: 1024*1024
});
EventImages = new FS.Collection("images", {
stores: [imageStore]
});
ImageStorePub.js:
Meteor.publish("EventImages", function() {
return EventImages.find();
});
ImageUploadHandler.js:
if (Meteor.isServer) {
EventImages.allow({
'insert': function() {
// add custom authentication code here
return true;
}
});
}
After typing all of this I tried wrapping them all in a if(Meteor.isServer){...} despite the fact that they're already in my server folder, but my app is still crashing due to error ReferenceError: EventImages is not defined
at server/route handlers/ImageUploadHandler.js:2:1
I made a mistake in not assigning the variable on both the client and server.

Meteor: Not able to upload image to S3 using CollectionFS

I am trying to test the upload functionality using this guide with the only exception of using cfs-s3 package. This is very basic with simple code but I am getting an error on the client console - Error: Access denied. No allow validators set on restricted collection for method 'insert'. [403]
I get this error even though I have set the allow insert in every possible way.
Here is my client code:
// client/images.js
var imageStore = new FS.Store.S3("images");
Images = new FS.Collection("images", {
stores: [imageStore],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
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;
}
});
And there is a simple file input button on the homepage -
// client/home.js
'change .myFileInput': function(e, t) {
FS.Utility.eachFile(e, function(file) {
Images.insert(file, function (err, fileObj) {
if (err){
console.log(err) // --- THIS is the error
} else {
// handle success depending what you need to do
console.log("fileObj id: " + fileObj._id)
//Meteor.users.update(userId, {$set: imagesURL});
}
});
});
}
I have set the proper policies and everything on S3 but I don't think this error is related to S3 at all.
// server/images.js
var imageStore = new FS.Store.S3("images", {
accessKeyId: "xxxx",
secretAccessKey: "xxxx",
bucket: "www.mybucket.com"
});
Images = new FS.Collection("images", {
stores: [imageStore],
filter: {
allow: {
contentTypes: ['image/*']
}
}
});
I have also published and subscribed to the collections appropriately. I have been digging around for hours but can't seem to figure out what is happening.
EDIT: I just readded insecure package and everything now works. So basically, the problem is with allow/deny rules but I am actually doing it. I am not sure why it is not acknowledging the rules.
You need to define the FS.Collection's allow/deny rules in sever-only code. These are server-side rules applied to the underlying Mongo.Collection that FS.Collection creates.
The best approach is to export the AWS keys as the following environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, remove the accessKeyId and secretAccessKey options from the FS.Store, and then move the FS.Collection constructor calls to run on both the client and server. The convenience of using env vars is mentioned on the cfs:s3 page
In addition to this you can control the bucket name using Meteor.settings.public, which is handy when you want to use different buckets based on the environment.

Categories

Resources