Node.js Weekly Update - 24 March, 2017

By Ferenc Hamori

Node.js Weekly Update - 24 March, 2017

Below you can find RisingStack‘s collection of the most important Node.js news, projects & updates from this week:

1. End-to-End Testing with Nightwatch.js

Nightwatch.js enables you to “write end-to-end tests in Node.js quickly and effortlessly that run against a Selenium/WebDriver server”.

  • End-to-end testing is part of the black-box testing toolbox. This means that as a test writer, you are examining functionality without any knowledge of internal implementation.

  • End-to-end testing can also be used as user acceptance testing, or UAT. UAT is the process of verifying that the solution actually works for the user.

2. I’ve been a Web Developer for 17 Years, and this is what I learned

Daniel Khan has a 17 year long web development carrier behind him, so he decided to share his insights during NodeConfBP (RisingStack’s Node.js Conference).

Node.js Weekly Update - 24 March, 2017

A few insights:

  • History repeats itself and the tech industry is most likely heading towards another crash – so developers must prepare themselves.
  • The Broken Windows theory fits well with coding, so remember to always write code for your future self!
  • You shouldn’t jump on a latest fashionable JS framework bandwagon all the time.
  • The module system is kind of broken, there are hundreds of modules solving the same problem. It’s hard to figure out what to use.
  • Information on StackOverflow is often wrong, don’t blindly copypaste code from there!

And so on..

3. npm announced free Orgs for Open-Source projects

Today, we’re excited to announce that npm Orgs, our collaboration tool for helping teams manage permissions and share their code, is free for all developers of open source packages. You may invite an unlimited number of collaborators to manage an unlimited number of public packages for $0.

Node.js Weekly Update - 24 March, 2017

4. Build a “Serverless” Slack Bot in 9 Minutes with Node.js and StdLib

Slack bots — they’re fun, they’re useful, and people are building new businesses around bot interaction models on a daily basis.

Node.js Weekly Update - 24 March, 2017

StdLib is a Function as a Service software library. The easiest way to think of it is to imagine if AWS Lambda and GitHub had a child, then asked NPM and Twilio to be the godparents — scalable microservices with no server administration, easy command line management, version immutability, service discovery, and the ability to charge customers for premium services you’ve built on a per-request basis.

5. Requiring modules in Node.js: Everything you need to know

When Node invokes that require() function with a local file path as the function’s only argument, Node goes through the following sequence of steps:

  • Resolving: To find the absolute path of the file.
  • Loading: To determine the type of the file content.
  • Wrapping: To give the file its private scope. This is what makes both the require and module objects local to every file we require.
  • Evaluating: This is what the VM eventually does with the loaded code.
  • Caching: So that when we require this file again, we don’t go over all the steps another time.

In this article, I’ll attempt to explain with examples these different stages and how they affect the way we write modules in Node.

Latest Node.js Releases

○ Node v6.10.1 (LTS)

IMPORTANT: This Node.js Version became the default on Amazon Lambda!

  • performance: The performance of several APIs has been improved.
    • Buffer.compare() is up to 35% faster on average.
    • buffer.toJSON() is up to 2859% faster on average.
    • fs.*statSync() functions are now up to 9.3% faster on average.
    • os.loadavg is up to 151% faster.
    • process.memoryUsage() is up to 34% faster.
    • querystring.unescape() for Buffers is 15% faster on average.
    • querystring.stringify() is up to 7.8% faster on average.
    • querystring.parse() is up to 21% faster on average.
  • IPC: Batched writes have been enabled for process IPC on platforms that support Unix Domain Sockets.
    • Performance gains may be up to 40% for some workloads.
  • child_process: spawnSync now returns a null status when child is terminated by a signal.
    • This fixes the behavior to act like spawn() does.
  • http:
    • Control characters are now always rejected when using http.request().
    • Debug messages have been added for cases when headers contain invalid values.
  • node: Heap statistics now support values larger than 4GB.
  • timers: Timer callbacks now always maintain order when interacting with domain error handling.

○ Version 7.7.4 (Current)

  • deps: Add node-inspect 1.10.6
  • inspector: proper WS URLs when bound to 0.0.0.0
  • tls: fix segfault on destroy after partial read.

Previously in the Node.js Weekly Update

In the previous Node.js Weekly Update we read fantastic articles about Serverless Node, a new course on Using npm scripts, Client-side routing, Concurrency in Node + v7.7.3 Released was released as well!

We help you to stay up-to-date with Node.js on a daily basis too. Check out our Node.js news page and its Twitter feed!

Source:: risingstack.com

Getting Started with Brunch: The Ultra-Fast Simple-Config Build Tool

By mwaleh

When it comes to build tools, web developers have a hard time choosing between Gulp, Grunt, Webpack, and Browserify to mention but a few. These tools are great helpers and they come with their own pros and cons. Unfortunately, a lot of time goes into learning, configuring and evaluating if the tool measures up to the task instead of actually coding.

Recently, I stumbled upon Brunch. Brunch is a build tool that has amazing capabilities which are provided out of the box performance. Brunch has actually been around before Grunt and Gulp, Unfortunately, it has not been marketed that much.

What is Brunch?

Brunch is purely an asset build tool with almost zero-config, seamless incremental compilation meant for rapid development.

Brunch compiles, concats and minifies your scripts and stylesheets. It also packages JavaScript files into AMD or CommonJS modules. Furthermore, it automatically applies plugins in the correct order and to the right files with no explicit setup necessary.

Brunch comes pre-equipped with a number of behaviors and features which include:

  • Categorization of source files into either JavaScript, templates or stylesheet.
  • Smart concatenation of these files towards one or more target files.
  • Module wrapping of JavaScript files.
  • Minification of resulting files in production mode.
  • Watching of source files and updating builds on the fly.

Why Brunch?

Brunch sets itself apart from other build tools through its technical and architectural aspects, which include in summary:

  • Speed and Simplicity
  • Configurations
  • Plugins
  • Commands
  • Live reload
  • Skeletons

Speed and Simplicity

Brunch was built for speed and simplicity.

One factor to consider when choosing a build tool is how fast it compiles or builds the project. A long build time is detrimental to a developer’s efficiency and performance.

Brunch uses pipelines instead of full builds. What this means is, when you make changes to a file, only the new content gets read and piped down to any number of processing avenues, be they sequential or parallel.

Moreover, Brunch goes a step further by using incremental build system and caching. Incremental builds are achieved by only rerunning the necessary build steps based on the detected changes, this immensely reduces the workload and time taken for a build to complete.

Here is an illustration of the Brunch pipeline.

Configurations

Brunch relies on configuration over code approach.

Configuration over Code approach reduces your configuration needs to the bare minimum, no code is needed. It also makes setting up the configuration easy and straight forward.

brunch-config. js or brunch-config.coffe is the config file used to manage the project. There are four main configuration properties that determine how Brunch will handle your project assets, these are:

  1. paths :
    Here you to specify a folder called ‘assets’ that is directly copied into your output folder(public) with no modifications.

  2. files :
    Most Brunch projects have two separate JavaScript files:

    • app.js, which contains your code, and
    • vendor.js for all external libraries, including bower packages.

    This allows you to package your files into modules without affecting external libraries.

  3. npm : Holds npm dependencies settings

  4. Plugins: Alters individual plugin settings.

Here is a sample of brunch-config.js file

module.exports = {
    paths: {
        public: '/user/www/deploy'
    },
    files: {
        javascripts: {
            joinTo: {
                'app.js': /^app/, // all js code from 'app/' ,
                'vendor.js': /^(?!app)/ // all BUT app js code - 'vendor/', 'node_modules/', etc
            }
        },
        stylesheets: {
            joinTo: 'app.css' /
        }
    },
    npm: {
        styles: {
            pikaday: ['css/pikaday.css']
        },
        globals: {
            Pikaday: 'pikaday'
        }
    },
    plugins: {
        on: ['postcss-brunch'],
        off: ['jade-brunch', 'handlebars-brunch'],
        npm: ['babel-brunch'],
        autoReload: {
            enabled: true
        }
    }
}

NB: Brunch has other settings but we won’t be discussing them for now.

Plugins

Brunch performs all transformations through plugins listed in package.jsons.

Commands

Brunch has three simple commands

  1. brunch new —> Creates a new project.
  2. brunch build —> Building and compiling the app’s assets.
  3. brunch watch —> Executes live builds and browser reloading.

Live reload

Brunch has built-in dev server with live reloads. Brunch automatic reloads the browser when using the brunch watch command.

Application Structure

Brunch has a simple application conventional structure which consists of
an App folder which contains any files that will be served statically e.g index.html images, JavaScript, CSS, templates or media files.

├── README.md
├── app         // Files inside `assets` folder will be copied to the public` dir.
│   ├── assets
│   │   └── index.html
│   └── initialize.js
├── brunch-config.js             // Basic assumptions about the project, like paths & outputs.
├── package.json               // Describes dependencies and Brunch plugins your app uses.
└── public                   // The "output" Brunch will regenerate on every build.
    ├── app.js              //  was generated from `initialize.js`
    ├── app.js.map        // Source mappings for simple debugging.
    └── index.html      // This was copied from our `app/assets`

This structure allows Brunch to easily identify which files are part of our app and which files are external libraries without having to write any complex regular expressions.

Skeletons

A Brunch Skeleton is simply a boilerplate

  • Skeletons provide a good starting point for new applications. For example, if you are building a React application you might run brunch new command and pass brunch/with-react as the repository option. This will clone your boilerplate from git://github.com/brunch/with-react.git.

  • Skeletons contain pre-required dependencies in package.json and providing a default Brunch configuration. Visit Brunch skeleton section to see a full list of available skeletons.

Brunch vs Webpack

If you are a JavaScript developer you must be asking, “what is the difference between Brunch and Webpack?”

It’s all a matter of preference. Both tools almost do the same thing. The upside for using Webpack is its ability to asynchronously load modules and cleverly process non-js/non-CSS assets. Although Webpack has a large community and support, most people spend a lot of time trying to find ways to make the right configurations. Brunch shines when it comes to handling configurations. You do not need to specify how to compile a file, every time you use it, just add a compiler plugin and voila!! everything works.

Setting up a basic Brunch project

Enough talking let us get started.

Prerequisites

We shall be setting up a simple project that uses ES6.

You need node
and Brunch installed on your system.

To install brunch run

$ npm i brunch -g

Creating the project structure

Creating a Brunch project structure is simple, we use the brunch new command.

In your terminal run the following command

$ brunch new myproject -s es6

This command does the following:

  1. It creates a folder called myproject
  2. Next, it clones our es6 skeleton. This creates our App folder and configuration files.
  3. Once the cloning is done npm install is activated, this installs app dependencies and brunch plugins

Our folder structure should look like this once the cloning is done.

