📜 ⬆️ ⬇️

Writing a Simple SailsJS Blog: Visual Practice for Beginners (Part 2)

Synopsis




Earlier we learned how to write the basics for our blog, and when we wrote the basics we got acquainted with the organization of statics, model making and writing controller code. We learned how to work with path configurations ( routes.js ), and how to work with views in SailsJS. In the second part about writing a simple blog on SailsJS, we will consider the following points: Users: creation. Sessions: creation (input), gap (output). Writing the Admin Panel, and working with policies and access restrictions.


Users


To create a new API complex, we introduce the command already familiar to us at the root of our project.
sails generate api user 

This time, when organizing the code, we will need to encrypt the password, for this we need an excellent password-hash module, which is suitable for this task. To install it - enter the following command in the root of our project.
 npm install password-hash --save 

The --save parameter indicates that we will save the value of the module as a dependency in package.json .
')
Since in the previous post I have already examined the basic skills of working with models and controllers in SailsJS - where they are and how to compose them correctly, I will not pay attention to the already obvious things.

Model

There will be several attributes for our user:
  1. Username
  2. Password
  3. Admin - access parameter

When compiling the model, we should not forget that we also want to do password encryption on the server, as well as make some additional auxiliary functions based on working with model life cycles.
 var passwordHash = require('password-hash'); var User = { attributes: { username: {type: 'string', required: true, unique: true}, password: {type: 'string', required: true, minLength: 8}, admin: { type: 'boolean', defaultsTo: false }, toJSON: function() { var element = this.toObject(); delete element.password; return element; } }, beforeCreate: function (values, next) { //       var mainPass = passwordHash.generate(values.password); values.encryptPassword = mainPass; next(); } }; module.exports = User; 

Before creating a new user, we add an additional attribute - encryptedPassword , which is an encrypted version of the password.

Controller

In the controller, we will only make the ability to create a user, and an index page. How to make handlers update and delete a user you can do in the likeness of what we have done in the post controller. Here is the controller code.
 module.exports = { //@API -   /** *   , *     *  , ,   *  .   *    *  .    *     * admin (api/policies/admin.js)   *       *    */ create: function (req, res) { var elem = { username : req.param('username'), password : req.param('password'), admin : req.param('admin') }; User.create(elem).exec(function (err, user) { if (err) return res.send(500); req.session.auth = true; res.redirect('/'); }); }, // @MAIN index: function (req, res) { res.view(); } }; 

In the configuration of paths ( config / routes.js ) add the following.
  '/register' : 'UserController', 

As a simple protection, we enable the CSRF protection in the configuration file ( config / csrf.js ) and edit the line as follows
 module.exports.csrf = true; 


View ( views / user / index.ejs )

And now we will make representation, it will have the elementary structure.
 <div class="container"> <div class="row"> <div class="col-md-4"></div> <div class="col-md-4"> <div class="panel panel-default"> <div class="panel-body"> <form action="/user/create" method="post"> <input type="text" name="username" placeholder=" "><br> <input type="password" name="password" placeholder=""><br> <input type="hidden" name="_csrf" value="<%= _csrf %>"> <!--        --> <input type="hidden" name="admin" value="true"> <input type="submit" class="btn btn-success btn-block" value=""> </form> </div> </div> </div> <div class="col-md-4"></div> </div> </div> 

Or, instead of a view, you can simply disable csrf to create a user — for example, using Postman. And then block the Users controller.

On it we will complete writing of components for creation of users. Now we have a model, controller, registration page path, and presentation template.

Sessions


To authorize users, we will use the session system built into Sails - this is convenient and quite safe (if compared to a cookie) our session controller will be able to create sessions and destroy them. Create a new controller in the standard way. Here is the code of our controller.
 var passwordHash = require('password-hash'); module.exports = { // @API    create: function (req, res) { /** *    * ,     *   */ var username = req.param('username'), password = req.param('password'); /** *        *  ,    * (.     *  ,   flash) */ if (!username || !password) { return res.redirect('/session'); }; /** *      * (username - req.param('username')) *     *      *    ,   * ,     - *   ,     *     .  *       *      *    ( ) */ User.findOneByUsername(username).exec(function (err, user) { if (!user || err) return res.send(500); if (passwordHash.verify(password, user.encryptPassword)) { //     //      //    req.session.auth = true; req.session.User = user; if (req.session.User.admin) { return res.redirect('/admin'); }; }; }); }, /** *      *     *  ,    */ destroy: function (req, res) { User.findOne(req.session.User.id).exec(function (err, user) { if (user) { req.session.destroy(); res.redirect('/'); } else { res.redirect('/login'); }; }); }, // @MAIN index: function (req, res) { res.view(); } }; 


Path configuration

  '/login' : 'SessionController', '/logout' : { controller: 'session', action: 'destroy' }, 


Representation

And the login page view
 <div class="container"> <div class="row"> <div class="col-md-4"></div> <div class="col-md-4 text-center"> <h2>Sign-in form</h2><hr> <form action="/session/create" method="POST"> <input type="text" name="username" placeholder="Username" class="form-control" /><br> <input type="password" name="password" placeholder="password" class="form-control" /><br> <input type="submit" class="btn btn-default" value="Log-In" /> <input type="hidden" name="_csrf" value="<%= _csrf %>" /> </form> </div> <div class="col-md-4"></div> </div> </div> 

Now we have created the ability to register and create sessions (log in with the system), it now remains to make the admin panel page, and configure the access control policy. And so the final stage.

Admin Panel and Differentiation of Rights



We will have the simplest admin page consisting of a list of posts, and a form for adding a new post. As well as a page for editing existing posts. Now create a new admin controller. Here is the code of our controller.
 module.exports = { index: function (req, res) { Post.find() .sort('id DESC') .exec(function (err, posts) { if (err) return res.send(500); res.view({ posts: posts }); }); }, edit: function (req, res) { var Id = req.param('id'); Post.findOne(Id).exec(function (err, post) { if (!post) return res.send(404); if (err) return res.send(500); res.view({ post: post }); }); } }; 

And our 2 submissions.

views / admin / index.ejs

 <div class="container text-center"> <h2>CREATE NEW</h2><br> <div class="row"> <form action="/post/create" method="POST"> <div class="col-md-6"> <input class="form-control" type="text" name="title" placeholder="Title Post"><hr> <textarea rows="3" class="form-control" name="description" placeholder="Description"></textarea> </div> <div class="col-md-6"> <textarea rows="7" class="form-control" name="content" placeholder="Content"></textarea> </div> <div class="col-md-12"> <input type="hidden" name="_csrf" value="<%= _csrf %>" /> <br><input type="submit" class="btn btn-success" value="CREATE" /> </div> </form> </div><br> <h2>POST LIST</h2> <table class="table text-left"> <tr> <th>ID</th> <th>TITLE</th> <th></th> <th></th> <th></th> </tr> <% _.each(posts, function (post) { %> <tr> <td><%= post.id %></td> <td><%= post.title %></td> <td><a href="/post/watch/<%= post.id %>" class="btn btn-info">Look</a></td> <td><a href="/post/delete/<%= post.id %>" class="btn btn-danger">Delete</a></td> <td><a href="/admin/edit/<%= post.id %>" class="btn btn-warning">Edit</a></td> </tr> <% }) %> </table> </div> 


views / admin / edit.ejs

 <div class="container"> <div class="row"> <div class="col-md-2"></div> <div class="col-md-8 well text-center"> <form action="/post/update" method="POST"> <h4>Title</h4> <input type="text" class="form-control" name="title" value="<%= post.title %>"><br> <h4>Description</h4> <textarea rows="3" name="description" class="form-control" value="<%= post.description %>"></textarea> <h4>Content</h4> <textarea rows="7" name="content" class="form-control" value="<%= post.content %>"></textarea> <input type="hidden" name="_csrf" value="<%= _csrf %>" /><br> <input type="submit" class="btn btn-success" value="Update"> </form> </div> <div class="col-md-2"></div> </div> </div> 


Now let's create a policy.

Politics

The system of differentiation of access rights in Sails is very convenient and easy to use, in our case it is enough just to verify that the user:

To express this in code, create a file of our policy - api / policies / admin.js . And here is the code of our delimiter.
 module.exports = function (req, res, ok) { if (req.session.auth && req.session.User.admin) { return ok(); } else { return res.redirect('/login'); }; } 

In this case, the callback is returning to skip the next steps. if the result is the opposite, prohibit and redirect to the login page. To activate our policy on a specific controller, open the file config / policies.js and bring it to the following form.
 module.exports.policies = { // Default policy for all controllers and actions // (`true` allows public access) '*': true, /** *     * Admin  admin.js,  *  . */ AdminController: { '*': 'admin' }, UserController: { create: 'admin' }, PostController: { //      index : true, page : true, watch : true, //      create : 'admin', update : 'admin', delete : 'admin', } }; 

This concludes the writing of a simple blog on Sails, of course there is very little functionality and protection in it - there is no error handling (even flash messages), there is no full-fledged multi-user admin, but this article is designed as a small introductory course in this framework, then you can study it yourself . In the future, to increase the functionality you should not be a big deal.

Source: https://habr.com/ru/post/224403/


All Articles