veliovgroup / Meteor-Files-Demos

Demos for ostrio:files package
https://github.com/VeliovGroup/Meteor-Files
BSD 3-Clause "New" or "Revised" License
52 stars 47 forks source link

removing image from server and post data #8

Closed ApayRus closed 7 years ago

ApayRus commented 7 years ago

I realized issue #7 with your help, using Sessions. Now, what about removing? It is enough to just remove image from collection Images? (I use S3 integration). Or it only clears information about image in db, but file steel exist on the server?

with AutoForm I was using this predefined template (and you can see how it looks in issue #7 , but what is good way to realize it without AutoForm, only with blaze):

<template name="myFilePreview">
    <br />
    <img src="{{link}}">
    <br />
    {{#if isAdmin}}
        <a data-remove-file href="#">Remove</a>
    {{/if}}
</template>
dr-dimitru commented 7 years ago

Now, what about removing? It is enough to just remove image from collection Images?

Yes, if you follow AWS-S3-Integration docs. This part is responsible for synced removal:

  // Intercept FilesCollection's remove method to remove file from AWS:S3
  const _origRemove = UserFiles.remove;
  UserFiles.remove = function (search) {
    const cursor = this.collection.find(search);
    cursor.forEach((fileRef) => {
      _.each(fileRef.versions, (vRef) => {
        if (vRef && vRef.meta && vRef.meta.pipePath) {
          // Remove the object from AWS:S3 first, then we will call the original FilesCollection remove
          s3.deleteObject({
            Bucket: s3Conf.bucket,
            Key: vRef.meta.pipePath,
          }, (error) => {
            bound(() => {
              if (error) {
                console.error(error);
              }
            });
          });
        }
      });
    });

    //remove original file from database
    _origRemove.call(this, search);
  };
ApayRus commented 7 years ago

I used some code from comments in some issue from man with same problem, because from docs didn't work:

import { Meteor } from "meteor/meteor";
import { FilesCollection } from "meteor/ostrio:files";

import { _ } from "meteor/underscore";
import { Random } from "meteor/random";

import fs from "fs";
import stream from "stream";

var s3, bound, s3Conf = {};

if (Meteor.isServer) {

    import S3 from "aws-sdk/clients/s3";

    s3Conf = Meteor.settings.s3 || {};
    bound = Meteor.bindEnvironment((callback) => {
        return callback();
    });

    // Create a new S3 object
    s3 = new S3({
        secretAccessKey: s3Conf.secret,
        accessKeyId: s3Conf.key,
        region: s3Conf.region,
        sslEnabled: true,
        httpOptions: {
            timeout: 6000,
            agent: false
        }
    });
}

var Images = new FilesCollection({
    debug: false,
    collectionName: "Images",
    allowClientCode: true, // Disallow remove files from Client
    onBeforeUpload(file) {
        // Allow upload files under 10MB, and only in png/jpg/jpeg formats
        if (file.size <= 1048576 && /png|jpg|jpeg|gif|svg/i.test(file.extension)) {
            return true;
        } else {
            return 'Please upload image, with size equal or less than 1MB';
        }
    },
    onAfterUpload(fileRef) {
        var self = this;
        _.each(fileRef.versions, (vRef, version) => {
            const filePath = "files/" + (Random.id()) + "-" + version + "." + fileRef.extension;
            s3.putObject({
                ServerSideEncryption: "AES256",
                StorageClass: "STANDARD",
                Bucket: s3Conf.bucket,
                Key: filePath,
                Body: fs.createReadStream(vRef.path),
                ContentType: vRef.type,
            }, (error) => {
                bound(() => {
                    if (error) {
                        console.error(error);
                    } else {

                        const upd = { $set: {} };
                        upd["$set"]["versions." + version + ".meta.pipePath"] = filePath;

                        self.collection.update({
                            _id: fileRef._id
                        }, upd, function(updError) {
                            if (updError) {
                                console.error(updError);
                            } else {
                                console.log("Uploaded to S3");
                                self.unlink(self.collection.findOne(fileRef._id), version);
                            }
                        });
                    }
                });
            });
        });
    },
    interceptDownload(http, fileRef, version) {
        let path;

        if (fileRef && fileRef.versions && fileRef.versions[version] && fileRef.versions[version].meta && fileRef.versions[version].meta.pipePath) {
            path = fileRef.versions[version].meta.pipePath;
        }

        if (path) {

            const opts = {
                Bucket: s3Conf.bucket,
                Key: path
            };

            if (http.request.headers.range) {
                const vRef = fileRef.versions[version];
                let range = _.clone(http.request.headers.range);
                const array = range.split(/bytes=([0-9]*)-([0-9]*)/);
                const start = parseInt(array[1]);
                let end = parseInt(array[2]);
                if (isNaN(end)) {
                    // Request data from AWS:S3 by small chunks
                    end = (start + this.chunkSize) - 1;
                    if (end >= vRef.size) {
                        end = vRef.size - 1;
                    }
                }
                opts.Range = `bytes=${start}-${end}`;
                http.request.headers.range = `bytes=${start}-${end}`;
            }

            const fileColl = this;
            s3.getObject(opts, function(error) {
                if (error) {
                    console.error(error);
                    if (!http.response.finished) {
                        http.response.end();
                    }
                } else {

                    if (http.request.headers.range && this.httpResponse.headers["content-range"]) {
                        // Set proper range header in according to what is returned from AWS:S3
                        http.request.headers.range = this.httpResponse.headers["content-range"].split("/")[0].replace("bytes ", "bytes=");
                    }

                    const dataStream = new stream.PassThrough();
                    fileColl.serve(http, fileRef, fileRef.versions[version], version, dataStream);
                    dataStream.end(this.data.Body);
                }
            });

            return true;
        }

        return false;
    }
});

global.Images = Images;

if (Meteor.isServer) {

    Meteor.publish("files.images.all", function() {
        return Images.find().cursor;
    });

} else {
    Meteor.subscribe("files.images.all");
}

export default Images;

S3 is black box for me. Should I learn its docs? In my case images don't remove from server?

dr-dimitru commented 7 years ago

because from docs didn't work

What actually not working in the AWS S3 tutorial? Do you have errors? - if you do, we will fix it.

S3 is black box for me. Should I learn its docs?

Sure, you're better to know what you're doing.

In my case images don't remove from server?

Only from server and DB, as you don't have a hook to remove a file from S3 with s3.deleteObject()

ApayRus commented 7 years ago

What actually not working in the AWS S3 tutorial?

sorry, I don't remember, I discussed it here in issues about 2 months ago. finally I have found solution.

what about my previos realisation? this part with removing image was in AutoForm plugin? Now, when I don't use it , where should I paste this part of code?

What I published in prev message, it is my whole images.js collection file.

dr-dimitru commented 7 years ago

what about my previos realisation? this part with removing image was in AutoForm plugin?

AutoForm has not relation to how do you initialize FilesCollection instance. If you take a look on mf-autoform quick start, you will see what construction new FilesCollection({/*...*/}); should be defined by you, and not handled by AutoForm package.

Now, when I don't use it , where should I paste this part of code?

What code? As I mentioned above using AutoForm or not using it has no relation to AWS:S3 integration - It's two separate, unrelated things.

What I published in prev message, it is my whole images.js collection file.

Well... compare it to the AWS S3 tutorial, and update with what is missing on your end.

ApayRus commented 7 years ago

With autoform plugin it was just few strings of code, to handle removing file.

<template name="myFilePreview">
    <br />
    <img src="{{link}}">
    <br />
    {{#if isAdmin}}
        <a data-remove-file href="#">Remove</a>
    {{/if}}
</template>

I'm interesting , how to make remove file without autoform. I suppose there is some small snippet, I didn't find it in demo. And don't want to read all docs (

dr-dimitru commented 7 years ago

how to make remove file without autoform

.remove() method

And don't want to read all docs (

Then I cannot help you, though. You should read the docs before asking a question.

ApayRus commented 7 years ago

Ok. Thanks. Your support is awesome!