Search code examples
uploadstorageloopbackjsfile-type

Validate and Rename Image file from loopback-component-storage


I got the similar question as Modify image obtained from loopback-component-storage but the answer is not satisfactory to me.

Use the same example :

At client side

Upload.upload(
{
    url: '/api/containers/container_name/upload',
    file: file,
    fileName: "demoImage.jpg",
    //Additional data with file
    params:{
     username : username
    }
});

Here is the requirement:

  1. Validate the file type of the file
  2. Modify the name saved in server
  3. Reject if invalid file or username

Here is some reference that I used and encountered :

  • The username is required, so it should be a user's method. I added a remote method like it is in https://stackoverflow.com/a/31118294/5241407 and changed the api into /api/usermodel/:id/upload. Some codes were add in remoteMethod to send username to container.upload function. Is it possible that we valid the file type and change the file name in this phase so that I can return error if the it is invalid ?

  • I used configure-storage.js in boot file as it is in https://stackoverflow.com/a/31059880/5241407 But this solution is inadequate. If the client send invalid filetype the server will throw error, which is not expected. It is better to reject the query with a error response instead of throw a system error. So how to return error without throw a error in system level?

  • Once I upload a png file and checked the file.type in configure-storage.js, only to find that the file type is application/octet-stream instead of image/png. This is the code I used to probe: curl -X POST --header "Content-Type: multipart/form-data" --header "Accept: application/json" "HOST/api/usermodel/userId/upload" -F "[email protected]" This unexpected result may hinder the judgement of file type.


Solution

  • This is what I had done to validate the file type and modifying the file name,

    in datasources.local.js [container name is container]

    module.exports = {
      container: {
        root: './upload',
        acl: 'public-read',
        allowedContentTypes: ['image/jpg', 'image/jpeg', 'image/png', 'image/tiff'],
        maxFileSize: 10 * 1024 * 1024,
        getFilename: function(fileInfo) {
          var fileName = fileInfo.name.replace(/\s+/g, '-').toLowerCase();
          return 'image-' + new Date().getTime() + '-' + fileName;
        }
      }
    };
    

    Rejection of request should be handled via ACLs for authentication and authorization check. Reject based on file names can be done by a remote hook.

    Below is a sample (I didn't test this)

    Container.beforeRemote('create', function(context, comment, next) {
      if (context.req.body.fileName.length < 7) {
        context.res.statusCode = 401;
        next(new Error('Filename is too short!'));
      } else {
        next();
      }
    });
    

    I hope this can help you to figure out to the way you want.