/* html */
<template name="uploadForm2">
{{#with currentUpload}}
Uploading <b>{{file.name}}</b>:
<span id="progress">{{progress.get}}%</span>
{{else}}
<input id="fileInput" type="file" />
<p><small>Upload file in <code>jpeg</code> or <code>png</code> format, with size less or equal to 10MB</small></p>
{{/with}}
</template>
<template name="uploadedFiles2">
{{#if uploadedFiles.count}}
<ul>
{{#each uploadedFiles.each}}
<li>
<a href="{{link}}?download=true" download="{{name}}">{{name}}</a>
<img src="{{link}}" alt="{{name}}" />
<a class="js-remove btn">Remove</a>
</li>
{{/each}}
</ul>
{{else}}
<div>No files uploaded, yet</div>
{{/if}}
</template>
/* .js */
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Collections } from '../../api/images/images.js';
import './file-upload-page.html';
Template.uploadForm2.onCreated(function fileUploadPageOnCreated() {
this.currentUpload = new ReactiveVar(false);
this.autorun(() => {
this.subscribe('files.images.all');
});
});
Template.uploadedFiles2.helpers({
uploadedFiles: function () {
return Collections.files.find();
},
});
Template.uploadedFiles2.events({
'click .js-remove': function (e, template) {
this.remove(function (error) {
if (error) {
console.error('File(s) is not removed!', error);
}
});
}
});
Template.uploadForm2.helpers({
currentUpload: function () {
return Template.instance().currentUpload.get();
}
});
Template.uploadForm2.events({
'change #fileInput': function (e, template) {
if (e.currentTarget.files && e.currentTarget.files[0]) {
// We upload only one file, in case
// there was multiple files selected
let file = e.currentTarget.files[0];
if (file) {
let uploadInstance = Collections.files.insert({
file: file,
streams: 'dynamic',
chunkSize: 'dynamic'
}, false);
uploadInstance.on('start', function() {
template.currentUpload.set(this);
});
uploadInstance.on('end', function(error, fileObj) {
if (error) {
alert('Error during upload: ' + error.reason);
} else {
alert('File "' + fileObj.name + '" successfully uploaded');
}
template.currentUpload.set(false);
});
uploadInstance.start();
}
}
},
});
/*server */
import { FilesCollection } from 'meteor/ostrio:files';
var Dropbox, Request, bound, client, fs = {};
if (Meteor.isServer) {
Dropbox = Npm.require('dropbox');
Request = Npm.require('request');
fs = Npm.require('fs');
bound = Meteor.bindEnvironment(function(callback) {
return callback();
});
client = new Dropbox.Client({
key: 'xxxx',
secret: 'xxxx',
token: 'xxxx',
});
}
const Collections = {};
Collections.files = new FilesCollection({
debug: true, // Change to `true` for debugging
throttle: false,
storagePath: 'assets/app/uploads/uploadedFiles',
collectionName: 'uploadedFiles',
allowClientCode: true,
onAfterUpload: function(fileRef) {
// In onAfterUpload callback we will move file to DropBox
var self = this;
var makeUrl = function(stat, fileRef, version, triesUrl) {
if (triesUrl == null) {
triesUrl = 0;
}
client.makeUrl(stat.path, {
long: true,
downloadHack: true
}, function(error, xml) {
// Store downloadable link in file's meta object
bound(function() {
if (error) {
if (triesUrl < 10) {
Meteor.setTimeout(function() {
makeUrl(stat, fileRef, version, ++triesUrl);
}, 2048);
} else {
console.error(error, {
triesUrl: triesUrl
});
}
} else if (xml) {
var upd = {
$set: {}
};
upd['$set']["versions." + version + ".meta.pipeFrom"] = xml.url;
upd['$set']["versions." + version + ".meta.pipePath"] = stat.path;
self.collection.update({
_id: fileRef._id
}, upd, function(error) {
if (error) {
console.error(error);
} else {
// Unlink original files from FS
// after successful upload to DropBox
self.unlink(self.collection.findOne(fileRef._id), version);
}
});
} else {
if (triesUrl < 10) {
Meteor.setTimeout(function() {
makeUrl(stat, fileRef, version, ++triesUrl);
}, 2048);
} else {
console.error("client.makeUrl doesn't returns xml", {
triesUrl: triesUrl
});
}
}
});
});
};
var writeToDB = function(fileRef, version, data, triesSend) {
// DropBox already uses random URLs
// No need to use random file names
if (triesSend == null) {
triesSend = 0;
}
client.writeFile(fileRef._id + "-" + version + "." + fileRef.extension, data, function(error, stat) {
bound(function() {
if (error) {
if (triesSend < 10) {
Meteor.setTimeout(function() {
writeToDB(fileRef, version, data, ++triesSend);
}, 2048);
} else {
console.error(error, {
triesSend: triesSend
});
}
} else {
// Generate downloadable link
makeUrl(stat, fileRef, version);
}
});
});
};
var readFile = function(fileRef, vRef, version, triesRead) {
if (triesRead == null) {
triesRead = 0;
}
fs.readFile(vRef.path, function(error, data) {
bound(function() {
if (error) {
if (triesRead < 10) {
readFile(fileRef, vRef, version, ++triesRead);
} else {
console.error(error);
}
} else {
writeToDB(fileRef, version, data);
}
});
});
};
var sendToStorage = function(fileRef) {
_.each(fileRef.versions, function(vRef, version) {
readFile(fileRef, vRef, version);
});
};
sendToStorage(fileRef);
},
interceptDownload: function(http, fileRef, version) {
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')
}).pipe(http.response);
return true;
} else {
// While file is not yet uploaded to DropBox
// We will serve file from FS
return false;
}
}
});
export { Collections };
if (Meteor.isServer) {
// Intercept File's collection remove method
// to remove file from DropBox
var _origRemove = Collections.files.remove;
Collections.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.remove(vRef.meta.pipePath, function(error) {
bound(function() {
if (error) {
console.error(error);
}
});
});
}
});
});
// Call original method
_origRemove.call(this, search);
};
}
if (Meteor.isServer) {
Collections.files.deny({
insert() { return true; },
update() { return true; },
remove() { return true; },
});
}
Here is the errors
/* server error */
I20160728-09:52:55.711(8)? [FilesCollection] [File Start Method] 20131124_125547.jpg - HP9HPqEgMfQWkZzSB
I20160728-09:52:55.731(8)? [FilesCollection] [Upload] [Start Method] Got #-1/7 chunks, dst: 20131124_125547.jpg
I20160728-09:52:56.225(8)? [FilesCollection] [Upload] [DDP] Got #1/7 chunks, dst: 20131124_125547.jpg
I20160728-09:52:56.376(8)? [FilesCollection] [Upload] [DDP] Got #2/7 chunks, dst: 20131124_125547.jpg
I20160728-09:52:56.436(8)? [FilesCollection] [Upload] [DDP] Got #3/7 chunks, dst: 20131124_125547.jpg
I20160728-09:52:56.515(8)? [FilesCollection] [Upload] [DDP] Got #4/7 chunks, dst: 20131124_125547.jpg
I20160728-09:52:56.546(8)? [FilesCollection] [Upload] [DDP] Got #5/7 chunks, dst: 20131124_125547.jpg
I20160728-09:52:56.561(8)? [FilesCollection] [Upload] [DDP] Got #7/7 chunks, dst: 20131124_125547.jpg
I20160728-09:52:56.625(8)? [FilesCollection] [Upload] [DDP] Got #6/7 chunks, dst: 20131124_125547.jpg
I20160728-09:52:56.638(8)? [FilesCollection] [Upload] [DDP] Got #-1/7 chunks, dst: 20131124_125547.jpg
I20160728-09:52:56.713(8)? [FilesCollection] [Upload] [finish(ing)Upload] -> assets\app\uploads\uploadedFiles\HP9HPqEgMfQWkZzSB.jpg
I20160728-09:52:56.713(8)? [FilesCollection] [Upload] [finish(ed)Upload] -> assets\app\uploads\uploadedFiles\HP9HPqEgMfQWkZzSB.jpg
I20160728-09:52:56.729(8)? [FilesCollection] [_preCollectionCursor.observeChanges] [removed]: HP9HPqEgMfQWkZzSB
I20160728-09:52:58.326(8)? [FilesCollection] [download(/cdn/storage/uploadedFiles/HP9HPqEgMfQWkZzSB/original/HP9HPqEgMfQWkZzSB.jpg, original)]
I20160728-09:52:58.333(8)? [FilesCollection] [serve(assets\app\uploads\uploadedFiles\HP9HPqEgMfQWkZzSB.jpg, original)] [200]
I20160728-09:53:03.516(8)? [FilesCollection] [Unlink Method] [.remove(HP9HPqEgMfQWkZzSB)]
I20160728-09:53:03.535(8)? [FilesCollection] [remove("HP9HPqEgMfQWkZzSB")]
I20160728-09:53:03.537(8)? [FilesCollection] [unlink(HP9HPqEgMfQWkZzSB, undefined)]
I20160728-09:53:09.453(8)? [FilesCollection] [File Start Method] 20131124_125547.jpg - CpBqKjPi8FnWEwDc7
I20160728-09:53:09.459(8)? [FilesCollection] [Upload] [Start Method] Got #-1/7 chunks, dst: 20131124_125547.jpg
I20160728-09:53:09.864(8)? [FilesCollection] [Upload] [DDP] Got #1/7 chunks, dst: 20131124_125547.jpg
I20160728-09:53:09.953(8)? [FilesCollection] [Upload] [DDP] Got #2/7 chunks, dst: 20131124_125547.jpg
I20160728-09:53:10.019(8)? [FilesCollection] [Upload] [DDP] Got #3/7 chunks, dst: 20131124_125547.jpg
I20160728-09:53:10.113(8)? [FilesCollection] [Upload] [DDP] Got #4/7 chunks, dst: 20131124_125547.jpg
I20160728-09:53:10.212(8)? [FilesCollection] [Upload] [DDP] Got #5/7 chunks, dst: 20131124_125547.jpg
I20160728-09:53:10.253(8)? [FilesCollection] [Upload] [DDP] Got #7/7 chunks, dst: 20131124_125547.jpg
I20160728-09:53:10.331(8)? [FilesCollection] [Upload] [DDP] Got #6/7 chunks, dst: 20131124_125547.jpg
I20160728-09:53:10.346(8)? [FilesCollection] [Upload] [DDP] Got #-1/7 chunks, dst: 20131124_125547.jpg
I20160728-09:53:10.378(8)? [FilesCollection] [Upload] [finish(ing)Upload] -> assets\app\uploads\uploadedFiles\CpBqKjPi8FnWEwDc7.jpg
I20160728-09:53:10.378(8)? [FilesCollection] [Upload] [finish(ed)Upload] -> assets\app\uploads\uploadedFiles\CpBqKjPi8FnWEwDc7.jpg
I20160728-09:53:10.393(8)? [FilesCollection] [_preCollectionCursor.observeChanges] [removed]: CpBqKjPi8FnWEwDc7
I20160728-09:53:12.605(8)? [FilesCollection] [download(/cdn/storage/uploadedFiles/CpBqKjPi8FnWEwDc7/original/CpBqKjPi8FnWEwDc7.jpg, original)]
I20160728-09:53:12.618(8)? [FilesCollection] [serve(assets\app\uploads\uploadedFiles\CpBqKjPi8FnWEwDc7.jpg, original)] [200]
I20160728-09:53:12.775(8)? Exception in callback of async function: TypeError: Cannot read property '_id' of undefined
I20160728-09:53:12.778(8)? at FilesCollection.exports.FilesCollection.FilesCollection.unlink (C:\projects\Testing\skillmate\.meteor\local\build\programs\server\packages\ostrio_files.js:2718:58)
I20160728-09:53:12.784(8)? at meteor://app/imports/api/images/images.js:63:22
I20160728-09:53:12.786(8)? at meteor://app/packages/mongo/collection.js:651:5
I20160728-09:53:12.789(8)? at runWithEnvironment (meteor://app/packages/meteor/dynamics_nodejs.js:110:1)
I20160728-09:53:12.792(8)? at meteor://app/packages/meteor/dynamics_nodejs.js:123:1
I20160728-09:53:12.795(8)? at meteor://app/packages/mongo/mongo_driver.js:322:7
I20160728-09:53:12.797(8)? at meteor://app/packages/mongo/mongo_driver.js:568:11
I20160728-09:53:12.804(8)? at runWithEnvironment (meteor://app/packages/meteor/dynamics_nodejs.js:110:1)
I20160728-09:53:26.966(8)? [FilesCollection] [unlink(CpBqKjPi8FnWEwDc7, original)]
I20160728-09:54:21.436(8)? [FilesCollection] [Unlink Method] [.remove(CpBqKjPi8FnWEwDc7)]
I20160728-09:54:21.443(8)? [FilesCollection] [remove("CpBqKjPi8FnWEwDc7")]
I20160728-09:54:21.454(8)? [FilesCollection] [unlink(CpBqKjPi8FnWEwDc7, undefined)]
Somewhy _id property isn't available in .unlink() method
Could you disable debug mode, I think there is a bug in logging.
Hi, here's the error after debug mode disabled.
=> Meteor server restarted
I20160728-21:45:49.338(8)? Exception in callback of async function: TypeError: Cannot read property 'versions' of undefined
I20160728-21:45:49.338(8)? at FilesCollection.exports.FilesCollection.FilesCollection.unlink (C:\projects\Testing\skillmate\.meteor\local\build\programs\server\packages\ostrio_files.js:2721:26)
I20160728-21:45:49.354(8)? at meteor://app/imports/api/images/images.js:62:22
I20160728-21:45:49.354(8)? at meteor://app/packages/mongo/collection.js:651:5
I20160728-21:45:49.354(8)? at runWithEnvironment (meteor://app/packages/meteor/dynamics_nodejs.js:110:1)
I20160728-21:45:49.354(8)? at meteor://app/packages/meteor/dynamics_nodejs.js:123:1
I20160728-21:45:49.354(8)? at meteor://app/packages/mongo/mongo_driver.js:322:7
I20160728-21:45:49.354(8)? at meteor://app/packages/mongo/mongo_driver.js:568:11
I20160728-21:45:49.370(8)? at runWithEnvironment (meteor://app/packages/meteor/dynamics_nodejs.js:110:1)
Could you post here few lines above snd below this line C:\projects\Testing\skillmate\.meteor\local\build\programs\server\packages\ostrio_files.js:2721:26 ?
You mean this way?
I20160728-21:45:49.338(8)? Exception in callback of async function: TypeError: Cannot read property 'versions' of undefined
I20160728-21:45:49.354(8)? at meteor://app/imports/api/images/images.js:62:22
I20160728-21:45:49.354(8)? at meteor://app/packages/mongo/collection.js:651:5
I20160728-21:45:49.354(8)? at runWithEnvironment (meteor://app/packages/meteor/dynamics_nodejs.js:110:1)
I20160728-21:45:49.354(8)? at meteor://app/packages/meteor/dynamics_nodejs.js:123:1
I20160728-21:45:49.354(8)? at meteor://app/packages/mongo/mongo_driver.js:322:7
I20160728-21:45:49.354(8)? at meteor://app/packages/mongo/mongo_driver.js:568:11
I20160728-21:45:49.370(8)? at runWithEnvironment (meteor://app/packages/meteor/dynamics_nodejs.js:110:1)
Nope, open this file: C:\projects\Testing\skillmate\.meteor\local\build\programs\server\packages\ostrio_files.js:2721
Here it is,
FilesCollection.prototype.unlink = Meteor.isServer ? function (fileRef, version) {
var ref, ref1;
if (this.debug) {
console.info("[FilesCollection] [unlink(" + fileRef._id + ", " + version + ")]");
}
if (version) {
if (((ref = fileRef.versions) != null ? ref[version] : void 0) && ((ref1 = fileRef.versions[version]) != null ? ref1.path : void 0)) {
fs.unlink(fileRef.versions[version].path, NOOP);
}
} else {
if (fileRef.versions && !_.isEmpty(fileRef.versions)) {
_.each(fileRef.versions, function (vRef) {
return bound(function () {
fs.unlink(vRef.path, NOOP);
});
});
} else {
fs.unlink(fileRef.path, NOOP);
}
}
return this;
} : void 0;
Looks good to me.
Is there any chance you're passing empty Object as fileRef to this method? Can you check ehat are you exactly passing into .unlink() method?
I don't think so ... All files and codes were shown above. No additional Object.
Could you just add console.log for arguments passed into .unlink() right before it?
I console.log fileRef_id and version... I not sure if this you wanna see.
I20160728-23:01:30.191(8)? remove: [Function] }
I20160728-23:01:31.001(8)? fileRef=[object Object]
I20160728-23:01:31.005(8)? fileRef._id = dknnxtsXQS8ixpcow
I20160728-23:01:31.008(8)? version = original
I20160728-23:01:31.597(8)? Exception in callback of async function: TypeError: Cannot read property 'versions' of undefined
I20160728-23:01:31.601(8)? at FilesCollection.exports.FilesCollection.FilesCollection.unlink (C:\projects\Testing\skillmate\.meteor\local\build\programs\server\packages\ostrio_files.js:2721:26)
I20160728-23:01:31.608(8)? at meteor://锟絘pp/imports/api/images/images.js:68:22
I20160728-23:01:31.611(8)? at meteor://锟絘pp/packages/mongo/collection.js:651:5
I20160728-23:01:31.615(8)? at runWithEnvironment (meteor://锟絘pp/packages/meteor/dynamics_nodejs.js:110:1)
I20160728-23:01:31.619(8)? at meteor://锟絘pp/packages/meteor/dynamics_nodejs.js:123:1
I20160728-23:01:31.622(8)? at meteor://锟絘pp/packages/mongo/mongo_driver.js:322:7
I20160728-23:01:31.626(8)? at meteor://锟絘pp/packages/mongo/mongo_driver.js:568:11
I20160728-23:01:31.629(8)? at runWithEnvironment (meteor://锟絘pp/packages/meteor/dynamics_nodejs.js:110:1)
I20160728-23:01:42.783(8)? fileRef=[object Object]
I20160728-23:01:42.788(8)? fileRef._id = zw5GNjkb8ZrsrXhbM
I20160728-23:01:42.795(8)? version = original
is fileRef has versions sub-object?
I did this.... correct me if i'm wrong.
else if (xml) {
console.log("fileRef=" + fileRef)
console.log("fileRef._id = " +fileRef._id)
console.log("version = " + version)
var upd = {
$set: {}
};
upd['$set']["versions." + version + ".meta.pipeFrom"] = xml.url;
upd['$set']["versions." + version + ".meta.pipePath"] = stat.path;
self.collection.update({
_id: fileRef._id
}, upd, function(error) {
if (error) {
console.error(error);
} else {
// Unlink original files from FS
// after successful upload to DropBox
self.unlink(self.collection.findOne(fileRef._id), version);
}
});
console.log(fileRef)
or even:
console.log(JSON.stringify(fileRef, null, 2));
Please use syntax highlighter for posted snippets. And normalise spaces and paddings, so I will be able easily read your code.
Using console.log(JSON.stringify(fileRef, null, 2)) inside onAfterUpload: function(fileRef)
Here is the output:
{
I20160730-11:49:30.037(8)? "name": "8152267739.jpg",
I20160730-11:49:30.040(8)? "extension": "jpg",
I20160730-11:49:30.044(8)? "path": "assets\\app\\uploads\\uploadedFiles\\XjpZmEGhj9EQH9Civ.jpg",
I20160730-11:49:30.047(8)? "meta": {},
I20160730-11:49:30.050(8)? "type": "image/jpeg",
I20160730-11:49:30.053(8)? "size": 49034,
I20160730-11:49:30.058(8)? "versions": {
I20160730-11:49:30.074(8)? "original": {
I20160730-11:49:30.081(8)? "path": "assets\\app\\uploads\\uploadedFiles\\XjpZmEGhj9EQH9Civ.jpg",
I20160730-11:49:30.084(8)? "size": 49034,
I20160730-11:49:30.087(8)? "type": "image/jpeg",
I20160730-11:49:30.090(8)? "extension": "jpg"
I20160730-11:49:30.093(8)? }
I20160730-11:49:30.100(8)? },
I20160730-11:49:30.103(8)? "isVideo": false,
I20160730-11:49:30.107(8)? "isAudio": false,
I20160730-11:49:30.110(8)? "isImage": true,
I20160730-11:49:30.118(8)? "isText": false,
I20160730-11:49:30.120(8)? "isJSON": false,
I20160730-11:49:30.124(8)? "isPDF": false,
I20160730-11:49:30.130(8)? "_storagePath": "assets\\app\\uploads\\uploadedFiles",
I20160730-11:49:30.134(8)? "_downloadRoute": "/cdn/storage",
I20160730-11:49:30.138(8)? "_collectionName": "uploadedFiles",
I20160730-11:49:30.142(8)? "_id": "XjpZmEGhj9EQH9Civ",
I20160730-11:49:30.146(8)? "userId": "GijYpdH5nYrc9HfgR",
I20160730-11:49:30.150(8)? "public": false
I20160730-11:49:30.153(8)? }
Okay, as everything looks good. I've read this thread from beginning few times. And just realised what error says Cannot read property 'versions' of undefined, that actually means what your trying to get versions property from undefined variable. Could you please check what all variables is defined and there is no typo, use jslint and "use strict"; mode.
Could mixing javascript with es6 caused this problem?
IDK I don't mix. Do you use .jsx extension?
WTB mixing Coffee with ES6 is okay on my end.
I use .js Extension. Anyway I try to change your code and defining variables to es6 sooner or later. let's see what happens. I shall close this issue for now. Thanks man.
@1073113 anyways, let me know
Sure, I will.
Hi Dr.Dimitri,
I found what caused the issue of Can't read property 'versions' of undefined
(google storage integration)
Its regarding Unlink Method in onAfterUpload
bucket.upload(fileRef.path, options, (error) => {
bound(() => {
let upd;
if (error) {
console.error(error);
} else {
upd = {
$set: {},
};
upd.$set[`versions.${version}.meta.pipePath`] = filePath;
this.collection.update({
_id: fileRef._id,
}, upd, (error) => {
if (error) {
console.error(error);
} else {
console.log('Run this condition- Unlink');
/* Error will prompted in server console
( Can't read property 'versions' of undefined`)
when I triggered removal method while this condition
hasn't finished execution.
( I have 3 versions )
I20170319-01:31:14.071(8)? Run this condition- Unlink
I20170319-01:31:14.276(8)? Run this condition- Unlink
I20170319-01:31:14.313(8)? Run this condition- Unlink
*/
this.unlink(this.collection.findOne(fileRef._id), version);
}
});
}
});
});
Error Statement:
Exception in callback of async function: TypeError:
Cannot read property 'versions' of undefined at
FilesCollection.module.runModuleSetters.FilesCollection.unlink
(C: ..\server\packages\ostrio_files.js:3030:26)
Error occured: Deleted an image (Press Delete Button) before it finished Unlink all versions.
The situation to trigger this error : Delete the Image right after the image shows on the browser.
The outcomes: It doesn't remove files( all versions) contained in Google Storage. The local collection.files document has removed.
My current remove method is as same as your in the docs.
const_origRemove = Collections.files.remove;
Collections.files.remove = function(search) {
var cursor = this.collection.find(search);
cursor.forEach(function(fileRef) {
_.each(fileRef.versions, function(vRef) {
if (vRef && vRef.meta && vRef.meta.pipePath != null) {
bucket.file(vRef.meta.pipePath).delete(function(error) {
bound(function() {
if (error) {
console.error(error);
}
});
});
}
});
});
// Call the original removal method
_origRemove.call(this, search);
};
My though to prevent this problem : Show the delete button/Image only after it finished to Unlink all versions upons Uploads.
Require your advise to change the code.
If there is better solution to solve this issue. That's cool!!
Thanks dr.dimitru.
Hello @1073113 ,
Well, there is may be a reason to execute _origRemove.call(this, search); after you walk through every file's version and remove it from bucket, right now it's asynchronous.
So you will have to .fetch() Cursor and loop with for(/*...*/){} and run _origRemove.call(this, search); inside bucket.file().delete() method callback after you reach last item on cursor and last subversion of the file.
To avoid your exception, make sure file is exists before running .unlink() method.
const fileObj = this.collection.findOne(fileRef._id);
if (fileObj) {
this.unlink(fileObj, version);
}
Hi Dr. Dimitri
Here is the code changes by following your advices/suggestions.
There is a slight behaviour changed when pressing delete button.
1) When delete the image right after the image showed on the browser. (1st time)
The outcomes:
There is no file deletion happened unless the Unlink method of all versions successfully unlinked. Therefore I have to trigger delete method for 2nd time (Press delete button twice) to successfully delete both local collections and google storage . However the CallBack function on the client code triggered message of 'successfully deleted' at the 1st trigger as there is no responses of all deletion at the 1st trigger.
2) Regarding the delete method code, Kindly check if this is the logic that you suggested.
I don't know how to loop thru to run _origRemove.call(this, search); at the last subversion in a bucket.file().delete() method callback. Need to help modify the code. Thank you.
Client Code
'click .js-remove-img'() {
this.remove((error) => {
if (error) {
console.log(error.error);
} else {
// it execute this block even it doesn't delete any files at the first trigger
console.log('successfully deleted');
}
});
Server Code
if (Meteor.isServer) {
const _origRemove = Collections.files.remove;
Collections.files.remove = function remove(search) {
const cursor = this.collection.find(search).fetch();
cursor.forEach((fileRef) => {
// totalLength = 3
const totalLength = Object.keys(fileRef.versions).length; // Original/Thumbnail/Preview
Object.keys(fileRef.versions).forEach((vRefObj, index) => {
const vRef = fileRef.versions[vRefObj];
if (vRef && vRef.meta && vRef.meta.pipePath != null) {
if (index < totalLength) {
// newLength = 2
const newLength = totalLength - 1;
if (index < newLength) {
bucket.file(vRef.meta.pipePath).delete((error) => {
bound(() => {
if (error) {
console.error(`remove error: ${error}`);
}
});
});
}
if (index === newLength) {
bucket.file(vRef.meta.pipePath).delete((error) => {
bound(() => {
if (error) {
console.error(`remove error: ${error}`);
} else {
_origRemove.call(this, search);
}
});
});
}
}
}
});
});
};
}
Hello @1073113 ,
Sorry for delay, here is updated code:
if (Meteor.isServer) {
const _origRemove = Collections.files.remove;
Collections.files.remove = function remove(search) {
const cursor = this.collection.find(search);
const filesLen = cursor.count() - 1;
let fileIndex = 0;
cursor.forEach((fileRef) => {
const verLen = Object.keys(fileRef.versions).length - 1; // Original/Thumbnail/Preview
Object.keys(fileRef.versions).forEach(function (vRefObj, verIndex) {
const vRef = fileRef.versions[vRefObj];
if (vRef && vRef.meta && vRef.meta.pipePath != null) {
if (verIndex < totalLength) {
bucket.file(vRef.meta.pipePath).delete((error) => {
bound(() => {
if (error) {
console.error(`remove error: ${error}`);
}
if (filesLen === this.fileIndex && verLen === verIndex) {
_origRemove.call(this, search);
}
});
});
}
}
}, {fileIndex});
fileIndex++;
});
};
}
Hi Dr.Dimitri,
Thank you so much for helping me to modify the code.
however, what is the totalLength (forgotten to defined) in
if (verIndex < totalLength) {...}
If I change to if (verIndex < verLen) {...}
Outcome: The last file version doesn't delete in Google Storage and local collection doesn't removed.
So I define -
const totalLength = Object.keys(fileRef.versions).length;
if (verIndex < totalLength ) {...}
outcome: All file versions deleted in Google Storage however it give error Cannot read property 'find' of undefined when execute _origRemove.call(this, search);
Error Statement
Exception in callback of async function: TypeError: Cannot read property 'find' of undefined
at Object.module.runModuleSetters.FilesCollection.remove (C:\.,,\.meteor\local\build\programs\server\packages\ostrio_files.js:2876:30)
Hello @1073113 ,
Well, this block-scope is changed, here is fix:
if (Meteor.isServer) {
const _origRemove = Collections.files.remove;
Collections.files.remove = function remove(search) {
const self = this;
const cursor = this.collection.find(search);
const filesLen = cursor.count() - 1;
let fileIndex = 0;
cursor.forEach((fileRef) => {
const verLen = Object.keys(fileRef.versions).length - 1; // Original/Thumbnail/Preview
Object.keys(fileRef.versions).forEach(function (vRefObj, verIndex) {
const vRef = fileRef.versions[vRefObj];
if (vRef && vRef.meta && vRef.meta.pipePath != null) {
bucket.file(vRef.meta.pipePath).delete((error) => {
bound(() => {
if (error) {
console.error(`remove error: ${error}`);
}
if (filesLen === this.fileIndex && verLen === verIndex) {
_origRemove.call(self, search);
}
});
});
}
}, {fileIndex});
fileIndex++;
});
};
}
Hi Dr.Dimitri , Thank you so much.. The code works fine! Appreciated!
Just a minor issue about the callback for deletion.. I'll figure it out.
I'm glad we've figured it out
Most helpful comment
Hi Dr.Dimitri , Thank you so much.. The code works fine! Appreciated!
Just a minor issue about the callback for deletion.. I'll figure it out.