diff options
-rwxr-xr-x | models/Event.js | 6 | ||||
-rwxr-xr-x | routes.js | 35 | ||||
-rwxr-xr-x | views/event.handlebars | 11 |
3 files changed, 48 insertions, 4 deletions
diff --git a/models/Event.js b/models/Event.js index 07da03f..d800077 100755 --- a/models/Event.js +++ b/models/Event.js @@ -25,6 +25,12 @@ const Attendees = new mongoose.Schema({ unique: true, sparse: true, }, + // The number of people that are attending under one 'attendee' object + number: { + type: Number, + trim: true, + default: 1 + }, created: Date, }) @@ -378,6 +378,9 @@ router.get('/:eventID', (req, res) => { if (!el.id) { el.id = el._id; } + if (el.number > 1) { + el.name = `${el.name} (${el.number} people)`; + } return el; }) .filter((obj, pos, arr) => { @@ -385,8 +388,14 @@ router.get('/:eventID', (req, res) => { }); let spotsRemaining, noMoreSpots; + let numberOfAttendees = eventAttendees.reduce((acc, attendee) => { + if (attendee.status === 'attending') { + return acc + attendee.number || 1; + } + return acc; + }, 0); if (event.maxAttendees) { - spotsRemaining = event.maxAttendees - eventAttendees.length; + spotsRemaining = event.maxAttendees - numberOfAttendees; if (spotsRemaining <= 0) { noMoreSpots = true; } @@ -410,6 +419,7 @@ router.get('/:eventID', (req, res) => { escapedName: escapedName, eventData: event, eventAttendees: eventAttendees, + numberOfAttendees, spotsRemaining: spotsRemaining, noMoreSpots: noMoreSpots, eventStartISO: eventStartISO, @@ -1400,7 +1410,9 @@ router.post('/attendee/provision', async (req, res) => { }); addToLog("provisionEventAttendee", "success", "Attendee provisioned in event " + req.query.eventID); - return res.json({ removalPassword }); + // Return the removal password and the number of free spots remaining + const freeSpots = event.maxAttendees - event.attendees.reduce((acc, a) => acc + (a.status === 'attending' ? (a.number || 1) : 0), 0); + return res.json({ removalPassword, freeSpots }); }); router.post('/attendevent/:eventID', async (req, res) => { @@ -1408,12 +1420,29 @@ router.post('/attendevent/:eventID', async (req, res) => { if (!req.body.removalPassword) { return res.sendStatus(500); } + const event = await Event.findOne({ id: req.params.eventID }).catch(e => { + addToLog("attendEvent", "error", "Attempt to attend event " + req.params.eventID + " failed with error: " + e); + return res.sendStatus(500); + }); + if (!event) { + return res.sendStatus(404); + } + const attendee = event.attendees.find(a => a.removalPassword === req.body.removalPassword); + if (!attendee) { + return res.sendStatus(404); + } + // Do we have enough free spots in this event to accomodate this attendee? + const freeSpots = event.maxAttendees - event.attendees.reduce((acc, a) => acc + (a.status === 'attending' ? (a.number || 1) : 0), 0); + if (req.body.attendeeNumber > freeSpots) { + return res.sendStatus(403); + } Event.findOneAndUpdate({ id: req.params.eventID, 'attendees.removalPassword': req.body.removalPassword }, { "$set": { "attendees.$.status": "attending", "attendees.$.name": req.body.attendeeName, "attendees.$.email": req.body.attendeeEmail, + "attendees.$.number": req.body.attendeeNumber, } }).then((event) => { addToLog("addEventAttendee", "success", "Attendee added to event " + req.params.eventID); @@ -1450,7 +1479,7 @@ router.post('/attendevent/:eventID', async (req, res) => { }) .catch((error) => { res.send('Database error, please try again :('); - addToLog("addEventAttendee", "error", "Attempt to add attendee to event " + req.params.eventID + " failed with error: " + err); + addToLog("addEventAttendee", "error", "Attempt to add attendee to event " + req.params.eventID + " failed with error: " + error); }); }); diff --git a/views/event.handlebars b/views/event.handlebars index 9b5f3e2..8c7e2e8 100755 --- a/views/event.handlebars +++ b/views/event.handlebars @@ -128,7 +128,7 @@ {{#if eventData.usersCanAttend}} <div class="card mb-4" id="eventAttendees"> - <h5 class="card-header">Attendees {{#if eventAttendees}}({{eventAttendees.length}}){{/if}} + <h5 class="card-header">Attendees {{#if eventAttendees}}({{numberOfAttendees}}){{/if}} <div class="btn-group" role="group" aria-label="Attendance controls"> {{#unless noMoreSpots}} <button type="button" id="attendEvent" class="btn btn-success" data-event-id="{{eventData.id}}"><i class="fas fa-user-plus"></i> Add me</button> @@ -174,6 +174,12 @@ </div> </div> <div class="form-group"> + <label for="attendeeName">How many people in your party?</label> + <div class="form-group"> + <input type="number" class="form-control" id="attendeeNumber" name="attendeeNumber" value="1" data-validation="required number" > + </div> + </div> + <div class="form-group"> <label for="attendeeEmail">Your email (optional)</label> <p class="form-text small">If you provide your email, you will receive updates to the event.</p> <div class="form-group"> @@ -576,6 +582,9 @@ axios.post('/attendee/provision', {}, { params: { eventID }}) .then((response) => { modal.find('#removalPassword').val(response.data.removalPassword); + modal.find('#attendeeNumber') + .attr('data-validation-allowing', `range[1;${response.data.freeSpots}]`) + .attr('data-validation-error-msg', `Please enter a number between 1 and ${response.data.freeSpots}`); modal.modal(); }) .catch((error) => { |