myproject
├── README.md
├── app                             // Main folder that handles our source files
│   ├── assets
│   │   └── index.html             // Folder stores static files
│   ├── components
│   │   └── App.jsx               // Stores our React component and .jsx files
│   ├── initialize.js
│   └── styles                    // Will store all our styling sheets
│       └── application.css
├── brunch-config.js              // Maintains our project configurations
└── package.json                  // Holds plugins and project dependencies

Project Configuration

Let’s have a look at the generated package.json

# package.json

{
  "name": "your-app",
  "description": "Description",
  "author": "Your Name",
  "version": "0.0.1",
  "repository": {
    "type": "git",
    "url": ""
  },
  "scripts": {
    "start": "brunch watch --server",
    "prod": "brunch build --production"
  },
  "dependencies": {},
  "devDependencies": {
    "auto-reload-brunch": "^2.0.0",
    "babel-brunch": "~6.0.0",
    "babel-preset-es2015": "~6.3.13",
    "brunch": "^2.4.0",
    "clean-css-brunch": "^2.0.0",
    "css-brunch": "^2.0.0",
    "javascript-brunch": "^2.0.0",
    "uglify-js-brunch": "^2.0.0" // default for all
  }
}

From package.json we can see the Babel ES6 transpiler has been installed through the Babel-brunch and babel-preset-es2015 dependencies. The other 5 dependencies are default dependencies that come with most skeletons.

 ....
  "auto-reload-brunch": "^2.0.0",       // adds automatic browser reloading support to brunch
    "brunch": "^2.4.0",                // Installs brunch locally
    "clean-css-brunch": "^2.0.0",   // CSS minifier
    "css-brunch": "^2.0.0",        // Provides CSS
    "uglify-js-brunch": "^2.0.0"  // JavaScript minifier

    .......

brunch-config.js does not need any configuration at this time. All the necessary settings are predefined. The file conforms to our discussion on configurations in the why brunch section

 # brunch-config.js
 module.exports = {
  files: {
    javascripts: {
      joinTo: {
        'vendor.js': /^(?!app)/, // Compiled from  js files except those in app folder
        'app.js': /^app/         // Compiles from all js files in the app
      }
    },
    stylesheets: {
    joinTo: 'app.css'  // compiled from css files in the app folder
    }
  },

  plugins: {
    babel: {presets: ['es2015']} // modifies es6 to es5
  }
};

NB: Brunch uses anymatch an npm module to match strings against configurable strings, globs, regular expressions or functions.

Building the App

To build our project, open ‘myproject’ folder
cd myprojectand run the build command.

 $ brunch build

brunch build compiles initialize.js into app.js and copies index.html into the public folder

 myproject
├── README.md
├── app
│   ├── assets
│   │   └── index.html
│   └── initialize.js
├── brunch-config.js
├── package.json
└── public
    ├── app.js          // compiled from app/initialize.js
    ├── app.js.map
    └── index.html // copied from app/assets/index.html

Running our app

Time to see what we have built, run the watch command.

   $ brunch watch --server

The bundle watch command automatically & efficiently rebuilds the app on every change. Adding --server flag makes it launch a HTTPserver at http://localhost:3333.

Open your browser and navigate to http://localhost:3333

Live Rebuild

So far nothing is displayed apart from the title. Open app/assets/index.html and add a header to the body and save it.


<!DOCTYPE html>
<!------- index.html----->
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
    <meta name="viewport" content="user-scalable=no, initial-scale=1,maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
    <title>Brunch with ES6</title>
    <script src="/vendor.js"></script>
    <script src="/app.js"></script>
    <script>
        require('initialize');
    </script>
</head>
<body>
    <div id="app"> <h2>Brunch is served</h2></div>
</body>
</html>

When the HTML file is saved, two things happen:

  1. On the terminal, a new log will notify us that compilation has taken place.

  2. The browser will display the header we just added.

Adding new dependencies

New dependencies added while the server is running are compiled effortlessly. There is no need of restarting the server.

Let’s install dimsum ( a random sentence generator library) and watch how Brunch will handle the new dependency.

While the server is running open a new terminal and run

$ npm install -S dimsum@0.1

You will notice immediately the install happens Brunch starts compiling the new changes

Next let’s use the new library in our code. Open app/initializer.js and add this code, save and check the browser.

// app/initializer.js
var dimsum = require('dimsum');

document.addEventListener('DOMContentLoaded', () => {
  // do your setup here
  console.log('Initialized app');
        document.body.innerHTML += "Yeaah!! <div><p>" + dimsum() +"</p></div>";

});

Yeaah!! The browser instantly picks the changes.

That’s all you need!!! You are ready to build your awesome app.

Conclusion

A recap of what we discussed:

  • Brunch was made for speed and simplicity
  • Brunch uses incremental builds instead of full builds
  • Brunch uses npm packages to run its plugins
  • Skeletons provides a good starting point for new applications
  • brunch new, brunch build and brunch watch --server are the only three commands that you need to get you started.
  • Brunch uses configuration over code approach
  • Live-build and live-reload make development workflow a piece of cake
  • Adding dependencies and plugins does not warrant you to restart your dev server when using Brunch

Brunch is a long time standing tool that does a job very well and if your project doesn’t require any special configuration or architecture it’s so easy to use.

I hope this inspires you to give it a try.

Source:: scotch.io

Build a Retrogames Archive with Node.JS, React, Redux and Redux-saga Part3: Authentication

By samuxyz

Here we are at the last part of the Retrogames Archive tutorial.
We have now a full working app written in JavaScript and it’s pretty much what we were looking to achieve.

However, at present all the users have full access to the common operations on the archive:
They can view, create and delete games entries.

In this last part of the tutorial we want to limit the operations of creating and deleting a game to allow only Authenticated user to perform them.
Plus, we are going to improve the UI with friendly notifications.

The project is always available on my github, the master branch contains the complete code.
Don’t forget to copy the up-to-date css in your project!

Prerequisites

The only prerequisite for this very last part of the tutorial is familiarity with JSON web tokens.
I take for granted all the other prerequisites described in the previous tutorials, part1 and part2.

NB: Since we are going to edit/update existing files I am going to highlight the changes with multi-line comments:

/* 
 * The new code starts after this comment...
 */ 

Table of Contents

Folder Structure

That’s the final folder structure:

 --app
 ----models
 ------game.js
 ------user.js
 ----routes
 ------game.js
 ------user.js
 --config
 ----index.js
 --client
 ----dist
 ------css
 --------style.css
 ------fonts
 --------PressStart2p.ttf
 ------index.html
 ------bundle.js
 ----src
 ------actions
 --------filestack.js
 --------games.js
 --------auth.js
 ------components
 --------About.jsx
 --------AddGamePanel.jsx
 --------Archive.jsx
 --------Contact.jsx
 --------Form.jsx
 --------Game.jsx
 --------GamesListManager.jsx
 --------Home.jsx
 --------index.js
 --------Login.jsx
 --------Modal.jsx
 --------Signup.jsx
 --------Welcome.jsx
 ------constants
 --------auth.js
 --------filestack.js
 --------games.js
 ------containers
 --------AddGameContainer.jsx
 --------GamesContainer.jsx
 --------reducers
 ----------auth.js
 ----------filestack.js
 ----------games.js
 ----------index.js
 ----------routing.js
 --------sagas
 ----------auth.js
 ----------filestack.js
 ----------games.js
 ----------index.js
 ------index.js
 ------routes.js
 ------store.js
 ------utils.js
 --.babelrc
 --package.json
 --server.js
 --webpack-loaders.js
 --webpack-paths.js
 --webpack.config.js
 --yarn.lock

If you compare this folder structure with the last one you should notice we mostly added files to handle the user authentication on both the server side (new routes and a model) and the client side (new components, reducers, sagas, actions etc.).

Authentication

Authentication is handled on both parts of your application, the server and the client, so let’s start with the server.

Server and JSON Token

We are using JSON web tokens to add a security layer to the app. Users should be able to sign up or login to modify the games archive.

First of all, open server.js and add two new routes:

import express from 'express';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
import morgan from 'morgan';

import { getGames, getGame, postGame, deleteGame } from './app/routes/game';
// New routes and middleware to manage the authentication
import { signup, login, verifyAuth } from './app/routes/user';

const app = express();
const port = process.env.PORT || 8080;

const options = {
  server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
  replset: { socketOptions: { keepAlive: 1, connectTimeoutMS : 30000 } }
};
mongoose.Promise = global.Promise;
mongoose.connect(YOUR_MONGODB_URL', options);

const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));

app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json());
app.use(morgan('dev'));

app.use(express.static(__dirname + '/client/dist'));

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header('Access-Control-Allow-Methods', 'GET,POST,DELETE');
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, x-access-token");
  next();
});

/*
 * New routes to handle Authentication
 */
app.post('/auth/login', login);
app.post('/auth/signup', signup);

app.route('/games')
    // verifyAuth is the security middleware to check the authentication
    .post(verifyAuth, postGame)
    .get(getGames);
app.route('/games/:id')
    .get(getGame)
    // Again delete requests pass through the security middleware
    .delete(verifyAuth, deleteGame);

app.route("*").get((req, res) => {
    res.sendFile('client/dist/index.html', { root: __dirname });
});

app.listen(port);

console.log(`listening on port ${port}`);
  • In the server main file we included two new routes in charge of handling the authentication: A POST requests to /auth/signup inserts a new user into the database and return the token while /auth/login checks the credentials and returns a token as well.
  • In addition, the route for posting a new game and the route for deleting a game are protected by verifyAuth middleware. Whenever the server receives a request to one of those routes, it first retrieves the token from the request header and verify it. Then, if the verification succeed, a call to next runs the function in charge of posting or deleting a game, otherwise the server simply returns a HTTP 403 forbidden status.

User Model

We now need to create the user model to store users in the database so we can go very simple:
We need e-mail, password and name fields. In particular, the password will be hashed and to do so we let’s add bcryptjs, a small library to help hashing passwords:

yarn add bcryptjs

Let’s add a new fileuser.js in /app/models and paste the following code:

// Require some dependencies
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcryptjs');

// Our schema defines 3 fields, notice email must be unique
var userSchema = new mongoose.Schema({
  email: { type: String, unique: true, lowercase: true },
  password: { type: String, select: false },
  name: String
});

userSchema.pre('save', function (next) {
  var user = this;
  // before saving a hashed version of the password is created and saved into the db
  bcrypt.genSalt(10, function (err, salt) {
    bcrypt.hash(user.password, salt, function (err, hash) {
      user.password = hash;
      next();
    });
  });
});

// This utility function comes handy during authentication
userSchema.methods.comparePwd = function(password, done) {
  // Compare the password sent by the user with the one stored in the db
  bcrypt.compare(password, this.password, (err, isMatch) => {
    done(err, isMatch);
  });
};

