How to Building a User Avatar Component With Node.js & TransloadIt

View: 351    Dowload: 0   Comment: 0   Post by: hanhga   Category: Javascript   Fields: Other

9 point/2 review File has been tested

A template contains assembly instructions in JSON format. Fire up your favourite text editor, begin some JSON:

{

}

… and let’s dive in.

Filtering Files

First we’ll add a step which utilizes the /file/filter robot to check the uploaded file’s MIME type, to ensure that it is an image. Add the following to your empty JSON document:

"steps":
  "files": {
    "robot": "/file/filter",
    "accepts": [
      [
        "${file.mime}",
        "regex",
        "image"
      ]
    ],
    "error_on_decline": true
  },

Let’s break this down.

We’re beginning with a step identified by the key files. You can call it what you want, but files makes sense in most cases.

Next we’re telling TransloadIt to use the /file/filter/ robot, which is used to perform some checks on the incoming files. In this case, we’re telling it what we want to accept; we ask it to extract the file’s MIME type and run a regular expression on it (image).

Should the test we’re setting fail, the error_on_decline parameter ensures an error is thrown rather than continuing to the next step.

In other words, we’re telling TransloadIt to reject any files which aren’t images.

Adding Resizing Steps

Now let’s create three more steps, each doing much the same thing — creating a derivative (that is, a particular size) of the incoming images.

We can call the steps whatever we like, so we’ll use names which provide some context to the derivatives — mediumlarge and thumbnail.

Let’s define the first of these steps:

"medium": {
  "use": ":original",
  "robot": "/image/resize",
  "width": 300,
  "height": 200,
  "resize_strategy": "fit"
},

Here we define a step named medium, which utilises the /image/resize robot. This takes a number of parameters, many of them optional, which are documented here.

The use parameter tells it to resize the original file.

In this case we’re providing the required dimensions — 300 by 200 pixels — as well as specifying a resize strategy. The available resize strategies are documented here, but essentially fit ensures that the image is resized to fit the specified dimensions, while preserving the aspect ratio.

The large step is virtually identical :

"large": {
  "use": ":original",
  "robot": "/image/resize",
  "width": 480,
  "height": 320,
  "resize_strategy": "fit"
},

Then the thumbnail step:

"thumbnail": {
  "use": ":original",
  "robot": "/image/resize",
  "width": 80,
  "height": 80,
  "resize_strategy": "crop"
},

At this stage, we’ve ensured that we’re dealing with an image, and we’ve resized it three times over to create three separate image derivatives. Next up, we’ll tell TransloadIt what to do with the newly-created derivatives.

Export

As noted previously, Transloadit won’t store our files for long — hosting isn’t what the service is all about — so we need to move the files somewhere more permanent.

We’re going to use the /s3/store file export robot to upload the files to an Amazon S3 bucket.

Here’s how you might configure that step:

"export": {
  "use": [
    "medium",
    "large",
    "thumbnail"
  ],
  "robot": "/s3/store",
  "path": "users/profiles/${fields.username}_${previous_step.name}.${file.ext}",
  "key": "YOUR-S3-AUTH-KEY",
  "secret": "YOUR-S3-AUTH-SECRET",
  "bucket": "YOUR-BUCKET-NAME"
}

The use parameter tells the robot to run this step for each of our resized images, thus generating three files on S3 for every upload. As you can see, mediumlarge and thumbnail match the identifiers of our three previous steps.

Then we specify the key — S3’s term for a path — used to store the resulting files using the pathconfiguration value. This, combined with the fully-qualified domain name of the bucket, later becomes the URI of the resulting derivative images.

In the example above, we’re using the following pattern:

users/profiles/${fields.username}_${previous_step.name}.${file.ext}

This pattern begins by prefixing the path with users/profiles/, then uses the value of a hidden form field named username which we’ll define shortly. It then concatenates that with the key which defines the previous step, which is the name of our derivatives. Finally, it adds the extension of the original file, which is accesible via the variable ${file.ext}.

That’s quite a mouthful, so perhaps it’s best illustrated with an example. Given a username of bob, this pattern will produce the following three paths:

users/profiles/bob_medium.jpg
users/profiles/bob_large.jpg
users/profiles/bob_thumbnail.jpg

There are all sorts of naming strategies you can employ, by chopping and changing the variables available to you. Foe example, consider the following pattern:

users/profiles/${fields.username}${file.meta.width}x${file.meta.width}.${file.ext}

