Skip to content

kapil019/NodeJsWorkflow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

NodeJsWorkflow

NodeJsWorkflow

How to use workflow in node js.


workflow.js
'use strict';

exports = module.exports = function(req, res) {
  var workflow = new (require('events').EventEmitter)();

  workflow.outcome = {
    success: false,
    errors: [],
    errfor: {}
  };

  workflow.hasErrors = function() {
    return Object.keys(workflow.outcome.errfor).length !== 0 || workflow.outcome.errors.length !== 0;
  };

  workflow.on('exception', function(err) {
    workflow.outcome.errors.push('Exception: '+ err);
    return workflow.emit('response');
  });

  workflow.on('response', function() {
    workflow.outcome.success = !workflow.hasErrors();
    res.send(workflow.outcome);
  });

  return workflow;
};

Usage, for user api given examples

'use strict';

// public api
var user = {
  find: function (req, res, next) {
    req.query.username = req.query.username ? req.query.username : '';
    req.query.limit = req.query.limit ? parseInt(req.query.limit, null) : 20;
    req.query.page = req.query.page ? parseInt(req.query.page, null) : 1;
    req.query.sort = req.query.sort ? req.query.sort : '_id';
    req.query.isActive = req.query.isActive ? req.query.isActive : '';
    req.query.roles = req.query.roles ? req.query.roles : '';

    var filters = {};
    if (req.query.username) {
      filters.username = new RegExp('^.*?' + req.query.username + '.*$', 'i');
    }

    if (req.query.isActive) {
      filters.isActive = req.query.isActive;
    }

    if (req.query.roles && req.query.roles === 'admin') {
      filters['roles.admin'] = {$exists: true};
    }

    if (req.query.roles && req.query.roles === 'account') {
      filters['roles.account'] = {$exists: true};
    }

    req.app.db.models.User.pagedFind({
      filters: filters,
      keys: 'username email isActive',
      limit: req.query.limit,
      page: req.query.page,
      sort: req.query.sort
    }, function (err, results) {
      if (err) {
        return next(err);
      }
      results.filters = req.query;
      res.status(200).json(results);
    });
  },
  create: function (req, res, next) {
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function () {
      if (!req.body.username) {
        workflow.outcome.errors.push('Please enter a username.');
        return workflow.emit('response');
      }

      if (!/^[a-zA-Z0-9\-\_]+$/.test(req.body.username)) {
        workflow.outcome.errors.push('only use letters, numbers, -, _');
        return workflow.emit('response');
      }

      workflow.emit('duplicateUsernameCheck');
    });

    workflow.on('duplicateUsernameCheck', function () {
      req.app.db.models.User.findOne({username: req.body.username}, function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errors.push('That username is already taken.');
          return workflow.emit('response');
        }

        workflow.emit('createUser');
      });
    });

    workflow.on('createUser', function () {
      var fieldsToSet = {
        username: req.body.username,
        search: [
          req.body.username
        ]
      };
      req.app.db.models.User.create(fieldsToSet, function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.outcome.record = user;
        return workflow.emit('response');
      });
    });

    workflow.emit('validate');
  },
  read: function (req, res, next) {
    req.app.db.models.User.findById(req.params.id).populate('roles.admin', 'name.full').populate('roles.account', 'name.full').exec(function (err, user) {
      if (err) {
        return next(err);
      }
      res.status(200).json(user);
    });
  },
  update: function (req, res, next) {
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function () {
      if (!req.body.isActive) {
        req.body.isActive = 'no';
      }

      if (!req.body.username) {
        workflow.outcome.errfor.username = 'required';
      } else if (!/^[a-zA-Z0-9\-\_]+$/.test(req.body.username)) {
        workflow.outcome.errfor.username = 'only use letters, numbers, \'-\', \'_\'';
      }

      if (!req.body.email) {
        workflow.outcome.errfor.email = 'required';
      } else if (!/^[a-zA-Z0-9\-\_\.\+]+@[a-zA-Z0-9\-\_\.]+\.[a-zA-Z0-9\-\_]+$/.test(req.body.email)) {
        workflow.outcome.errfor.email = 'invalid email format';
      }

      if (workflow.hasErrors()) {
        return workflow.emit('response');
      }

      workflow.emit('duplicateUsernameCheck');
    });

    workflow.on('duplicateUsernameCheck', function () {
      req.app.db.models.User.findOne({username: req.body.username, _id: {$ne: req.params.id}}, function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errfor.username = 'username already taken';
          return workflow.emit('response');
        }

        workflow.emit('duplicateEmailCheck');
      });
    });

    workflow.on('duplicateEmailCheck', function () {
      req.app.db.models.User.findOne({email: req.body.email.toLowerCase(), _id: {$ne: req.params.id}}, function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errfor.email = 'email already taken';
          return workflow.emit('response');
        }

        workflow.emit('patchUser');
      });
    });

    workflow.on('patchUser', function () {
      var fieldsToSet = {
        isActive: req.body.isActive,
        username: req.body.username,
        email: req.body.email.toLowerCase(),
        search: [
          req.body.username,
          req.body.email
        ]
      };
      var options = {new : true}; //so that user returned is the updated not original doc

      req.app.db.models.User.findByIdAndUpdate(req.params.id, fieldsToSet, options, function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }
        workflow.emit('patchAdmin', user);
      });
    });

    workflow.on('patchAdmin', function (user) {
      if (user.roles.admin) {
        var fieldsToSet = {
          user: {
            id: req.params.id,
            name: user.username
          }
        };
        req.app.db.models.Admin.findByIdAndUpdate(user.roles.admin, fieldsToSet, function (err, admin) {
          if (err) {
            return workflow.emit('exception', err);
          }

          workflow.emit('patchAccount', user);
        });
      } else {
        workflow.emit('patchAccount', user);
      }
    });

    workflow.on('patchAccount', function (user) {
      if (user.roles.account) {
        var fieldsToSet = {
          user: {
            id: req.params.id,
            name: user.username
          }
        };
        req.app.db.models.Account.findByIdAndUpdate(user.roles.account, fieldsToSet, function (err, account) {
          if (err) {
            return workflow.emit('exception', err);
          }

          workflow.emit('populateRoles', user);
        });
      } else {
        workflow.emit('populateRoles', user);
      }
    });

    workflow.on('populateRoles', function (user) {
      user.populate('roles.admin roles.account', 'name.full', function (err, populatedUser) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.outcome.user = populatedUser;
        workflow.emit('response');
      });
    });

    workflow.emit('validate');
  },
  password: function (req, res, next) {
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function () {
      if (!req.body.newPassword) {
        workflow.outcome.errfor.newPassword = 'required';
      }

      if (!req.body.confirm) {
        workflow.outcome.errfor.confirm = 'required';
      }

      if (req.body.newPassword !== req.body.confirm) {
        workflow.outcome.errors.push('Passwords do not match.');
      }

      if (workflow.hasErrors()) {
        return workflow.emit('response');
      }

      workflow.emit('patchUser');
    });

    workflow.on('patchUser', function () {
      req.app.db.models.User.encryptPassword(req.body.newPassword, function (err, hash) {
        if (err) {
          return workflow.emit('exception', err);
        }

        var fieldsToSet = {password: hash};
        var options = {new : true};
        req.app.db.models.User.findByIdAndUpdate(req.params.id, fieldsToSet, options, function (err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function (err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.outcome.newPassword = '';
            workflow.outcome.confirm = '';
            workflow.emit('response');
          });
        });
      });
    });

    workflow.emit('validate');
  },
  linkAdmin: function (req, res, next) {
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function () {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not link users to admins.');
        return workflow.emit('response');
      }

      if (!req.body.newAdminId) {
        workflow.outcome.errfor.newAdminId = 'required';
        return workflow.emit('response');
      }

      workflow.emit('verifyAdmin');
    });

    workflow.on('verifyAdmin', function (callback) {
      req.app.db.models.Admin.findById(req.body.newAdminId).exec(function (err, admin) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!admin) {
          workflow.outcome.errors.push('Admin not found.');
          return workflow.emit('response');
        }

        if (admin.user.id && admin.user.id !== req.params.id) {
          workflow.outcome.errors.push('Admin is already linked to a different user.');
          return workflow.emit('response');
        }

        workflow.admin = admin;
        workflow.emit('duplicateLinkCheck');
      });
    });

    workflow.on('duplicateLinkCheck', function (callback) {
      req.app.db.models.User.findOne({'roles.admin': req.body.newAdminId, _id: {$ne: req.params.id}}).exec(function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errors.push('Another user is already linked to that admin.');
          return workflow.emit('response');
        }

        workflow.emit('patchUser');
      });
    });

    workflow.on('patchUser', function (callback) {
      req.app.db.models.User.findById(req.params.id).exec(function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        user.roles.admin = req.body.newAdminId;
        user.save(function (err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function (err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.emit('patchAdmin');
          });
        });
      });
    });

    workflow.on('patchAdmin', function () {
      workflow.admin.user = {id: req.params.id, name: workflow.outcome.user.username};
      workflow.admin.save(function (err, admin) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.emit('response');
      });
    });

    workflow.emit('validate');
  },
  unlinkAdmin: function (req, res, next) {
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function () {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not unlink users from admins.');
        return workflow.emit('response');
      }

      if (req.user._id + '' === req.params.id) {
        workflow.outcome.errors.push('You may not unlink yourself from admin.');
        return workflow.emit('response');
      }

      workflow.emit('patchUser');
    });

    workflow.on('patchUser', function () {
      req.app.db.models.User.findById(req.params.id).exec(function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!user) {
          workflow.outcome.errors.push('User was not found.');
          return workflow.emit('response');
        }

        var adminId = user.roles.admin;
        user.roles.admin = null;
        user.save(function (err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function (err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.emit('patchAdmin', adminId);
          });
        });
      });
    });

    workflow.on('patchAdmin', function (id) {
      req.app.db.models.Admin.findById(id).exec(function (err, admin) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!admin) {
          workflow.outcome.errors.push('Admin was not found.');
          return workflow.emit('response');
        }

        admin.user = undefined;
        admin.save(function (err, admin) {
          if (err) {
            return workflow.emit('exception', err);
          }

          workflow.emit('response');
        });
      });
    });

    workflow.emit('validate');
  },
  linkAccount: function (req, res, next) {
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function () {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not link users to accounts.');
        return workflow.emit('response');
      }

      if (!req.body.newAccountId) {
        workflow.outcome.errfor.newAccountId = 'required';
        return workflow.emit('response');
      }

      workflow.emit('verifyAccount');
    });

    workflow.on('verifyAccount', function (callback) {
      req.app.db.models.Account.findById(req.body.newAccountId).exec(function (err, account) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!account) {
          workflow.outcome.errors.push('Account not found.');
          return workflow.emit('response');
        }

        if (account.user.id && account.user.id !== req.params.id) {
          workflow.outcome.errors.push('Account is already linked to a different user.');
          return workflow.emit('response');
        }

        workflow.account = account;
        workflow.emit('duplicateLinkCheck');
      });
    });

    workflow.on('duplicateLinkCheck', function (callback) {
      req.app.db.models.User.findOne({'roles.account': req.body.newAccountId, _id: {$ne: req.params.id}}).exec(function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errors.push('Another user is already linked to that account.');
          return workflow.emit('response');
        }

        workflow.emit('patchUser');
      });
    });

    workflow.on('patchUser', function (callback) {
      req.app.db.models.User.findById(req.params.id).exec(function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        user.roles.account = req.body.newAccountId;
        user.save(function (err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function (err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.emit('patchAccount');
          });
        });
      });
    });

    workflow.on('patchAccount', function () {
      workflow.account.user = {id: req.params.id, name: workflow.outcome.user.username};
      workflow.account.save(function (err, account) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.emit('response');
      });
    });

    workflow.emit('validate');
  },
  unlinkAccount: function (req, res, next) {
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function () {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not unlink users from accounts.');
        return workflow.emit('response');
      }

      workflow.emit('patchUser');
    });

    workflow.on('patchUser', function () {
      req.app.db.models.User.findById(req.params.id).exec(function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!user) {
          workflow.outcome.errors.push('User was not found.');
          return workflow.emit('response');
        }

        var accountId = user.roles.account;
        user.roles.account = null;
        user.save(function (err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function (err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.emit('patchAccount', accountId);
          });
        });
      });
    });

    workflow.on('patchAccount', function (id) {
      req.app.db.models.Account.findById(id).exec(function (err, account) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!account) {
          workflow.outcome.errors.push('Account was not found.');
          return workflow.emit('response');
        }

        account.user = undefined;
        account.save(function (err, account) {
          if (err) {
            return workflow.emit('exception', err);
          }

          workflow.emit('response');
        });
      });
    });

    workflow.emit('validate');
  },
  delete: function (req, res, next) {
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function () {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not delete users.');
        return workflow.emit('response');
      }

      // work around as typeof req.user._id === "Object"
      if (req.user._id + '' === req.params.id) {
        workflow.outcome.errors.push('You may not delete yourself from user.');
        return workflow.emit('response');
      }

      workflow.emit('deleteUser');
    });

    workflow.on('deleteUser', function (err) {
      req.app.db.models.User.findByIdAndRemove(req.params.id, function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.emit('response');
      });
    });

    workflow.emit('validate');
  }
};
module.exports = user;

About

NodeJsWorkflow

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published