// Export the model
module.exports = mongoose.model('User', userSchema);

Authentication Routes and Middleware

The logic to authenticate the user is also in charge to create the token to be sent as response:
To create the token we can define payload with some useful information:

  1. sub: The subject is the user name. In the client the token can be decoded and the user name shown in the app along with a welcome message.
  2. exp: The expiration date is set to 1 day and to easily set it we are gonna install moment, very useful JavaScript library to work with dates.

So let’s install jsonwebtoken and moment:

yarn add jsonwebtoken moment

In server.js we defined two new routes and a middleware all residing in the same file /app/routes/user.js. Let’s create it and past the following code:

// Our new dependencies
import jwt from 'jsonwebtoken';
import moment from 'moment';
// We import the User model we have just defined
import User from '../models/user';
// The config file contains the secret to sign the token
import config from '../../config';

// Utility function to create and return the token, it requires TOKEN_SECRET from config
const createToken = name => {
  var payload = {
    sub: name,
    exp: moment().add(1, 'day').unix()
  };
  return jwt.sign(payload, config.TOKEN_SECRET);
}

// signup function for the /auth/signup route
const signup = (req, res) => {
  // query the database to make sure the e-mail is not taken already
  User.findOne({ email: req.body.email }, (err, existingUser) => {
    if (existingUser) {
    // HTTP 409 status is sent in case the e-mail is taken
      return res.status(409).json({ message: 'Email is already taken' });
    }

    // A new user is created with the information sent by the client
    const user = Object.assign(new User(), req.body);
    user.save((err, result) => {
      if (err) {
        res.send(err);
      }
      // Notice we also send the token as we want the user to be immediately logged in
      res.json({
        message: 'Welcome to Retrogames, you are now logged in',
        token: createToken(result.name)
      });
    });
  });
};

// Login function for /auth/login
const login = (req, res) => {
  // Query the database for user with that specific e-mail
  User.findOne({ email: req.body.email }, '+password', (err, user) => {
    if (!user) {
    // If the user doesn't exist just send a HTTP 401 status
      return res.status(401).json({ message: 'Invalid email/password' });
    }
    /* If the user exists, the password sent by the client is compared with the one in the db
    with the utilily function comparePwd
   */
    user.comparePwd(req.body.password, (err, isMatch) => {
      if (!isMatch) {
    // In case of wrong password, we send another HTTP 401 status
        return res.status(401).send({ message: 'Invalid email/password' });
      }
      // Correct information from the client, a token is sent
      res.json({ message: 'You are now logged in', token: createToken(user.name) });
    });
  });
};

// verifyAuth middleware to protect post and delete routes
const verifyAuth = (req, res, next) => {
  // Get the token from the header x-access-token
  const token = req.headers['x-access-token'];
  if (token) {
    // Verifies the token and the expiration
    jwt.verify(token, config.TOKEN_SECRET, function(err, payload) {
      // If the verification fails it returns http status 403
      if (err) {
        return res.status(403).send({
          message: 'Failed to authenticate token.'
        });
      } else {
        // Goes to the next route since there are no errors
        next();
      }
    });
  } else {
    // Requests without token return http status 403
    return res.status(403).send({
        message: 'No token provided.'
    });
  }
};

// Export the functions for server.js
export {
  signup,
  login,
  verifyAuth
};

There are 4 functions we created and 3 of them are exported for further usage in server.js.

  • createToken: It’s an utility function in charge to create and return a valid token.
  • signup: The function receives a new user’s information to create a new user entry in the database and returns the token. Before that, it checks if the e-mail was taken by another user before.
  • login: Whenever a user try to authenticate to /auth/login, the function first retrieves the correct user from the database (given the e-mail) and then verify the password. If all goes right, it sends the token back to the client.
  • verifyAuth: This is the middleware in charge to protect the archive: Only authenticated user can create or delete games.

Take a look at createToken: To sign the token we need a secret string that we imported from a config file, let’s create /config/index.js and paste the following code:

const TOKEN_SECRET = process.env.TOKEN_SECRET || 'YOUR_SECRET_STRING';

export default {
  TOKEN_SECRET
};

Replace YOUR_SECRET_STRING with a string of your choice.

The server side is done, let’s test it with Postman!

Test the Server

The first thing we can do is to try to add a new game with no token in the header to verify whether the server actually refuses your request or not:

POST Request to /games

in Postman, send a new game to localhost:8080/games and you should receive a HTTP 403 status with message “No token provided.”:

The middleware seems to be working fine! Let’s create a user now:

POST Request to /auth/signup

We need to send an e-mail, name and password to the server at /auth/signup, let’s see if it works:

As you can see we received a token, let’s now use it for creating a new game!

Authenticated POST Request to /games

We copy the token in the header tab for the post request. Here is the result:

And the game was successfully created!

Finally, we want to simulate the login request.

POST Request to /auth/login

Let’s login to the server by sending e-mail and password:

And this works too, we can now go working on the client-side!

Client

In the client-side of the app we want show the buttons to login, sign-up or logout so let’s take a look at these two screenshots:

  1. The user is not authenticated:

  • The users can login or sign-up.
  • Since the user is not authenticated, he/she cannot add/delete any games.
  1. The user is authenticated:

  • The user is now authenticated so the buttons to login/sign-up don’t show.
  • The user has now the right to add/delete a game. Notice on the top right the welcome message along with the logout button.

Finally, the views to login/sign-up are pretty straightforward:

Manage the Routing with Redux

Before writing the authentication logic, let’s think about the steps to login/signup:
Once the user clicks on the login/register button, the client communicates with the server and if all goes well it receives back the token. At this point, a redirection the user to /games should happen.
I find react-router-redux package very useful because we can control the routing in the state and we have a handy action-creator push to dispatch actions to the reducer and change view.

Let’s add it by running:

yarn add react-router-redux

To use the push action-creator we need to add a new middleware when configuring the store:

In /client/src/store.js paste the following code:

import {
  createStore,
  applyMiddleware,
  compose
} from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootSaga from './sagas';
import reducer from './reducers';
/* 
 * Here we imported the routerMiddleware
 */ 
import { routerMiddleware } from 'react-router-redux';
import { hashHistory } from 'react-router';

const configureStore = () => {
  const sagaMiddleware = createSagaMiddleware();
  /*
   * It requires the app history as parameter
   */ 
  const routeMiddleware = routerMiddleware(hashHistory);
  const store = createStore(
    reducer,
    /* 
     * we add it right after sagaMiddleware 
     */ 
    applyMiddleware(sagaMiddleware, routeMiddleware)
  );
  sagaMiddleware.run(rootSaga);

  return store;
}
export default configureStore;

Since we are using Immutable for the state we need to define the routing reducer by ourselves as well as pass a selector to access the payload state and convert it to a JavaScript object.

NB: These steps are not necessary with a mutable state.

Let’s create the reducer in /client/src/reducers/routing.js:

// This is a standard definition for the routing reducer
import Immutable from 'immutable';
import { LOCATION_CHANGE } from 'react-router-redux';

const initialState = Immutable.fromJS({
  locationBeforeTransitions: null
});

export default (state = initialState, action) => {
  if (action.type === LOCATION_CHANGE) {
    return state.set('locationBeforeTransitions', action.payload);
  }

  return state;
};

This is pretty straightforward, there is just an action to interact with the reducer and it comes directly from react-router-redux. We also gotta edit the index.js in /client/src/reducers:

import { combineReducers } from 'redux-immutable';
import { reducer as form } from 'redux-form/immutable';
import games from './games';
import filestack from './filestack';
/* 
 * Here we imported the routing reducer
 */ 
import routing from './routing';

export default combineReducers({
  games,
  form,
  filestack,
  /* 
   * Combine routing as well
   */ 
  routing,
});

The last thing to do is to call syncHistoryWithStore to get the routing part of the state and convert it to an object.

In /client/src/routes.js paste the following code:

import React from 'react';
import { Provider } from 'react-redux';
import configureStore from './store';
import { Router, Route, hashHistory, IndexRoute } from 'react-router';
import { AddGameContainer, GamesContainer } from './containers';
import { Home, Archive, Welcome, About, Contact } from './components';
/* 
 * Here we imported syncHistoryWithStore
 */ 
import { syncHistoryWithStore } from 'react-router-redux';

const store = configureStore();
/* 
 * Sync navigation events with the store
 */
const history = syncHistoryWithStore(hashHistory, store, {
  selectLocationState (state) {
    return state.get('routing').toObject();
  }
});

const routes = (
  <Provider store={store}>
    <Router history={history}>
      <Route path="/" component={Home}>
        <IndexRoute component={Welcome} />
        <Route path="/about" component={About} />
        <Route path="/contact" component={Contact} />
      </Route>
      <Route path="/games" component={Archive}>
        <IndexRoute component={GamesContainer} />
        <Route path="add" component={AddGameContainer} />
      </Route>
    </Router>
  </Provider>
);

export default routes;

That’s all, the navigation is now synchronized with the store and we can dispatch actions to change the views.
If you are interested in digging more into redux and immutability I suggest you to take a look at redux-immutable documentation where it also further explains what we have just done.

Time to write the login.

User Login

Let’s start by the view, create a Login component in /client/src/components/Login.jsx and paste the following code:

// We import a bunch of dependencies
import React, { PureComponent } from 'react';
import { Link } from 'react-router';
import { Field, reduxForm } from 'redux-form/immutable';
// Some action-creators we are going to write later
import * as authActionCreators from '../actions/auth';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

class Login extends PureComponent {
  login () {
    // dispatch action to the redux-saga
    this.props.authActions.loginUser(this.props.location.query.next || '/games');
  }

  render () {
    const { picture, uploadPicture } = this.props;
    return (
      <div className="row scrollable">
        <div className="col-md-offset-2 col-md-8">
          <div className="text-left">
            <Link to="/games" className="btn btn-info">Back</Link>
          </div>
       <div className="panel panel-default">
         <div className="panel-heading">
        <h2 className="panel-title text-center">Login</h2>
         </div>
         <div className="panel-body">
           <form>
                <div className="form-group text-left">
                  <label htmlFor="name">Name</label>
                  <Field
                    name="email"
                    type="text"
                    className="form-control"
                    component="input"
                    placeholder="Enter the name"
                  />
                </div>
                <div className="form-group text-left">
                  <label htmlFor="password">Password</label>
                  <Field
                    name="password"
                    component="textarea"
                    className="form-control"
                    placeholder="Enter the password"
                    rows="5"
                  />
                </div>
          <button 
            type="button" 
            className="btn btn-submit btn-block" 
            onClick={() => this.login()}
          >
          Login
          </button>
          </form>
        </div>
      </div>
       </div>
     </div>
    );
  }
}
// Bind the action-creators so that we can call them as props
function mapDispatchToProps (dispatch) {
  return {
    authActions: bindActionCreators(authActionCreators, dispatch)
  };
}
// Wrap the login into a reduxForm HOC
export default reduxForm({ form: 'login' })(connect(null, mapDispatchToProps)(Login));