This dynamically constructs a filename by concatenating the username, the resulting file’s width and height, and finally the file’s extension. This will result in something like this:

users/profiles/bob480x320.jpg

To simply use the original filename:

${file.name}

To ensure uniqueness, the following variable provides a unique 32-character prefix:

${unique_prefix}

For a full list of the available variables, refer to the section in the documentation on assembly variables.

Uploading Templates

Putting all of these steps together, our assembly instructions — which make up our template — look like this:

{
  "steps": {
    "files": {
      "robot": "/file/filter",
      "accepts": [
        [
          "${file.mime}",
          "regex",
          "image"
        ]
      ],
      "error_on_decline": true
    },
    "medium": {
      "use": ":original",
      "robot": "/image/resize",
      "width": 300,
      "height": 200,
      "resize_strategy": "fit"
    },
    "large": {
      "use": ":original",
      "robot": "/image/resize",
      "width": 480,
      "height": 320,
      "resize_strategy": "fit"
    },
    "thumbnail": {
      "use": ":original",
      "robot": "/image/resize",
      "width": 80,
      "height": 80,
      "resize_strategy": "crop"
    },
    "export": {
      "use": [
        "medium",
        "large",
        "thumbnail"
      ],
      "robot": "/s3/store",
      "path": "users/profiles/${fields.username}_${previous_step.name}.${file.ext}",
      "key": "YOUR-S3-AUTH-KEY",
      "secret": "YOUR-S3-AUTH-SECRET",
      "bucket": "YOUR-BUCKET-NAME"
    }
  }
}

If you haven’t already created an account with TransloadIt, you’ll need to do so now.

You’ll need to be logged in; then go to your dashboard (My Account). Under Integrations in the left sidebar, select Templates. Then click the New button in the top-right hand corner.

You’ll be asked to provide a name to identify your template — something like user_avatars should do just fine. Then paste in the JSON above (which you’ll also find at the root of the repository which accompanies this article) in — ensuring you’ve replaced the dummy S3 values with your own — and hit

The Example Application

You’ll find an example application to accompany this tutorial on Github.

In order to run it, you’ll need to ensure you have the following pre-requisites installed:

  • Node.js
  • npm
  • MongoDB
  • Bower
npm install
bower install

There are a couple of elements in the application worth covering briefly.

Here is the schema definition for the User model:

var userSchema = mongoose.Schema({
  username : { type: String, required: true, unique: true },
  email    : { type: String, required: true, unique: true },
  password : { type: String, required: true },
  avatar   : { type: mongoose.Schema.Types.Mixed, required: false }
});

Notice how we include an avatar field of type Mixed. This will allow us to specify the avatar as a hash, for example:

user.avatar = {
  thumbnail : 'http://your.bucket.name.aws.amazon.com/user/profile/bob_thumbnail.jpg',
  medium    : 'http://your.bucket.name.aws.amazon.com/user/profile/bob_medium.jpg',
  large     : 'http://your.bucket.name.aws.amazon.com/user/profile/bob_large.jpg'
};

Now that the basic structure is in place, let’s look at TransloadIt’s jQuery plugin.

The jQuery Plugin

The easiest way to integrate with TransloadIt on the client-side is to use the official jQuery plugin, although there are other alternatives, as we’ll see later in the article.

The latest version of the plugin is avaialble via the following URL:

https://assets.transloadit.com/js/jquery.transloadit2-latest.js

The minimal integration involves the following steps:

  • You bind the plugin to your form
  • The plugin “hijacks” the form submission, sending files directly to Transloadit
  • The plugin waits until the files have been uploaded AND processed
  • Transloadit returns a JSON object with the results, which will also include the URLs to the newly-generated files
  • It creates a hidden textarea element containing the JSON from Transloadit
  • The form is submitted to your application

Here’s a very simple example of initializing the plugin, telling it to use a template:

$(function() {
  $('#upload-form').transloadit({
    wait: true,
    params: {
      auth: {
        key: 'YOUR-AUTH-KEY'
      },
      template_id: 'YOUR-TEMPLATE-ID'
    }
  });
});

However as we noted in the previous part, exposing your authentication credentials in your client-side code is a bad idea. Instead, we’ll use a signature.

Signatures

Signatures are a more secure alternative to using authentication tokens, though they require some server-side work.

