summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xmodels/Event.js6
-rwxr-xr-xroutes.js35
-rwxr-xr-xviews/event.handlebars11
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,
})
diff --git a/routes.js b/routes.js
index 7e582b4..ccb6518 100755
--- a/routes.js
+++ b/routes.js
@@ -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) => {