Skip to content
This repository has been archived by the owner on Jun 21, 2019. It is now read-only.

Commit

Permalink
Merge pull request #73 from HackIllinois/staging
Browse files Browse the repository at this point in the history
Version 0.0.4
  • Loading branch information
nmagerko authored Feb 5, 2017
2 parents 67eb2e6 + 691e031 commit 8fc8ceb
Show file tree
Hide file tree
Showing 21 changed files with 527 additions and 19 deletions.
130 changes: 130 additions & 0 deletions api/v1/controllers/RSVPController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
var bodyParser = require('body-parser');
var _Promise = require('bluebird');

var services = require('../services');
var middleware = require('../middleware');
var requests = require('../requests');
var roles = require('../utils/roles');
var mail = require('../utils/mail');

var router = require('express').Router();

function _isAuthenticated (req) {
return req.auth && (req.user !== undefined);
}

function _removeFromList(rsvpCurrent, rsvpNew) {
return rsvpCurrent.get('isAttending') && !rsvpNew.isAttending;
}

function _addToList(rsvpCurrent, rsvpNew) {
return !rsvpCurrent.get('isAttending') && rsvpNew.isAttending;
}

function createRSVP(req, res, next) {
if(!req.body.isAttending)
delete req.body.type;

services.RegistrationService
.findAttendeeByUser(req.user)
.then(function(attendee) {
return services.RSVPService
.createRSVP(attendee, req.user, req.body);
})
.then(function(rsvp) {
if(rsvp.get('isAttending'))
services.MailService.addToList(req.user, mail.lists.attendees);
res.body = rsvp.toJSON();

return next();
})
.catch(function(error) {
return next(error);
});
}

function fetchRSVPByUser(req, res, next) {
services.RegistrationService
.findAttendeeByUser(req.user)
.then(function(attendee) {
return services.RSVPService
.findRSVPByAttendee(attendee);
})
.then(function (rsvp) {
res.body = rsvp.toJSON();
if(!res.body.type) {
delete res.body.type;
}

return next();
})
.catch(function(error) {
return next(error);
})
}

function fetchRSVPById(req, res, next) {
services.RSVPService
.getRSVPById(req.params.id)
.then(function(rsvp){
res.body = rsvp.toJSON();
if(!res.body.type) {
delete res.body.type;
}

return next();
})
.catch(function(error) {
return next(error);
})
}

function updateRSVPByUser(req, res, next) {
if(!req.body.isAttending)
delete req.body.type;

services.RegistrationService
.findAttendeeByUser(req.user)
.then(function(attendee) {
return _updateRSVPByAttendee(req.user, attendee, req.body);
})
.then(function(rsvp){
res.body = rsvp.toJSON();

return next();
})
.catch(function (error) {
return next(error);
});
}

function _updateRSVPByAttendee(user, attendee, newRSVP) {
return services.RSVPService
.findRSVPByAttendee(attendee)
.then(function (rsvp) {
return services.RSVPService.updateRSVP(user, rsvp, newRSVP)
.then(function (updatedRSVP) {
if(_addToList(rsvp, newRSVP))
services.MailService.addToList(user, mail.lists.attendees);
if(_removeFromList(rsvp, newRSVP))
services.MailService.removeFromList(user, mail.lists.attendees);

return updatedRSVP
});
});
}

router.use(bodyParser.json());
router.use(middleware.auth);

router.post('/attendee', middleware.request(requests.RSVPRequest),
middleware.permission(roles.ATTENDEE, _isAuthenticated), createRSVP);
router.get('/attendee/', middleware.permission(roles.ATTENDEE), fetchRSVPByUser);
router.get('/attendee/:id', middleware.permission(roles.ORGANIZERS), fetchRSVPById);
router.put('/attendee/', middleware.request(requests.RSVPRequest),
middleware.permission(roles.ATTENDEE), updateRSVPByUser);

router.use(middleware.response);
router.use(middleware.errors);

module.exports.router = router;
1 change: 1 addition & 0 deletions api/v1/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ module.exports = {
PermissionController: require('./PermissionController.js'),
ProjectController: require('./ProjectController.js'),
HealthController: require('./HealthController.js'),
RSVPController: require('./RSVPController.js'),
StatsController: require('./StatsController.js')
};
3 changes: 2 additions & 1 deletion api/v1/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ v1.use('/permission', controllers.PermissionController.router);
v1.use('/project', controllers.ProjectController.router);
v1.use('/ecosystem', controllers.EcosystemController.router);
v1.use('/health', controllers.HealthController.router);
v1.use('/rsvp', controllers.RSVPController.router);
v1.use('/stats', controllers.StatsController.router);