In essence using signatures requires that instead of sending a bunch of instructions to TransloadIt from your client-side app, you encode the instructions and encrypt them using the HMAC algorithm in conjunction with your private authentication key. A temporary token — i.e. signature — is generated as a result, which is restricted to that particular combination of instructions. Because it’s temporary, then if that token becomes compromised then it will very quickly become useless.

You needn’t worry about the ins-and-outs of generating the signature yourself, since we can use a third-party library to handle the process. If you’re using Node.js, the official SDK will take care of it for you.

To install the library:

npm install transloadit --save

Now create an instance of the TransloaditClient class, providing it with your authentication details:

var TransloaditClient =   require('transloadit');
var transloadit       =   new TransloaditClient({
      authKey     : config.transloadit.auth_key,
      authSecret  : config.transloadit.auth_secret
    });

Next, define the parameters for the action you want to take. That can either be in the form of a set of assembly instructions:

var params = {
  steps: {
    // ...
  }
};

Or, in our case, we simply provide the ID of our template:

var params = {
  template_id: 'YOUR-TEMPLATE-ID'
};

To create the signature:

var sig = transloadit.calcSignature(params);

This results in a hash containing a signature — an access token, of sorts — as well as the parameters you’ll need to call the service. So our sig object will look something like this:

{
  signature: "fec703ccbe36b942c90d17f64b71268ed4f5f512",
  params: {
    template_id: 'YOUR-TEMPLATE-ID',
    auth: {
     key: 'idfj0gfd9igj9dfjgifd8gfdj9gfdgf',
     expires: '2015-06-25T10:05:35.502Z'
    }
  }
}

In order to pass this to our Handlebars templates so that our JavaScript can utilise it, we need to create a very simple helper:

app.engine('.hbs', exphbs(
  {
    extname: '.hbs',
    defaultLayout: 'default',
    helpers : {
      json : function(context) {
        return JSON.stringify(context);
      }
    }
  }
));

Let’s now put this together to define the account route, which will include our avatar upload form:

// The account page
app.get('/account', ensureAuthenticated, function(req, res){

  // Require the TransloadIt client
  var TransloaditClient = require('transloadit');
  
  // Create an instance of the client
  var transloadit       =   new TransloaditClient({
    authKey     : config.transloadit.auth_key,
    authSecret  : config.transloadit.auth_secret
  });

  // Build the Transloadit parameters...
  var params = {
    template_id  :  config.transloadit.template_id
  };

  // ...and generate the signature
  var sig = transloadit.calcSignature(params);  

  return res.render('account', {
    user: req.user,
    sig : sig
  });
});

Then, in the corresponding template (views/account.hbs), let’s start with some very simple HTML:

<h2>Hello, {{ user.username }}</h2>