The Login component is nothing but a redux-form asking for e-mail and password (remember the test with Postman?).
The login button is responsible for calling the login function which dispatches the action described by loginUser.

Let’s make the Login available through /client/src/components/index.js:

import About from './About';
import Contact from './Contact';
import Form from './Form';
import Game from './Game';
import GamesListManager from './GamesListManager';
import Home from './Home';
import Archive from './Archive';
import Modal from './Modal';
import Welcome from './Welcome';
/* 
 * Here we import Login.jsx
 */ 
import Login from './Login';

export {
  About,
  Contact,
  Form,
  Game,
  GamesListManager,
  Home,
  Archive,
  Modal,
  Welcome,
  Login // Export Login
};

What about the login route? We wanto to show the login view at localhost:8080/auth/login so let’s edit /client/src/routes.js:

import React from 'react';
import { Provider } from 'react-redux';
import configureStore from './store';
import { Router, Route, hashHistory, IndexRoute } from 'react-router';
import { AddGameContainer, GamesContainer } from './containers';
/* 
 * We can conveniently import Login with all the other components
 */ 
import { Home, Archive, Welcome, About, Contact, Login } from './components';
/* 
 * Here we imported syncHistoryWithStore
 */ 
import { syncHistoryWithStore } from 'react-router-redux';

const store = configureStore();
/* 
 * Sync navigation events with the store
 */ 
const history = syncHistoryWithStore(hashHistory, store, {
  selectLocationState (state) {
    return state.get('routing').toObject();
  }
});

const routes = (
  <Provider store={store}>
    <Router history={history}>
      <Route path="/" component={Home}>
        <IndexRoute component={Welcome} />
        <Route path="/about" component={About} />
        <Route path="/contact" component={Contact} />
      </Route>
      <Route path="/games" component={Archive}>
        <IndexRoute component={GamesContainer} />
        <Route path="add" component={AddGameContainer} />
      </Route>
      {
      /* 
       * The Archive component defines the layout that works for both Login and Signup
       */
    }
      <Route path="/auth" component={Archive}>
        <Route path="login" component={Login} />
       </Route>
    </Router>
  </Provider>
);

export default routes;

Notice the new Route with path /auth has component Archive, in fact the layout of the login page (and as we will see later, of the signup too) is very similar to the AddGame view so we can reuse it.

We haven’t defined the action-creators yet, let’s do it.

In /client/src/actions create a file auth.js and paste the following code:

// We always define constants
import {
  LOGIN_USER,
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILURE,
} from '../constants/auth';

// Intercepted by a redux-saga
function loginUser (redirection) {
  return {
    type: LOGIN_USER,
    redirection
  };
}

// In case of successful response from the server
function loginUserSuccess (token) { // It carries the token!
  return {
    type: LOGIN_USER_SUCCESS,
    token
  };
}

// In case of failure
function loginUserFailure () {
  return {
    type: LOGIN_USER_FAILURE
  };
}

export {
  loginUser,
  loginUserSuccess,
  loginUserFailure
};
  • The loginUser action-creator dispatch a LOGIN_USER action which is intercepted by a saga we are writing later.
  • The saga sends user credentials to the server and wait for a token, then call loginUserSuccesful or loginUserFailure according to the response.

You should be already familiar with the pattern of writing 3 action-creators.

Let’s now define the constants, create a file auth.js in /src/client/constants:

// New constants for the login
const LOGIN_USER = 'LOGIN_USER';
const LOGIN_USER_SUCCESS = 'LOGIN_USER_SUCCESS';
const LOGIN_USER_FAILURE = 'LOGIN_USER_FAILURE';

export {
  LOGIN_USER,
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILURE,
};

The code is pretty straightforward, we export the constants to be used throughout the project.

Then, let’s create the reducer in a new file in /client/src/reducers/auth.js:

import Immutable from 'immutable';
// We neeed jwt-decode to take the user name from the token and store it in the state
import jwtDecode from 'jwt-decode';
import {
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILURE,
} from '../constants/auth';

// The initial state has no token hence no name and isAuthenticated is false
const initialState = Immutable.Map({
  isAuthenticated: false,
  token: null,
  name: null
});

export default (state = initialState, action) => {
  switch (action.type) {
    // Once the server sent a token, the saga dispatches loginUserSuccess 
    case LOGIN_USER_SUCCESS: { 
      return state.merge({
        isAuthenticated: true,
        token: action.token,
        name: jwtDecode(action.token).sub
      });
    }
    // In case of failure the state goes back to the initial one
    case LOGIN_USER_FAILURE: return state.merge(initialState);
    default: return state;
  }
}
  • isAuthenticated is a very important field, later we will use to query the state and see whether the user is authenticated or not.
  • Moreover, we decoded the token to get the user name and include it in the welcome message.

Have you noticed we imported jwt-decode? That’s a simple library to help us decode the token in the frontend side of the app. Let’s install it:

yarn add jwt-decode

Let’s update /client/src/reducers/index.js:

import { combineReducers } from 'redux-immutable';
import { reducer as form } from 'redux-form/immutable';
import games from './games';
import filestack from './filestack';
/* 
 * Import the auth reducer
 */ 
import auth from './auth';
import routing from './routing';

export default combineReducers({
  games,
  form,
  filestack,
  auth, // Combine it with the other reducers
  routing
});

Finally, we need a new saga to communicate with the server.
So create auth.js in /client/src/sagas and paste the following code:

import { takeLatest } from 'redux-saga';
import { put, call, select } from 'redux-saga/effects';
// We import the constant to use it in the watcher
import { LOGIN_USER } from '../constants/auth';
import {
  loginUserSuccess,
  loginUserFailure
} from '../actions/auth';
// push action-creators to change the view
import { push } from 'react-router-redux';
// We want to show a notification to the user once logged in
import {actions as toastrActions} from 'react-redux-toastr';

// Selector to get the credential from the form
const getForm = (state, form) => {
  return state.getIn(['form', form]).toJS();
}

// Fetch sends the credentials to the server
const sendCredentials = (route, credentials) => {
  return fetch(`http://localhost:8080/auth/${route}`, {
    headers: new Headers({
      'Content-Type': 'application/json'
    }),
    method: 'POST',
    body: JSON.stringify(credentials)
  })
  .then(response => {
    if (response.status === 200) {
      return response.json(); // This contains the token!
    }
    throw response;
  });
};

function* loginUser (action) {
  // The redirection changes the view to the main page
  const { redirection } = action;
  try {
    const credentials = yield select(getForm, 'login');
    const result = yield call(sendCredentials, 'login', credentials.values);
    // Redux-toastr shows the users nice notifications
    yield put(toastrActions.add({
       type: 'success', // success is a green notification
       title: 'Retrogames Archive',
       message: result.message
    }));
    // We also save the token in the local storage
    localStorage.setItem('token', result.token); 
    // We send the token to the reducer
    yield put(loginUserSuccess(result.token));
    // Redirect to the main page!
    yield put(push(redirection));
  } catch (e) {
    // The status 401 has a personalized message to show in a notification
    let message = '';
    if(e.status === 401) {
      message = 'Invalid email/password';
    } else {
      message = 'Sorry, an error occured!';
    }
    // Set the state to initial state
    yield put(loginUserFailure());
    yield put(toastrActions.add({
       type: 'error', // Red notification
       title: 'Retrogames Archive',
       message: message
     }));
  }
}

// Saga watcher to intercept LOGIN_USER
export function* watchLoginUser () {
  yield takeLatest(LOGIN_USER, loginUser);
}

Although the loginUser seems more complicated than the others we wrote in the past, it is actually very easy, the comments in the code highlight the steps.
So, you must have notice redux-toastr that, as the name says, implement toastrs notifications to be used with redux.

We haven’t added them yet, so let install it:

yarn add redux-toastr

Redux-toastr requires to add its own reducer, edit /client/src/reducers/index.js:

import { combineReducers } from 'redux-immutable';
import { reducer as form } from 'redux-form/immutable';
import games from './games';
import filestack from './filestack';
import auth from './auth';
import routing from './routing';
/* 
 * Import redux-toastr reducer
 */ 
import { reducer as toastr} from 'react-redux-toastr'

export default combineReducers({
  games,
  form,
  filestack,
  auth,
  routing,
  toastr // Combine toastr
});

Then, it requires its own css, edit /client/dist/index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Retrogames Archive</title>
    <link rel="icon" href="https://cdn.filestackcontent.com/S0zeyXxRem6pL6tHq9pz">
<!-- redux-toastr css to style the notifications -->
    <link href="http://diegoddox.github.io/react-redux-toastr/4.4/react-redux-toastr.min.css" rel="stylesheet" type="text/css">
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

  </head>
  <body>
    <div id="content"></div>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="https://api.filestackapi.com/filestack.js"></script>
    <script src="./bundle.js"></script>
  </body>
</html>

The last step is to add ReduxToastr component at the root of the app, let’s edit /client/src/routes.js:

import React from 'react';
import { Provider } from 'react-redux';
import configureStore from './store';
import { Router, Route, hashHistory, IndexRoute } from 'react-router';
import { AddGameContainer, GamesContainer } from './containers';
import { Home, Archive, Welcome, About, Contact, Login } from './components';
import { syncHistoryWithStore } from 'react-router-redux';
/* 
 * Import ReduxToastr
 */ 
import ReduxToastr from 'react-redux-toastr';

const store = configureStore();
const history = syncHistoryWithStore(hashHistory, store, {
  selectLocationState (state) {
    return state.get('routing').toObject();
  }
});