// log any outgoing response for debugging
Expand All @@ -35,4 +36,4 @@ v1.use(function (req, res, next) {
next();
});

module.exports = v1;
module.exports = v1;
12 changes: 8 additions & 4 deletions api/v1/models/Attendee.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var AttendeeProject = require('./AttendeeProject');
var AttendeeExtraInfo = require('./AttendeeExtraInfo');
var AttendeeEcosystemInterest = require('./AttendeeEcosystemInterest');
var AttendeeRequestedCollaborator = require('./AttendeeRequestedCollaborator');
var AttendeeRSVP = require('./AttendeeRSVP');
var Attendee = Model.extend({
tableName: 'attendees',
idAttribute: 'id',
Expand Down Expand Up @@ -55,6 +56,9 @@ var Attendee = Model.extend({
collaborators: function () {
return this.hasMany(AttendeeRequestedCollaborator);
},
rsvp: function () {
return this.hasOne(AttendeeRSVP);
},
parse: function (attrs) {
attrs = Model.prototype.parse(attrs);
attrs.isNovice = !!attrs.isNovice;
Expand All @@ -70,7 +74,7 @@ var Attendee = Model.extend({
* @return {Promise<Model>} a Promise resolving to the resulting Attendee or null
*/
Attendee.findByUserId = function (userId) {
return Attendee.where({ user_id: userId }).fetch({withRelated: ['projects', 'ecosystemInterests', 'extras', 'collaborators']});
return Attendee.where({ user_id: userId }).fetch({withRelated: ['projects', 'ecosystemInterests', 'extras', 'collaborators', 'rsvp']});
};


Expand All @@ -83,7 +87,7 @@ Attendee.fetchWithResumeByUserId = function (userId) {
return Attendee.transaction(function (t){
var attendee;
return Attendee.where({ user_id: userId })
.fetch({withRelated: ['projects', 'ecosystemInterests', 'extras', 'collaborators'], transacting: t})
.fetch({withRelated: ['projects', 'ecosystemInterests', 'extras', 'collaborators', 'rsvp'], transacting: t})
.then(function (a) {
attendee = a;
if(_.isNull(a)){
Expand All @@ -106,7 +110,7 @@ Attendee.fetchWithResumeByUserId = function (userId) {
* @return {Promise<Model>} a Promise resolving to the resulting model or null
*/
Attendee.findById = function (id) {
return Attendee.where({ id: id }).fetch({withRelated: ['projects', 'ecosystemInterests', 'extras', 'collaborators']});
return Attendee.where({ id: id }).fetch({withRelated: ['projects', 'ecosystemInterests', 'extras', 'collaborators', 'rsvp']});
};

/**
Expand All @@ -118,7 +122,7 @@ Attendee.fetchWithResumeById = function (id) {
return Attendee.transaction(function (t){
var attendee;
return Attendee.where({ id: id })
.fetch({withRelated: ['projects', 'ecosystemInterests', 'extras', 'collaborators'], transacting: t})
.fetch({withRelated: ['projects', 'ecosystemInterests', 'extras', 'collaborators', 'rsvp'], transacting: t})
.then(function (a) {
attendee = a;
if(_.isNull(a)){
Expand Down
28 changes: 28 additions & 0 deletions api/v1/models/AttendeeRSVP.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
var _ = require('lodash');
var CheckIt = require('checkit');

var rsvp = require('../utils/rsvp');
var Model = require('./Model');
var AttendeeRSVP = Model.extend({
tableName: 'attendee_rsvps',
idAttribute: 'id',
validations: {
attendeeId: ['required', 'integer'],
isAttending: ['required', 'boolean']
}
});

AttendeeRSVP.findByAttendeeId = function (attendeeId) {
return AttendeeRSVP.where({ attendee_id: attendeeId }).fetch();
};

AttendeeRSVP.prototype.validate = function () {
var checkit = CheckIt(this.validations);
checkit.maybe({type: ['required', 'string', rsvp.verifyAttendanceReply]}, function(input) {
return input.isAttending;
});

return checkit.run(this.attributes);
};

module.exports = AttendeeRSVP;
4 changes: 2 additions & 2 deletions api/v1/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ User.prototype.setPassword = function (password) {
* @return {UserRole} the desired role, or undefined
*/
User.prototype.getRole = function (role) {
return _.find(this.related('roles').models, function (role) {
return role.role === role;
return _.find(this.related('roles').models, function (roleInUser) {
return roleInUser.get('role') === role;
});
};

Expand Down
1 change: 1 addition & 0 deletions api/v1/models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = {
AttendeeProject: require('./AttendeeProject'),
AttendeeProjectInterest: require('./AttendeeProjectInterest'),
AttendeeRequestedCollaborator: require('./AttendeeRequestedCollaborator'),
AttendeeRSVP: require('./AttendeeRSVP'),
Project: require('./Project'),
Ecosystem: require('./Ecosystem'),
MailingList: require('./MailingList'),
Expand Down
22 changes: 22 additions & 0 deletions api/v1/requests/RSVPRequest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
var Request = require('./Request');
var rsvp = require('../utils/rsvp');

var bodyRequired = ['isAttending'];
var bodyAllowed = ['type'];
var bodyValidations = {
'isAttending': ['required', 'boolean'],
'type': ['string', rsvp.verifyAttendanceReply]
};

function RSVPRequest(headers, body) {
Request.call(this, headers, body);

this.bodyRequired = bodyRequired;
this.bodyAllowed = bodyAllowed;
this.bodyValidations = bodyValidations;
}

RSVPRequest.prototype = Object.create(Request.prototype);
RSVPRequest.prototype.constructor = RSVPRequest;

module.exports = RSVPRequest;
3 changes: 2 additions & 1 deletion api/v1/requests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ module.exports = {
ProjectMentorRequest: require('./ProjectMentorRequest'),
ResetTokenRequest: require('./ResetTokenRequest'),
ResetPasswordRequest: require('./ResetPasswordRequest'),
UploadRequest: require('./UploadRequest')
UploadRequest: require('./UploadRequest'),
RSVPRequest: require('./RSVPRequest')
};
90 changes: 90 additions & 0 deletions api/v1/services/RSVPService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
var CheckitError = require('checkit').Error;
var _Promise = require('bluebird');
var _ = require('lodash');

var RSVP = require('../models/AttendeeRSVP');
var UserRole = require('../models/UserRole');
var errors = require('../errors');
var utils = require('../utils');

/**
* Gets an rsvp by its id
* @param {integer} id the id of the RSVP to find
* @returns {Promise} the resolved rsvp
*/
module.exports.getRSVPById = function (id) {
return RSVP.findById(id);
};

/**
* Creates an RSVP and sets the users attendee role to active
* @param {Attendee} attendee the associated attendee for the rsvp
* @param {User} user the associated user for the rsvp
* @param {Object} attributes the rsvp data
* @returns {Promise} the resolved rsvp
* @throws {InvalidParameterError} thrown when an attendee already has an rsvp
*/
module.exports.createRSVP = function (attendee, user, attributes) {
attributes.attendeeId = attendee.get('id');
var rsvp = RSVP.forge(attributes);

return rsvp
.validate()
.catch(CheckitError, utils.errors.handleValidationError)
.then(function (validated) {
return RSVP.findByAttendeeId(attributes.attendeeId);
})
.then(function (result) {
if (!_.isNull(result)) {
var message = "An RSVP already exists for the given attendee";
var source = "attendeeId";
throw new errors.InvalidParameterError(message, source);
}

var userRole = user.getRole(utils.roles.ATTENDEE);
UserRole.setActive(userRole, true);

return rsvp.save();
})
};

/**
* Finds an RSVP by its associated attendee
* @param {Attendee} attendee the associated attendee for the rsvp
* @returns {Promise} the resolved rsvp for the attendee
* @throws {NotFoundError} when the attendee has no RSVP
*/
module.exports.findRSVPByAttendee = function (attendee) {
return RSVP
.findByAttendeeId(attendee.get('id'))
.then(function (result) {
if (_.isNull(result)) {
var message = "An RSVP cannot be found for the given attendee";
var source = "attendeeId";
throw new errors.NotFoundError(message, source);
}

return _Promise.resolve(result);
});
};

/**
* Updates a given RSVP
* @param {RSVP} rsvp the RSVP to update
* @param {Object} attributes the new RSVP data to set
* @returns {Promise} the resolved RSVP
*/
module.exports.updateRSVP = function (user, rsvp, attributes) {
rsvp.set({'type': null});
rsvp.set(attributes);

return rsvp
.validate()
.catch(CheckitError, utils.errors.handleValidationError)
.then(function (validated) {
var userRole = user.getRole(utils.roles.ATTENDEE);
rsvp.get('isAttending') ? UserRole.setActive(userRole, true) : UserRole.setActive(userRole, false);

return rsvp.save();
});
};
Loading

0 comments on commit 8fc8ceb

Please sign in to comment.