{{# if user.avatar }}
<img src="{{ user.avatar.thumbnail }}" id="avatar">
{{else}}
<img src="/avatar.png" id="avatar">
{{/if}}

<form method="POST" action="/avatar" id="avatar-form">
  <input type="file" name="image" id="avatar-upload">
  <input type="hidden" name="username" value="{{user.username}}">
</form>

Now add the JavaScript, beginning with some variable initialization using our json Handlebars helper:

var sig = {{{ json sig }}};

Now we’ll bind the TransloadIt plugin to the upload form:

$(function() {
  $('#avatar-form').transloadit({
    wait: true,
    params: JSON.parse(sig.params),
    signature: sig.signature,
    fields: true,
    triggerUploadOnFileSelection: true,
    autoSubmit: false,
    onSuccess: function(assembly) {
      $('img#avatar').attr('src', assembly.results.thumbnail[0].url + '?' + (new Date()).getTime() );
      var derivatives = {
        thumbnail : assembly.results.thumbnail[0].url,
        medium : assembly.results.medium[0].url,
        large : assembly.results.large[0].url
      };
      $.ajax({
        type: 'post',
        url: '/avatar',
        data: derivatives,
        success: function(resp){
          console.log(resp);
        }
      })
    }
  });
});

This is more complex than the minimal integration initialization we looked at earlier, so let’s go through it a bit at a time.

We’re pulling in the params and signature from the sig variable, which we generated on the server and then encoded as JSON. Because the params part is nested, we use JSON.parse() to convert it back into an object, from which TransloadIt will extract the relevant parameters.

To provide visual feedback to the user, we also grab the URL of the thumbnail and modify the avatar on the page to show the newly-uploaded image.

Finally, we use Ajax to POST that data silently back to our application.

Here’s the avatar route to capture that data:

// Ajax callback for setting the avatar
app.post('/avatar', ensureAuthenticated, function(req, res){
  req.user.avatar = req.body
  req.user.save(function(err) {
    if(err) {
      return res.send('error');
    }
    return res.send('ok');
  });
});

Advanced Usage

Before we wrap up, let’s just take a brief look at a couple of the more advanced aspects of TransloadIt.

Other Client-Side Options

You don’t have to use the provided jQuery plugin. In the Community Projects section of the documentation you’ll find a number of alternatives, including a plugin for Bootstrap, one for drag n’ drop, an Angular plugin or support for plain old XHR, among others.

The XHR one might be worth you looking at in more detail. It’s a bare-bones solution which offers plenty of flexibility, whilst requiring you to provide your own feedback — for example some sort of upload indicator. It’s also worth noting that once it has uploaded the file, it tries to determine when the assembly has been completed by polling the server at intervals of 1000ms.

Notifications

Rather than have users wait around for their uploads to be processed, you can use notifications to ping your application when the files are ready. Using this approach a user only need wait until the upload has completed.

Notifications are easy to implement from a consumer point-of-view; simply include a notify_url with your assembly instructions, for example:

{
  auth       : { ... },
  steps      : { ... },
  notify_url : "http://example.com/webhooks/incoming/transloadit"
}

 

How to Building a User Avatar Component With Node.js & TransloadIt

How to Building a User Avatar Component With Node.js & TransloadIt Posted on 09-03-2016  A template contains assembly instructions in JSON format. Fire up your favourite text editor, begin some JSON: 4.5/10 351

Comment:

To comment you must be logged in members.

Files with category

  • AngularJS and REST API

    AngularJS and REST API

    View: 57    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    This is a tutorial for those interested in a quick introduction to AngularJS and REST API. We will build the familiar Periodic Table of the Elements found in every chemistry textbook, and allow the user to select a Chemical Element by clicking on...

  • Collective Intelligence, Recommending Items Based on Similar Users' Taste

    Collective Intelligence, Recommending Items Based on Similar Users' Taste

    View: 85    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Using Collaborative Filtering to find people who share tastes, and for making automatic recommendations based on things that other people like.

  • Think Like a Bird for Better Parallel Programming

    Think Like a Bird for Better Parallel Programming

    View: 57    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Coding an application to run in parallel is hard, right? I mean, it must be hard or we’d see parallel programs everywhere. All we'd see are slick parallel apps that use every available core effortlessly. Instead multi-threaded apps are the exception...

  • Getting Started with the Bing Search APIs

    Getting Started with the Bing Search APIs

    View: 64    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Bing Search API is a set of REST interfaces that find web pages, news, images, videos, entities, related searches, spelling corrections, and more in response to queries from any programming language that can generate a web request. Applications that...

  • Brief Introduction of SocketPro High Performance and Scalable Persistent Message Queue

    Brief Introduction of SocketPro High Performance and Scalable Persistent Message Queue

    View: 260    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Continuous in-line request/result batching, real-time stream sending/processing, asynchronous data transferring and parallel computation for best performance and scalability

  • Iteration Over Java Collections with High Performance

    Iteration Over Java Collections with High Performance

    View: 53    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Java developers usually deal with Collections such as ArrayList, HashSet, Java 8 come with lambda and streaming API helps us to easily work with Collections. In most cases, we work with few thousands of items and performance isn't a concern. But in...

  • SR2JLIB - A Symbolic Regression Library for Java

    SR2JLIB - A Symbolic Regression Library for Java

    View: 58    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Grammar-Guided Genetic Programming library featuring: multi-threading, just-in-time compilation of individuals, dynamic class loading, and JNI interfacing with C/C++ code

  • Yet Another Fluent JDBC Wrapper in 200 Lines of Code

    Yet Another Fluent JDBC Wrapper in 200 Lines of Code

    View: 72    Download: 0   Comment: 0

    Category: Javascript     Fields: Other

    Those who are not convinced to use Hibernate to manage persistence are forced to use plain old JDBC API. Though powerful, it requires lot of typing to get it right. For example, retrieving user data from database often requires such code snippet:

 
File suggestion for you
File top downloads
Codetitle.net - library source code to share, download the file to the community
Copyright © 2015. All rights reserved. codetitle.net Develope by Vinagon .Ltd