UNPKG

f1foo

Version:

An integration between Wufoo's WebHooks and Fellowship One's REST API.

283 lines (246 loc) 8.65 kB
var debug = require('debug')(require('../package.json').name + ':F1Register') var F1 = require('fellowshipone') var util = require('util') var async = require('async') var _ = require('lodash') var NEW_STATUS = process.env.NEW_STATUS || 'New from Website' var EMAIL = 'Email' var PHONE = 'Telephone' var HOME_PHONE = 'Home Phone' var MOBILE_PHONE = 'Mobile Phone' /** * @method F1Register * @param {F1} f1 The fellowshipone object - optional * @param {F1.People} people The F1 people object - optional */ function F1Register (f1, people) { Object.defineProperties(this, { f1: { // lazy-get this thing because the environment may not have the var // right this nanosecond... And besides, we don't really need it yet! get: function () { if (!f1) { debug('no f1 yet, creating anew...') f1 = new F1(JSON.parse(process.env.F1_CONFIG)) } return f1 } }, people: { get: function () { if (!people) { people = new F1.People(this.f1) } return people } } }) } /** * Create a query object based on the given registration data * * @method searchQuery * @param {[type]} reg [description] * @param {Function} callback [description] */ F1Register.prototype.searchQuery = function (reg, callback) { var query = {} var name = reg.Name query.searchFor = [name.First, name.Last].join(' ') query.communication = reg.Email callback(null, query) } /** * Validate the given registration. yields an error if it's not valid, otherwise passes it through. * * @method validateReg * @param {[type]} reg [description] * @param {Function} callback [description] */ F1Register.prototype.validateReg = function (reg, callback) { function clientError (msg) { debug('%s - %j', msg, reg) return callback({ statusCode: 400, message: msg }) } if (!reg.Name) return clientError('Registration invalid: no Name') if (!reg.Name.First) return clientError('Registration invalid: no First Name') if (!reg.Name.Last) return clientError('Registration invalid: no Last Name') if (!reg.Email) return clientError('Registration invalid: no Email') callback(null, reg) } /** * Create a new Person record in F1 based on the given registration * * @method createPerson * @param {[type]} reg [description] * @param {Function} callback [description] */ F1Register.prototype.createPersonRecord = function (reg, callback) { this.getStatus(NEW_STATUS, function (err, status) { if (err) return callback(err) this.createHousehold(reg, function (err, householdResponse) { if (err) return callback(err) this.createPerson(householdResponse.household['@id'], status, reg, function (err, body) { if (err) return callback(err) debug('Person created: %j', body.person) this.createEmail(body.person, reg, function (err, emailResponse) { if (err) return callback(err) this.createAddress(body.person, reg, function (err, addr) { callback(err, body) }) }.bind(this)) }.bind(this)) }.bind(this)) }.bind(this)) } F1Register.prototype._createComm = function (generalCommName, commName, person, reg, callback) { if (reg[commName]) { this.getCommunicationType(commName, function (err, commType) { if (err) return callback(err) var commObj = { person: _.pick(person, ['@id', '@uri']), communicationType: commType, communicationGeneralType: generalCommName, communicationValue: reg[commName], searchCommunicationValue: reg[commName], preferred: 'true' } var comms = new F1.PersonCommunications(this.f1, person['@id']) comms.create(commObj, callback) }.bind(this)) } else { callback(null, {}) } } F1Register.prototype.createHomePhone = function (person, reg, callback) { return this._createComm(PHONE, HOME_PHONE, person, reg, callback) } F1Register.prototype.createMobilePhone = function (person, reg, callback) { return this._createComm(PHONE, MOBILE_PHONE, person, reg, callback) } F1Register.prototype.createEmail = function (person, reg, callback) { return this._createComm(EMAIL, EMAIL, person, reg, callback) } F1Register.prototype.createPerson = function (householdID, status, reg, callback) { var person = { status: status, firstName: reg.Name.First, lastName: reg.Name.Last, '@householdID': householdID } debug('Creating person %j', person) var people = new F1.People(this.f1) people.create(person, callback) } F1Register.prototype.createHousehold = function (reg, callback) { var household = { householdName: reg.Name.First + ' ' + reg.Name.Last, householdSortName: reg.Name.Last, householdFirstName: reg.Name.First } var households = new F1.Households(this.f1) households.create(household, callback) } F1Register.prototype.getResourceByName = function (pluralResourceName, name, callback) { var resources = new F1[pluralResourceName](this.f1) resources.list(function (err, list) { if (err) return callback(err) async.filter(list, function (item, callback) { callback(item.name === name) }, function (items) { if (_.isEmpty(items)) { return callback('No ' + pluralResourceName + ' with name `' + name + '` could be found!') } return callback(null, items[0]) }) }) } F1Register.prototype.getStatus = function (name, callback) { this.getResourceByName('Statuses', name, callback) } F1Register.prototype.getCommunicationType = function (name, callback) { this.getResourceByName('CommunicationTypes', name, callback) } F1Register.prototype.getAddressType = function (name, callback) { this.getResourceByName('AddressTypes', name, callback) } F1Register.prototype.createAddress = function (person, reg, callback) { this.getAddressType('Primary', function (err, addressType) { if (err) return callback(err) var address = { person: _.pick(person, ['@id', '@uri']), addressType: addressType, address1: reg.Address['Street Address'], address2: reg.Address['Address Line 2'], city: reg.Address.City, stProvince: reg.Address['State / Province / Region'], postalCode: reg.Address['Postal / Zip Code'], country: reg.Address.Country } var addresses = new F1.PersonAddresses(this.f1, person['@id']) addresses.create(address, callback) }.bind(this)) } /** * TODO: implement this... * * @method registerPerson * @param {[type]} registration [description] * @param {[type]} people [description] * @param {Function} callback [description] */ F1Register.prototype.registerPerson = function (registration, person, callback) { var msg = util.format('Registered %j', registration) debug(msg) callback(null, msg) } /** * Ensure that a person record gets created if necessary. * * @method ensureCreated * @param {[type]} registration the form submission object * @param {[type]} person the person object. May be null or undefined - if so a new person record will be created. * @param {Function} callback yields an error (if received) and the person object. */ F1Register.prototype.ensureCreated = function (registration, person, callback) { if (!person) { this.createPersonRecord(registration, function (err, person) { if (err) return callback(err) debug('New person `%s %s` created at id %s', registration.Name.First, registration.Name.Last, person.person['@id']) callback(null, registration, person) }) } else { debug('Person found') callback(null, registration, person) } } F1Register.prototype.handleDuplicateRecords = function (body, callback) { if (Number(body.results['@count']) > 1) { debug('Found returned duplicate records - registration will need to be handled manually') callback('Found returned duplicate records - registration will need to be handled manually') } else { callback(null, body) } } F1Register.prototype.register = function (reg, callback) { debug('registering: %j', reg) async.waterfall([ this.f1.authenticate.bind(this.f1), this.validateReg.bind(this, reg), this.searchQuery.bind(this), this.people.search.bind(this.people), this.handleDuplicateRecords.bind(this), function handlePerson (body, next) { this.ensureCreated(reg, body.results.person, next) }.bind(this), this.registerPerson.bind(this) ], callback ) } module.exports = F1Register