const routes = (
  <Provider store={store}>
  {
  /* 
   * We add the div wrapper as Route and ReduxToastr are on the same level 
   */
   }
    <div className="wrapper">
    <Router history={history}>
      <Route path="/" component={Home}>
        <IndexRoute component={Welcome} />
        <Route path="/about" component={About} />
        <Route path="/contact" component={Contact} />
       </Route>
       <Route path="/games" component={Archive}>
         <IndexRoute component={GamesContainer} />
         <Route path="add" component={AddGameContainer} />
       </Route>
       <Route path="/auth" component={Archive}>
         <Route path="login" component={Login} />
       </Route>
    </Router>
    {
      /* 
       * we can customize it's behavior and look through props 
      /*
    }
    <ReduxToastr
        timeOut={2000}
        newestOnTop={false}
        preventDuplicates={true}
        position="top-right"
        transitionIn="fadeIn"
        transitionOut="fadeOut"
      />
   </div>
  </Provider>
);

export default routes;

For more information regarding Redux-toastr options, check the documentation.

The login logic is done, let’s do the signup that you will see it’s very similar.

User Signup

Let’s create Signup.jsx in /client/src/components and paste the following code:

import React, { PureComponent } from 'react';
import { Link } from 'react-router';
import { Field, reduxForm } from 'redux-form/immutable';
import * as authActionCreators from '../actions/auth';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

class Signup extends PureComponent {
  // signupUser dispatches SIGNUP_USER to be intercepted by a redux-saga
  register () {
    this.props.authActions.signupUser();
  }

  render () {
    const { picture, uploadPicture } = this.props;
    return (
      <div className="row scrollable">
    <div className="col-md-offset-2 col-md-8">
         <div className="text-left">
            <Link to="/games" className="btn btn-info">Back</Link>
         </div>
      <div className="panel panel-default">
        <div className="panel-heading">
          <h2 className="panel-title text-center">
        Sign Up
          </h2>
        </div>
       <div className="panel-body">
        <form onSubmit={this.props.handleSubmit}>
                <div className="form-group text-left">
                  <label htmlFor="email">E-mail</label>
                  <Field
                    name="email"
                    type="text"
                    className="form-control"
                    component="input"
                    placeholder="Enter the e-mail"
                  />
                </div>
                <div className="form-group text-left">
                  <label htmlFor="name">Name</label>
                  <Field
                    name="name"
                    type="text"
                    className="form-control"
                    component="input"
                    placeholder="Enter the name"
                  />
                </div>
                <div className="form-group text-left">
                  <label htmlFor="password">Password</label>
                  <Field
                    name="password"
                    component="textarea"
                    className="form-control"
                    placeholder="Enter the password"
                    rows="5"
                  />
                </div>
        <button 
          type="button" 
          className="btn btn-submit btn-block" 
          onClick={() => this.register()}
        >
        Register
        </button>
        </form>
       </div>
      </div>
    </div>
     </div>
    );
  }
}
// Bint the action-creators to be used as props
function mapDispatchToProps (dispatch) {
  return {
    authActions: bindActionCreators(authActionCreators, dispatch)
  };
}
// redux-form HOC to wrap the component
export default reduxForm({ form: 'signup' })(connect(null, mapDispatchToProps)(Signup));

It’s very similar to Login so let’s move on and edit /client/src/components/index.js to make the component available:

import About from './About';
import Contact from './Contact';
import Form from './Form';
import Game from './Game';
import GamesListManager from './GamesListManager';
import Home from './Home';
import Archive from './Archive';
import Modal from './Modal';
import Welcome from './Welcome';
import Login from './Login';
/* 
 * Import Signup
 */ 
import Signup from './Signup';

export {
  About,
  Contact,
  Form,
  Game,
  GamesListManager,
  Home,
  Archive,
  Modal,
  Welcome,
  Login,
  Signup // Export Signup
};

And then we create its own route at /auth/signup. Let’s edit /client/src/routes.js and paste the following:

import React from 'react';
import { Provider } from 'react-redux';
import configureStore from './store';
import { Router, Route, hashHistory, IndexRoute } from 'react-router';
import { AddGameContainer, GamesContainer } from './containers';
/* 
 * We also import Signup
 */ 
import { Home, Archive, Welcome, About, Contact, Login, Signup } from './components';
import { syncHistoryWithStore } from 'react-router-redux';
import ReduxToastr from 'react-redux-toastr';

const store = configureStore();
const history = syncHistoryWithStore(hashHistory, store, {
  selectLocationState (state) {
    return state.get('routing').toObject();
  }
});

const routes = (
  <Provider store={store}>
    <div className="wrapper">
    <Router history={history}>
      <Route path="/" component={Home}>
        <IndexRoute component={Welcome} />
        <Route path="/about" component={About} />
        <Route path="/contact" component={Contact} />
       </Route>
       <Route path="/games" component={Archive}>
         <IndexRoute component={GamesContainer} />
         <Route path="add" component={AddGameContainer} />
       </Route>
       <Route path="/auth" component={Archive}>
         {
         /* 
          * Signup Route 
          */
           }
         <Route path="signup" component={Signup} />
         <Route path="login" component={Login} />
       </Route>
    </Router>
    <ReduxToastr
        timeOut={2000}
        newestOnTop={false}
        preventDuplicates={true}
        position="top-right"
        transitionIn="fadeIn"
        transitionOut="fadeOut"
      />
   </div>
  </Provider>
);

export default routes;

To define the action-creators we are going to edit /client/src/actions/auth.js:

import {
  LOGIN_USER,
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILURE,
  /*
   * New constants to be imported
   */ 
  SIGNUP_USER,
  SIGNUP_USER_SUCCESS,
  SIGNUP_USER_FAILURE
} from '../constants/auth';

function loginUser (redirection) {
  return {
    type: LOGIN_USER,
    redirection
  };
}

function loginUserSuccess (token) {
  return {
    type: LOGIN_USER_SUCCESS,
    token
  };
}

function loginUserFailure () {
  return {
    type: LOGIN_USER_FAILURE
  };
}
/* 
 * signupUser dispatched from Signup component
 */ 
function signupUser () {
  return {
    type: SIGNUP_USER
  };
}
/* 
 * SignupUserSuccess send the token to be added to the state
 */ 
function signupUserSuccess (token) { // It carries the token!
  return {
    type: SIGNUP_USER_SUCCESS,
    token
  };
}
/* 
 * In case of server failure
 */
function signupUserFailure () {
  return {
    type: SIGNUP_USER_FAILURE
  };
}

export {
  loginUser,
  loginUserSuccess,
  loginUserFailure,
  signupUser,
  signupUserSuccess,
  signupUserFailure
};

As we did for login, let’s add the constants in /client/src/constants/auth.js:

const LOGIN_USER = 'LOGIN_USER';
const LOGIN_USER_SUCCESS = 'LOGIN_USER_SUCCESS';
const LOGIN_USER_FAILURE = 'LOGIN_USER_FAILURE';
/* 
 * New constants
 */
const SIGNUP_USER = 'SIGNUP_USER';
const SIGNUP_USER_SUCCESS = 'SIGNUP_USER_SUCCESS';
const SIGNUP_USER_FAILURE = 'SIGNUP_USER_FAILURE';

export {
  LOGIN_USER,
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILURE,
  SIGNUP_USER,
  SIGNUP_USER_SUCCESS,
  SIGNUP_USER_FAILURE
};

And now we are going to edit the reducer in /src/clients/reducers/auth.js:

import Immutable from 'immutable';
import jwtDecode from 'jwt-decode';
import {
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILURE,
  /* 
   * New constants
   */ 
  SIGNUP_USER_SUCCESS,
  SIGNUP_USER_FAILURE
} from '../constants/auth';

const initialState = Immutable.Map({
  isAuthenticated: false,
  token: null,
  name: null
});
// The actions dispatched by the signup logic do exactly the same of login ones
export default (state = initialState, action) => {
  switch (action.type) {
    case SIGNUP_USER_SUCCESS:
    case LOGIN_USER_SUCCESS: {
      return state.merge({
        isAuthenticated: true,
        token: action.token,
        name: jwtDecode(action.token).sub
      });
    }
    case SIGNUP_USER_FAILURE: // All the failures simply return the initial state
    case LOGIN_USER_FAILURE: return state.merge(initialState);
    default: return state;
  }
}

Someone may wonder why we should define different constants for login and signup as they practically do the same:
This is actually a personal choice, in my case I want to make it easier to read and understand that the action belongs to the signup logic instead of the login one.

Finally, let’s edit /client/src/sagas/auth:

import { takeLatest } from 'redux-saga';
import { put, call, select } from 'redux-saga/effects';
import { LOGIN_USER, SIGNUP_USER } from '../constants/auth';
import {
  loginUserSuccess,
  loginUserFailure,
  /* 
   * We import the signup action-creators
   */
  signupUserSuccess,
  signupUserFailure
} from '../actions/auth';
import { push } from 'react-router-redux';
import {actions as toastrActions} from 'react-redux-toastr';

const getForm = (state, form) => {
  return state.getIn(['form', form]).toJS();
}

const sendCredentials = (route, credentials) => {
  return fetch(`http://localhost:8080/auth/${route}`, {
    headers: new Headers({
      'Content-Type': 'application/json'
    }),
    method: 'POST',
    body: JSON.stringify(credentials)
  })
  .then(response => {
    if (response.status === 200) {
      return response.json();
    }
    throw response;
  });
};

function* loginUser (action) {
  const { redirection } = action;
  try {
    const credentials = yield select(getForm, 'login');
    const result = yield call(sendCredentials, 'login', credentials.values);
    yield put(toastrActions.add({
       type: 'success',
       title: 'Retrogames Archive',
       message: result.message
    }));
    localStorage.setItem('token', result.token);
    yield put(loginUserSuccess(result.token));
    yield put(push(redirection));
  } catch (e) {
    let message = '';
    if(e.status === 401) {
      message = 'Invalid email/password';
    } else {
      message = 'Sorry, an error occured!';
    }
    yield put(loginUserFailure());
    yield put(toastrActions.add({
       type: 'error',
       title: 'Retrogames Archive',
       message: message
     }));
  }
}
/* 
 * the new sagas to handle signup
 */ 
function* signupUser () {
  try {
    // We get the credentials from the form in the state
    const credentials = yield select(getForm, 'signup');
    const result = yield call(sendCredentials, 'signup', credentials.values);
    // Show a notification in the browser 
    yield put(toastrActions.add({
       type: 'success',
       title: 'Retrogames Archive',
       message: result.message
    }));
    // Set the token in the local storage
    localStorage.setItem('token', result.token);
    // Update the state with the token
    yield put(signupUserSuccess(result.token));
    // Redirect to /games
    yield put(push('/games'));
  } catch (e) {
    // As we did for loginUser, we show a personalized message according to the error status
    let message = '';
    if(e.status === 409) {
      message = 'Email is already taken';
    } else {
      message = 'Sorry, an error occured!';
    }
    // Set the auth portion of the state to the initial value
    yield put(signupUserFailure());
    yield put(toastrActions.add({
       type: 'error',
       title: 'Retrogames Archive',
       message: message
     }));
  }
}

export function* watchLoginUser () {
  yield takeLatest(LOGIN_USER, loginUser);
}

/* 
 * Signup watcher
 */
export function* watchSignupUser () {
  yield takeLatest(SIGNUP_USER, signupUser);
}

And we are done for the sign-up logic! We need to run the two sagas watchLoginUser and watchSignupUser. Edit /client/src/sagas/index.js and paste the following code:

import {
  watchGetGames,
  watchDeleteGame,
  watchPostGame
} from './games';
import { watchUploadPicture } from './filestack';
/* 
 * The new watchers in charge of the authentication
 */ 
import { watchLoginUser, watchSignupUser } from './auth';

export default function* rootSaga () {
  yield [
    watchGetGames(),
    watchDeleteGame(),
    watchPostGame(),
    watchUploadPicture(),
    watchLoginUser(),
    watchSignupUser()
  ];
}

Now you can create a user and login by manually type /auth/signup or /auth/login.However the app has no buttons to login/sign-up, plus users who actually are not authenticated can still create or delete games.
It’s now time to protect the app and this concludes our tutorial.

Authentication Wrapper

So we want to protect some routes in our app and possibly hide/show the buttons to delete or add a game. To do so we are going to rely on redux-auth-wrapper.
So what is this authentication wrapper? The idea is that we can decouple Authentication and Authorization with high order components that wrap other components, this is kinda useful to protect routes too!

Let’s go on and install it:

yarn add redux-auth-wrapper

if you open /client/src/routes.js you should know that on /games/add the router is going to show AddGameContainer, however this should not happen when the user is not authenticated. Otherwise he/shes is going to be redirected to the login page.

Let’s see it in action, we can create a utils.js file in /client/src and paste the following code:

 // We import the wrapper component
 import { UserAuthWrapper } from 'redux-auth-wrapper';

// We export a simple function which receives some options and return the wrapper
export default (options) => UserAuthWrapper(options);

The options we provide are useful to define customized rules for the app.

Now in /client/routes.js paste the following code:

import React from 'react';
import { Provider } from 'react-redux';
import configureStore from './store';
import { Router, Route, browserHistory, hashHistory, IndexRoute } from 'react-router';
import { AddGameContainer, GamesContainer } from './containers';
import { Home, Archive, Welcome, About, Contact, Login, Signup } from './components';
import { UserAuthWrapper } from 'redux-auth-wrapper';
import { push } from 'react-router-redux';
import { syncHistoryWithStore } from 'react-router-redux';
import ReduxToastr from 'react-redux-toastr';
/* 
 * We imported the utility function
 */ 
import userAuthenticated from './utils';

const store = configureStore();
const history = syncHistoryWithStore(hashHistory, store, {
  selectLocationState (state) {
    return state.get('routing').toObject();
  }
});
/* 
 * Here we set the rules for the wrapper
 */ 
const options = {
  authSelector: state => state.get('auth'),
  predicate: auth => auth.get('isAuthenticated'),
  redirectAction: ({ pathname, query }) => {
    if(query.redirect) {
    // If the user is not logged in go to /auth/login
      return push(`auth${pathname}?next=${query.redirect}`);
    } 
  },
  wrapperDisplayName: 'UserIsJWTAuthenticated'
};
const requireAuthentication = userAuthenticated(options);

const routes = (
  <Provider store={store}>
    <div className="wrapper">
      <Router history={history}>
        <Route path="/" component={Home}>
          <IndexRoute component={Welcome} />
          <Route path="/about" component={About} />
          <Route path="/contact" component={Contact} />
        </Route>
        <Route path="/games" component={Archive}>
          <IndexRoute component={GamesContainer} />
       {
         /* 
          * you can see that AddGameContainer is now literally wrapped 
          */
          }
          <Route path="add" component={requireAuthentication(AddGameContainer)} />
        </Route>
        <Route path="/auth" component={Archive}>
          <Route path="signup" component={Signup} />
          <Route path="login" component={Login} />
        </Route>
      </Router>
      <ReduxToastr
        timeOut={2000}
        newestOnTop={false}
        preventDuplicates={true}
        position="top-right"
        transitionIn="fadeIn"
        transitionOut="fadeOut"
      />
    </div>
  </Provider>
);

export default routes;

So what have we actually done?

  • authSelector receives a selector of part of the state, in our case the auth has it’s contain isAuthenticated
  • predicate receives the result from authSelector and according to the boolean balue of isAuthenticated it will either go to games/add or to auth/login.
  • As you can redirectAction is a redux action-creator, we check the redirection and in case push to /auth/login?next=query.redirect. query.redirect is actually /games/add so when the user logged in the view automatically shows the form to add a new game.
  • wrapperDisplayName is a name describing the authorization.

It’s great, in few lines of code we have now a wrapper we can reuse to protect all the other routes that require authentication.
However, we can do more than this, redux-auth-wrapper can actually hide/show any component, which is what we want to achieve:
Show/hide the delete game button, or show the add game button when the user is authenticated while replacing it with login and sign-up buttons when not authenticated.
Let’s how easy it is!

Let’s start from the delete button, to hide/show it we simply wrap it and pass the right options!
Edit /client/src/components/Game.jsx and paste the following code:

import React, { PureComponent } from 'react';
import { Link } from 'react-router';
/* 
 * We import our utility function
 */ 
import userAuthenticated from '../utils';

/* 
 * Here we set the rules to hide/show the delete button
 */ 
const options = {
  authSelector: state => state.get('auth'),
  predicate: auth => auth.get('isAuthenticated'),
  wrapperDisplayName: 'authDeleteGame',
  FailureComponent: null
};

/* 
 * We define the 'wrapper' version of the delete button
 */ 
const DeleteButton = userAuthenticated(options)(
  (props) => <button className="btn btn-danger" role="button" onClick={() => props.deleteGame(props.id)}>Delete</button>
);

export default class Game extends PureComponent {
  render () {
    const { _id, i, name, description, picture, toggleModal, deleteGame } = this.props;
    return (
      <div className="col-md-4">
        <div className="thumbnail">
          <div className="thumbnail-frame">
            <img src={picture} alt="..." className="img-responsive thumbnail-pic" />
          </div>
          <div className="caption">
            <h5>{name}</h5>
            <p className="description-thumbnail">{`${description.substring(0, 150)}...`}</p>
            <div className="btn-group" role="group" aria-label="...">
              <button className="btn btn-success" role="button" onClick={() => toggleModal(i)}>View</button>
           {
           /* 
            * the new DeleteButton 
            */
           }
              <DeleteButton deleteGame={deleteGame} id={_id} />
            </div>
          </div>
        </div>
      </div>
    );
  }
}
  • As we have done before to protect the rule, we check inside the app state and if isAuthenticated the button will show up in the page.
  • FailureComponent is just a component we can render in the page when the user is not authorized. In this case it’s set to null because there is no need but it comes handy with the sign-up/login panel instead.

Finally, we want to show the add game button when the user is authenticated, plus a welcome message and logout button. But, when the user is not logged in, then show the buttons sign-in and login.

Let’s have another look at the UI:

  1. User Authenticated
  2. User not Authenticated

Let’s create another component to achieve this, in /client/src/components create AddGamePanel.jsx and paste the following code:

import React, { PureComponent } from 'react';
import { Link } from 'react-router';
/* 
 * Import the utility function
 */ 
import userAuthenticated from '../utils';

class AddGamePanel extends PureComponent {
  render () {
    /* 
     * userName comes from the state while logout 
     * is an action creator we are going to define later 
     */
    const { userName, logout } = this.props;
    return (
      <div className="add-game-panel">
        <h5>Welcome back {userName}, <span onClick={logout}>Logout</span></h5>
        <Link to="/games/add" className="btn btn-danger">add a new Game!</Link>
      </div>
    );
  }
}
/* 
 * Auth-wrapper options
 */ 
const options = {
  authSelector: state => state.get('auth'),
  predicate: auth => auth.get('isAuthenticated'),
  wrapperDisplayName: 'authAddGame',
  /* 
   * This time the failure component are the buttons 
   * to authenticate the user or register a new one 
   */
  FailureComponent: () => {
    return (
      <div className="btn-group" role="group" aria-label="...">
        <Link to="/auth/signup" className="btn btn-primary">Sign Up</Link>
        <Link to="/auth/login" className="btn btn-danger">Login</Link>
      </div>
    );
  }
};

// We export it 
export default userAuthenticated(options)(AddGamePanel);

The options are totally the same as the delete buttons ones but this time we render FailureComponent when the user is not authenticated.

Now, let’s import it inside GamesListManager, edit /client/src/components/GamesListManager.jsx:

import React, { PureComponent } from 'react';
import { Link } from 'react-router';
import Game from './Game';
/* 
 * Import the new component
 */
import AddGamePanel from './AddGamePanel';

export default class GamesListManager extends PureComponent {

  render () {
    const {
      games,
      searchBar,
      setSearchBar,
      toggleModal,
      deleteGame,
      userName,
      /*
    * The new action-creator to be defined
    */ 
      logout
    } = this.props;

    return (
      <div className="container scrollable">
        <div className="row text-left">
        {
        /* 
         * we add the component 
         */
        }
          <AddGamePanel logout={logout} userName={userName}/>
        </div>
        <div className="row">
          <input
            type="search" placeholder="Search by Name" className="form-control search-bar" onKeyUp={setSearchBar} />
        </div>
        <div className="row">
        {
          games
            .filter(game => game.name.toLowerCase().includes(searchBar))
            .map((game, i) => {
              return (
                <Game  {...game}
                  key={game._id}
                  i={i}
                  toggleModal={toggleModal}
                  deleteGame={deleteGame}
                />
              );
            })
        }
        </div>
        <hr />
      </div>

    );
  }
}

Nothing exotic, we just render the component inside its parent GamesListManager.

The userName and logout props come from the GamesContainer so let’s edit /client/src/containers/GamesContainer.jsx:

import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import Immutable from 'immutable';
import { Modal, GamesListManager } from '../components';
import * as gamesActionCreators from '../actions/games';
import * as authActionCreators from '../actions/auth';
/* 
 * Add toastr to show notifcations
 */ 
import { toastr } from 'react-redux-toastr';

class GamesContainer extends PureComponent {
  constructor (props) {
    super(props);
    this.toggleModal = this.toggleModal.bind(this);
    this.deleteGame = this.deleteGame.bind(this);
    this.setSearchBar = this.setSearchBar.bind(this);
    // Bind logout to this
    this.logout = this.logout.bind(this);
  }

  componentDidMount () {
    this.getGames();
  }

  toggleModal (index) {
    this.props.gamesActions.showSelectedGame(this.props.games[index]);
    $('#game-modal').modal();
  }

  getGames () {
    this.props.gamesActions.getGames();
  }

  deleteGame (id) {
    this.props.gamesActions.deleteGame(id);
  }

  setSearchBar (event) {
    this.props.gamesActions.setSearchBar(event.target.value.toLowerCase());
  }
  /* 
   * The function calls an action to remove the user 
   * from the state, show a notification and    delete the token from the local storage 
   */
  logout () {
    this.props.authActions.logoutUser();
    toastr.success('Retrogames archive', 'Your are now logged out');
    localStorage.removeItem('token');
  }

  render () {
    const { games, selectedGame, searchBar, userName, authActions } = this.props;
    return (
      <div>
        <Modal game={selectedGame} />
        <GamesListManager
          games={games}
          searchBar={searchBar}
          setSearchBar={this.setSearchBar}
          toggleModal={this.toggleModal}
          deleteGame={this.deleteGame}
       {
       /* 
        * the new props to be passed 
        */
       }
          userName={userName}
          logout={this.logout}
        />
      </div>
    );
  }
}

function mapStateToProps (state) {
  return {
    games: state.getIn(['games', 'list'], Immutable.List()).toJS(),
    searchBar: state.getIn(['games', 'searchBar'], ''),
    selectedGame: state.getIn(['games', 'selectedGame'], Immutable.List()).toJS(),
    /* 
     * The name comes from token after being decoded
     */ 
    userName: state.getIn(['auth', 'name'])
  }
}

function mapDispatchToProps (dispatch) {
  return {
    gamesActions: bindActionCreators(gamesActionCreators, dispatch),
    authActions: bindActionCreators(authActionCreators, dispatch)
  };
}
export default connect(mapStateToProps, mapDispatchToProps)(GamesContainer);

As the container contains the logic it’s a connected component, this is where we can get the props for AddGamePanel.

To conclude, let’s create the logout action-creators in /client/src/actions/auth.js:

import {
  LOGIN_USER,
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILURE,
  /* 
   * Import a new constant
   */ 
  LOGOUT_USER,
  SIGNUP_USER,
  SIGNUP_USER_SUCCESS,
  SIGNUP_USER_FAILURE
} from '../constants/auth';

function loginUser (redirection) {
  return {
    type: LOGIN_USER,
    redirection
  };
}

function loginUserSuccess (token) {
  return {
    type: LOGIN_USER_SUCCESS,
    token
  };
}

function loginUserFailure () {
  return {
    type: LOGIN_USER_FAILURE
  };
}
/* 
 * The action-creator
 */ 
function logoutUser () {
  return {
    type: LOGOUT_USER
  };
}

function signupUser () {
  return {
    type: SIGNUP_USER
  };
}

function signupUserSuccess (token) {
  return {
    type: SIGNUP_USER_SUCCESS,
    token
  };
}

function signupUserFailure () {
  return {
    type: SIGNUP_USER_FAILURE
  };
}

export {
  loginUser,
  loginUserSuccess,
  loginUserFailure,
  logoutUser,
  signupUser,
  signupUserSuccess,
  signupUserFailure
};

And then add the constant in /client/src/constants/auth.js:

const LOGIN_USER = 'LOGIN_USER';
const LOGIN_USER_SUCCESS = 'LOGIN_USER_SUCCESS';
const LOGIN_USER_FAILURE = 'LOGIN_USER_FAILURE';
/* 
 * New constant
 */ 
const LOGOUT_USER = 'LOGOUT_USER';
const SIGNUP_USER = 'SIGNUP_USER';
const SIGNUP_USER_SUCCESS = 'SIGNUP_USER_SUCCESS';
const SIGNUP_USER_FAILURE = 'SIGNUP_USER_FAILURE';

export {
  LOGIN_USER,
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILURE,
  LOGOUT_USER,
  SIGNUP_USER,
  SIGNUP_USER_SUCCESS,
  SIGNUP_USER_FAILURE
};

Finally, the auth reducer is going to intercept the action LOGOUT_USER, edit /client/src/reducers/auth:

import Immutable from 'immutable';
import jwtDecode from 'jwt-decode';
import {
  LOGIN_USER_SUCCESS,
  LOGIN_USER_FAILURE,
  /* 
   * Import the logout constant
   */ 
  LOGOUT_USER,
  SIGNUP_USER_SUCCESS,
  SIGNUP_USER_FAILURE
} from '../constants/auth';

const initialState = Immutable.Map({
  isAuthenticated: false,
  token: null,
  name: null
});

export default (state = initialState, action) => {
  switch (action.type) {
    case SIGNUP_USER_SUCCESS:
    case LOGIN_USER_SUCCESS: {
      return state.merge({
        isAuthenticated: true,
        token: action.token,
        name: jwtDecode(action.token).sub
      });
    }
    case SIGNUP_USER_FAILURE:
    case LOGIN_USER_FAILURE: // initial state is naturally the logout state
    case LOGOUT_USER: return state.merge(initialState);
    default: return state;
  }
}

And that’s all, we added authentication to our Archive app!

There is only one last thing we can do: Whenever a user refreshes the page we should first look for the token in the local storage, in case it’s valid we can directly authenticate him/her. To make sure of this edit /client/src/routes.js:

import React from 'react';
import { Provider } from 'react-redux';
import configureStore from './store';
import { Router, Route, browserHistory, hashHistory, IndexRoute } from 'react-router';
import { AddGameContainer, GamesContainer } from './containers';
import { Home, Archive, Welcome, About, Contact, Login, Signup } from './components';
import { UserAuthWrapper } from 'redux-auth-wrapper';
import { push } from 'react-router-redux';
import { syncHistoryWithStore } from 'react-router-redux';
/* 
 * import the action-creator
 */ 
import { loginUserSuccess } from './actions/auth';
import ReduxToastr from 'react-redux-toastr';
import userAuthenticated from './utils';

const store = configureStore();
const history = syncHistoryWithStore(hashHistory, store, {
  selectLocationState (state) {
    return state.get('routing').toObject();
  }
});

const options = {
  authSelector: state => state.get('auth'),
  predicate: auth => auth.get('isAuthenticated'),
  redirectAction: ({ pathname, query }) => {
    if(query.redirect) {
      return push(`auth${pathname}?next=${query.redirect}`);
    }
  },
  wrapperDisplayName: 'UserIsJWTAuthenticated'
};
const requireAuthentication = userAuthenticated(options);

const routes = (
  <Provider store={store}>
    <div className="wrapper">
      <Router history={history}>
        <Route path="/" component={Home}>
          <IndexRoute component={Welcome} />
          <Route path="/about" component={About} />
          <Route path="/contact" component={Contact} />
        </Route>
        <Route path="/games" component={Archive}>
          <IndexRoute component={GamesContainer} />
          <Route path="add" component={requireAuthentication(AddGameContainer)} />
        </Route>
        <Route path="/auth" component={Archive}>
          <Route path="signup" component={Signup} />
          <Route path="login" component={Login} />
        </Route>
      </Router>
      <ReduxToastr
        timeOut={2000}
        newestOnTop={false}
        preventDuplicates={true}
        position="top-right"
        transitionIn="fadeIn"
        transitionOut="fadeOut"
      />
    </div>
  </Provider>
);

/* 
 * If the token exists let's log the user
 */ 
const token = localStorage.getItem('token');
if (token !== null) {
    store.dispatch(loginUserSuccess(token));
}

export default routes;

And this is the end of the tutorial, Congratulations!

Conclusions

In this part.3 of the tutorial to create a Retrogame Archive app we added a simple authentication logic to limit the actions users can do when not logged in: They can only view the games, to modify the database they must be authorized.

To do so we first created two useful roues on our Node.js server to handle signup and login. Both returns a token that it’s exchanged whenever the user wants to add or delete a game. To retrieve the token from HTTP requests we wrote a middleware.

In the client-side we added redux-auth-wrapper which helps us to write high order components to wrap routes or components. By doing so we can show/hide buttons and protect views from unauthorized users.

Further Improvements

It was definitely a long tutorial, divided in 3 parts, I hope you enjoyed it as I did while writing this fun app.
However there are tons of optimization that can be done, first of all a general refactoring of the components:
To name one, there may not be need separate components for signup and login views.

Here I summarizied a few suggestions:

  1. Writing constants and action-creators can become tedious (reducers included) so I suggest you to read the redux documentation to find strategies to reduce boilerplate.
  2. The same can be said for Redux-saga, take a look at the advanced concepts and you should get some hints on how to refactor the sagas we wrote.
  3. Finally, the webpack configuration to serve the bundle from Node.js is not optimized for production, which is why I set the NODE_ENV=build, not production. Also, Webpack 2 is at the time I wrote this tutorial very stable so I would suggest you all to start using it, the documentation to migrate from v1 to v2 is very complete.

Source:: scotch.io

How to get the title of a remote web page using javascript and NodeJS

By Adrian Matei

Octocat

When I add a new bookmark to my bookmarks collection, I set the title of the new bookmark, most of the time, the same as the title of the web page being bookmark –
I assume the authors have put some thought into it. To make this happen automatically, I am using a technique called web scraping1. I cannot do it in front end (angular), since most of the URLs are outside
of the https://bookmarks.codingpedia.org/ domain. So the magic happens in back end, in NodeJS, with the help of a library called cheerio2, thank you Matthew for that.
Cheerio is a fast, flexible, and lean implementation of core jQuery3 designed specifically for the server. Read on to learn how this works.

Source code for bookmarks.codingpedia.org is available on Github – frontend and backend.

Continue reading How to get the title of a remote web page using javascript and NodeJS

Finally! CSS Triangles Without Ugly Hacks

By Danny Markov

css-triangles

Anyone who has tried to make HTML upvote arrows, speech bubbles or other pointy elements, knows that in order to create a CSS-only triangle you have to use some sort of hack. The two most popular solutions are to create your triangles out of borders, or to use unicode characters.

We have to admit that both these CSS hacks are pretty clever but they still are terrible solutions, and as such make our code much uglier and less flexible. For instance, we can’t have a triangle with a background image, since borders and characters can only be one color.

Introducing Clip-path

Clip-path is a fairly new addition to the CSS spec that allows us to show only part of an element and hide the rest. Here is how it works:

Let’s say we have an ordinary rectangular div element. You can click Run in the editor below to view the rendered HTML.

(Play with our code editor on Tutorialzine.com)

To make a triangle we will need the polygon() function. It expects as argument comma separated 2D points which will define the shape of our mask. A triangle = 3 points. Try and change the values to see how the shape transforms.

(Play with our code editor on Tutorialzine.com)

Everything inside the path we created stays, everything outside it is hidden. This way we can make not only triangles, but all sorts of asymmetrical shapes that will behave like regular CSS blocks.

The only drawback of this technique is that we have to carefully calculate the coordinates of our points in order to get a good looking triangle.

Still, it’s way better than using borders or ▲.

Browser Support

If you open the caniuse page for clip-path things don’t look very good at first sight, but in reality the property works perfectly fine unprefixed in Chrome and with the -webkit- prefix in Safari. Firefox users have to wait till version 53. IE/Edge is behind the curve as usual but we can expect support sometime in the future.

Further Reading

The clip-path property has many other tricks up its sleeve, including some SVG magic. To find out more about it check out the links below.

  • Clip-path on MDN – here
  • In-depth tutorial for clip-path on Codrops – here
  • Clippy, a clip-path generator – here

Source:: Tutorialzine.com

Build A Tweet Bot With Python

By waleadesina

This article demonstrates how to build a tweet bot with Python programming language. Typically, a bot performs tasks that are both simple and repetitive in nature, at a much higher rate than would be possible for a human alone.

The possibilities of what could be achieved on Twitter is endless, and with 500 million+ tweets per day, there’s a lot of data to analyze and to play with. A tweet bot is a program that interacts with Twitter automatically like post tweets follow users, favorite or retweet tweets, or perform any other function possible on Twitter.

Twitter bots can be useful through providing information or updates, and they can also make Twitter more interesting for users.

What We’ll Build

There are different classifications of tweet bots depending on the function they perform. This tutorial would work through building a tweet bot that takes any image you tweet at it and randomly rearranges blocks of pixels of the image to create a new scrambled image and replies the tweet with the newly formed image.

Create Your Own Bot

Writing a Twitter bot is easy. You can write a Twitter bot in just about any language you please.

Prerequisites

In this tutorial we would be using Python programming language so one of the prerequisites includes a Python programming environment, other prerequisites are:

  1. A Twitter account
  2. Tweepy: An easy-to-use Python library for accessing the Twitter API
  3. PIL : Python Imaging Library

Create A Twitter Account

The first step is creating a Twitter account https://twitter.com/signup. Once this is done the next step is to create a new application.

Create a Twitter App

  • Go to apps.twitter.com and click on ‘Create New App ‘ button
  • Fill out the details of the form correctly
  • Read the developer agreement section, and check the box at the bottom if you agree. Then click on the ‘Create your Twitter application’ button

Keys and Access Tokens

In order to post to a Twitter account automatically, you have to get access keys for your account.

  1. After creating your new app, you would be redirected to its own page. If you weren’t, go to apps.twitter.com and click on your app’s name.
  2. On the app’s page, click on the ‘Keys and Access Tokens’ tab
  3. At the bottom of this page, click on the ‘Create my access token’ button.
  4. Make sure you make note of the following four keys, as you will need these later.

Coding The Bot

Twitter provides REST APIs you can use to interact with their service. There is also a bunch of Python-based clients out there that we can use without re-inventing the wheel. In particular, Tweepy in one of the most interesting and straightforward to use, so let’s install it:

pip install tweepy

We also need to install PIL, a Python Imaging Library (PIL) that adds image processing capabilities to the Python interpreter. This library supports many file formats and provides powerful image processing and graphics capabilities.You can install PIL with pip:

pip install Pillow

Now that we have tweepy and PIL installed, we can begin to lay the structure of the bot application

tweetbot 
|-- bot.py
|-- secrets.py

Storing Credentials

The secrets.py file holds valuable information which would be needed to access your Twitter account. Anyone who has access to these strings can use your Twitter account, so you don’t want to share these, or make them public.

 # secrets.py

consumer_key = 'YOUR-CONSUMER-KEY'
consumer_secret = 'YOUR-CONSUMER-SECRET'
access_token = 'YOUR-ACCESS-TOKEN'
access_secret = 'YOUR-ACCESS-SECRET'

Replace the following variables with values from the “Keys and Access Tokens” tab of your Twitter app.

OAuth Authentication

Tweepy supports OAuth authentication. Authentication is handled by the tweepy.AuthHandler class. In the bot.py add the following

# bot.py

import tweepy
from secrets import *

#create an OAuthHandler instance
# Twitter requires all requests to use OAuth for authentication
auth = tweepy.OAuthHandler(consumer_key, consumer_secret) 

auth.set_access_token(access_token, access_secret)

 #Construct the API instance
api = tweepy.API(auth) # create an API object

The api variable is now our entry point for most of the operations we can perform with Twitter. The API class provides access to the entire Twitter RESTful API methods. Each method can accept various parameters and return responses. Please refer to API Reference for more information.

Some of the many things we can do with the API like read tweets on your timeline


public_tweets = api.home_timeline()
for tweet in public_tweets:
    print(tweet.text)

Or get the list of all your followers


user = api.get_user('picscrambler')
for friend in user.friends():
   print(friend.screen_name)

Streaming With Tweepy

The tweet bot we will build in this tutorial would watch for images that were tweeted at it, and replies with scrambled pixel versions of the original image. To do these we would need a way to keep the connection open to being able to respond to all incoming and upcoming tweets, this is where the streaming API comes in. Tweepy makes it easier to use the Twitter streaming API by handling authentication, connection, creating and destroying the session, reading incoming messages, and partially routing messages.

The streaming API is quite different from the REST API because the REST API is used to pull data from Twitter but the streaming API pushes messages to a persistent session. This allows the streaming API to download more data in real time than could be done using the REST API. To read more about the Streaming API See the Twitter Streaming API Documentation.

Inside bot.py

#bot.py

import tweepy

#create a class inherithing from the tweepy  StreamListener
class BotStreamer(tweepy.StreamListener):

    # Called when a new status arrives which is passed down from the on_data method of the StreamListener
    def on_status(self, status):
        username = status.user.screen_name 
        status_id = status.id

    #entities provide structured data from Tweets including resolved URLs, media, hashtags and mentions without having to parse the text to extract that information
        if 'media' in status.entities:
            for image in status.entities['media']:
                tweet_image(image['media_url'], username, status_id)

Using the streaming API has three steps:

  • Create a class inheriting from StreamListener
  • Using that class create a Stream object
  • Connect to the Twitter API using the Stream

We just created a class that inherits from StreamListener class overriding the on_status method capturing the username of the account that posted the tweet and tweet id and checking if an image exists in the status object (tweet) and passes it all to the tweet_image function which we are yet to write.

Next, we create a stream object

# bots.py

myStreamListener = BotStreamer()

 #Construct the Stream instance
stream = tweepy.Stream(auth, myStreamListener)

A number of Twitter streams are available through Tweepy. Most cases will use the filter, the user_stream, or the sitestream method. For more information on the capabilities and limitations of the different streams, see Twitter Streaming API Documentation.

In this example, we will use a filter to stream all tweets tweeted at our bot . The track parameter is an array of search terms to watch for.

stream.filter(track=['@picscrambler'])

In this case, the track parameter should be the name of your Twitter application.

Scramble Image Pixel

Now let’s code up our tweet_image function

# bots.py

import requests
from io import BytesIO
from PIL import Image

def tweet_image(url, username, status_id):

    filename = 'temp.png'
    # send a get request
    request = requests.get(url, stream=True)
    if request.status_code == 200:
        # read data from downloaded bytes and returns a PIL.Image.Image object
        i = Image.open(BytesIO(request.content))
        # Saves the image under the given filename
        i.save(filename)
        scramble(filename)
        # Update the authenticated user's status
        api.update_with_media('scramble.png', status='@{0}'.format(username), in_reply_to_status_id=status_id)
    else:
        print("unable to download image")

We use the Python request http library to download the image from the url and write its content into a temp.png file using the Python image library then call a scramble function on the PIL image object to produce a scrambled pixel image which is then used to reply the original tweet using the API object.

We are yet to write our image scrambler function

# bots.py

import random

def scramble(filename):
    BLOCKLEN = 64  # Adjust and be careful here.

    img = Image.open(filename)
    width, height = img.size

    xblock = width // BLOCKLEN
    yblock = height // BLOCKLEN
    # creates sequence of 4-tuples (box) defining the left, upper, right, and lower pixel coordinate
    blockmap = [(xb * BLOCKLEN, yb * BLOCKLEN, (xb + 1) * BLOCKLEN, (yb + 1) * BLOCKLEN)
                for xb in range(xblock) for yb in range(yblock)]

    shuffle = list(blockmap)

    #shuffle the sequence
    random.shuffle(shuffle)

    # Creates a new image with the given mode and size.
    result = Image.new(img.mode, (width, height))
    for box, sbox in zip(blockmap, shuffle):
        # Returns a rectangular region from this original image.
        crop = img.crop(sbox)
        # Pastes the cropped pixel into the new image Object
        result.paste(crop, box)
    result.save('scramble.png')

At this point, the bots.py should look like this

# bots.py

import random
from io import BytesIO

import requests
import tweepy
from PIL import Image
from PIL import ImageFile

from secrets import *

ImageFile.LOAD_TRUNCATED_IMAGES = True

auth = OAuthHandler(consumer_key, consumer_secret) # Twitter requires all requests to use OAuth for authentication
auth.set_access_token(access_token, access_secret) 
api = tweepy.API(auth)

def tweet_image(url, username, status_id):
    filename = 'temp.png'
    # send a get request
    request = requests.get(url, stream=True)
    if request.status_code == 200:
        # read data from downloaded bytes and returns a PIL.Image.Image object
        i = Image.open(BytesIO(request.content))
        # Saves the image under the given filename
        i.save(filename)
        scramble(filename)
        # Update the authenticated user's status
        api.update_with_media('scramble.png', status='@{0}'.format(username), in_reply_to_status_id=status_id)
    else:
        print("unable to download image")

def scramble(filename):
    BLOCKLEN = 64  # Adjust and be careful here.

    img = Image.open(filename)
    width, height = img.size

    xblock = width // BLOCKLEN
    yblock = height // BLOCKLEN
    # creates sequence of 4-tuples (box) defining the left, upper, right, and lower pixel coordinate
    blockmap = [(xb * BLOCKLEN, yb * BLOCKLEN, (xb + 1) * BLOCKLEN, (yb + 1) * BLOCKLEN)
                for xb in range(xblock) for yb in range(yblock)]

    shuffle = list(blockmap)

    # shuffle the sequence
    random.shuffle(shuffle)

    # Creates a new image with the given mode and size.
    result = Image.new(img.mode, (width, height))
    for box, sbox in zip(blockmap, shuffle):
        # Returns a rectangular region from this original image.
        crop = img.crop(sbox)
        # Pastes the cropped pixel into the new image Object
        result.paste(crop, box)
    result.save('scramble.png')

# create a class inheriting from the tweepy  StreamListener
class BotStreamer(tweepy.StreamListener):
    # Called when a new status arrives which is passed down from the on_data method of the StreamListener
    def on_status(self, status):
        username = status.user.screen_name
        status_id = status.id

        # entities provide structured data from Tweets including resolved URLs, media, hashtags and mentions without having to parse the text to extract that information
        if 'media' in status.entities:
            for image in status.entities['media']:
                tweet_image(image['media_url'], username, status_id)

myStreamListener = BotStreamer()
# Construct the Stream instance
stream = tweepy.Stream(auth, myStreamListener)
stream.filter(track=['@picscrambler'])

That’s all we need to test this bot. Run bots.py from terminal and post a tweet with an image @picscrambler. After a few seconds the bot replies with a scrambled version of the original picture.

You can see a minimal working example of the Twitter bot in this githhub repository tweetbot

Conclusion

This tutorial walked through setting up and running a Twitter bot to automatically interact with the Twitter social media platform. There is a lot more that you can do with the Twitter API and with libraries like Tweepy that make it easy for developers to make use of Twitter.

REFERENCES

Source:: scotch.io