neotoma/sync-server

View on GitHub
app/models/contactVerification.js

Summary

Maintainability
A
1 hr
Test Coverage
/**
 * ContactVerification model
 * @module
 */

var async = require('async'),
  ContactVerificationRequest = require('app/models/contactVerificationRequest'),
  debug = require('app/lib/debug')('app:contactVerification'),
  jsonapi = require('app/lib/jsonapi'),
  logger = require('app/lib/logger'),
  modelFactory = require('app/factories/model'),
  NotificationRequest = require('app/models/notificationRequest'),
  User = require('app/models/user');

/**
 * Represents verification of contact information
 * @class ContactVerification
 * @global
 * @property {string} contactVerificationRequestCode - Secure code initially generated by ContactVerificationRequest
 * @property {module:models/contactVerificationRequest~ContactVerificationRequest} contactVerificationRequest - Parent contactVerificationRequest 
 * @property {module:models/user~User} [user] - User who verified contact
 */
module.exports = modelFactory.new('ContactVerification', {
  contactVerificationRequestCode: { type: String, required: true },
  contactVerificationRequest: { ref: 'ContactVerificationRequest', required: true },
  session: String,
  user: { ref: 'User' }
}, {
  jsonapi: {
    delete: jsonapi.adminFlag,
    get: {
      allowed: 'public',
      queryConditions: function(req, done) {
        done(undefined, { session: req.session.id });
      }
    },
    patch: jsonapi.adminFlag,
    post: {
      allowed: 'public',

      /**
       * Authenticate user after POST if related contactVerificationRequest indicates to do so
       * @param {Object} req - Express request object
       * @param {Object} res - Express response object
       * @param {Object} contactVerification - Mongoose contactVerification document created by POST request
       * @param {function} done - Callback function expecting error, res, req and contactVerification params
       */
      post: function(req, res, contactVerification, done) {
        var authenticateUser = function(done) {
          if (contactVerification.user && contactVerification.contactVerificationRequest.authenticateSession) {
            req.logIn(contactVerification.user, function(error) {
              if (!error) {
                logger.info('contactVerification model post-POST procedure authenticated session');
              } else {
                logger.error('contactVerification model post-POST procedure failed to authenticate session');
              }

              done(error);
            });
          } else {
            done();
          }
        };

        var saveSession = function(done) {
          contactVerification.session = req.session.id;
          contactVerification.save(done);
        };

        async.series([authenticateUser, saveSession], done);
      }
    }
  }
}, null, function(schema) {
  schema.pre('save', function(next) {
    if (!this.isNew) { return next(); }

    debug('pre save ContactVerificationRequest.findOne %s, code: %s', this.contactVerificationRequest, this.contactVerificationRequestCode);

    ContactVerificationRequest.findOne({
      _id: this.contactVerificationRequest,
      code: this.contactVerificationRequestCode
    }, function(error, contactVerificationRequest) {
      if (error) {
        next(error);
      } else if (!contactVerificationRequest) {
        next(new Error('Unable to find corresponding contactVerificationRequest by ID and code'));
      } else {
        next();
      }
    });
  });

  schema.post('save', function(contactVerification, next) {
    if (!this.wasNew) { return next(); }

    var findContactVerificationRequest = (done) => {
      ContactVerificationRequest.findOne({
        _id: this.contactVerificationRequest,
        code: this.contactVerificationRequestCode
      }, function(error, contactVerificationRequest) {
        if (error) {
          return done(error);
        } else if (!contactVerificationRequest) {
          return done(new Error('Unable to find corresponding contactVerificationRequest'));
        }

        return done(null, contactVerificationRequest);
      });
    };

    var findOrCreateUser = (contactVerificationRequest, done) => {
      if (contactVerificationRequest.method === 'email' && contactVerificationRequest.contact && (contactVerificationRequest.createUser || contactVerificationRequest.authenticateSession)) {
        var query = User.findOne;

        if (contactVerificationRequest.createUser) {
          query = User.findOrCreate;
        }

        query.apply(User, [{
          email: contactVerificationRequest.contact
        }, function(error, user) {
          if (error) {
            return done(error);
          } else if (!user) {
            return done(new Error('Unable to find or create user'));
          }

          contactVerification.user = user;
          contactVerification.save(function(error) {
            done(error, user, contactVerificationRequest);
          });
        }]);
      } else {
        done(null, null, contactVerificationRequest);
      }
    };

    var createNotificationRequests = (user, contactVerificationRequest, done) => {
      if (user && contactVerificationRequest.createNotificationRequests) {
        async.each(contactVerificationRequest.createNotificationRequests, function(notificationRequestAttributes, done) {
          notificationRequestAttributes.user = user;
          debug('notificationRequestAttributes', notificationRequestAttributes);
          NotificationRequest.findOrCreate(notificationRequestAttributes, (error, notificationRequest) => {
            if (notificationRequest) {
              debug('notificationRequest created', notificationRequest.id);
            } else if (error) {
              debug('error creating notificationRequest', error);
            }

            done(error);
          });
        }, done);
      } else {
        done(null, user, contactVerificationRequest);
      }
    };

    async.waterfall([
      findContactVerificationRequest,
      findOrCreateUser, 
      createNotificationRequests
    ], function(error) {
      if (error) {
        logger.error('ContactVerification model post-save procedure failed', { error: error.message });
      }

      next(error);
    });
  });
});