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) => {  | 
