const path = require('path') const fs = require('fs') const {groupTeamsnapItems, parsePositionLabel, compilePositionLabel, teamsnapCallback} = require("../lib/utils") const tsUtils = require('../lib/utils') const { loadEventLineupEntries } = require('teamsnap.js') exports.partials = path.join(__dirname, "../views/eventlineup/partials") exports.helpers = require('../helpers/eventlineup.js') exports.getEventLineup = async (req, res)=>{ await Promise.all(req.promises) const {user, team, members, event, layout, event_lineup, event_lineup_entries, availabilities, availabilitySummary, csrfToken} = req attachBenchcoachPropertiesToMember(members, event_lineup_entries, availabilities) members.sort(tsUtils.teamsnapMembersSortLineupAvailabilityLastName) const scripts = [ "https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js", "/js/eventlineup.js", "/js/tinymce.min.js" ] res.render("eventlineup/edit", {user, team, members, event, availabilities, scripts, layout, event_lineup, event_lineup_entries, availabilitySummary, csrfToken}) } exports.getAdjacentEventLineup = async (req, res) => { await Promise.all(req.promises) const index = Number(req.query.index) const {user, team, members, csrfToken} = req let event if (index > 0) { event = req.upcoming_events[index-1] } else if (index < 0){ event = req.recent_events[Math.abs(index)-1] } else { throw new Error('Index must be positive or negative number') } if (!event) { res.status(500).send() return } const availabilitySummary = event.availabilitySummary const event_lineup = req.timeline.event_lineups?.find(i=>i.eventId==event.id) const event_lineup_entries = req.timeline.event_lineup_entries?.filter(i=>i.eventId==event.id) const availabilities = req.timeline.availabilities.filter(i=>i.eventId==event.id) attachBenchcoachPropertiesToMember(members, event_lineup_entries, availabilities) members.sort(tsUtils.teamsnapMembersSortLineupAvailabilityLastName) console.log() res.render("eventlineup/edit", {user, team, members, event, layout: null, event_lineup, event_lineup_entries, availabilitySummary, availabilities, csrfToken}) } attachBenchcoachPropertiesToMember = (members, event_lineup_entries, availabilities) => { members.forEach((member)=> { // I *think* this can be done with linking https://github.com/teamsnap/teamsnap-javascript-sdk/wiki/Persistence#linking // here's an example: // member.link('eventLineupEntry', event_lineup_entries.find(i=>i.id=members[1].id)) member.benchcoach = {} // I don't really like this, but the member_id changes once a season is archived. // as far as I can tell, member_name should consistently be formulated from first and last name // perhaps could have some edge cases if first or last names change, but this *should be* exceedingly rare. const member_name = `${member.firstName} ${member.lastName}` const event_lineup_entry = event_lineup_entries?.find(e=> e.memberId == member.id || e.memberName == member_name) const availability = availabilities.find(e=>e.memberId == member.id) member.benchcoach.availability = availability if (event_lineup_entry != null) { // member.link('eventLineupEntry', event_lineup_entry) member.benchcoach.eventLineupEntry = event_lineup_entry const {positionLabelWithoutFlag, positionFlags} = parsePositionLabel(event_lineup_entry.label); member.benchcoach.eventLineupEntry.positionLabelWithoutFlag = positionLabelWithoutFlag member.benchcoach.eventLineupEntry.flags = positionFlags } else { member.benchcoach.eventLineupEntry = null } } ) } exports.attachBenchcoachPropertiesToMember = attachBenchcoachPropertiesToMember exports.getEventLineupEmail = async (req, res)=>{ const {body} = req if (body.memberId == null) {res.status(400).end();return} await Promise.all(req.promises) const {user, team, members, event, layout, event_lineup, event_lineup_entries, availabilities, availabilitySummary} = req const eventLineupEntries = req.event_lineup.eventLineupEntries const {newEventLineupEntries} = processPostedEventLineupEntries(body, eventLineupEntries, event_lineup) attachBenchcoachPropertiesToMember(members, newEventLineupEntries, availabilities) members.sort(tsUtils.teamsnapMembersSortLineupAvailabilityLastName) res.status(200).render("eventlineup/partials/email_modal.hbs", {layout:null, user, team, members, event, event_lineup, event_lineup_entries: newEventLineupEntries, availabilities, availabilitySummary}) } exports.getAvailabilityRemindersModal = (req, res) => { res.status(200).render("eventlineup/partials/availability_reminder_modal.hbs") } exports.getEventLineupEntries = async (req, res)=>{ const {event_lineup, event_lineup_entries} = req res.setHeader('Content-Type', 'application/json').send(JSON.stringify(req.event_lineup_entries)) } exports.getEventLineupEntriesData = async (req, res)=>{ const {event_lineup, event_lineup_entries} = req res.setHeader('Content-Type', 'application/json').send(JSON.stringify(req.event_lineup_entries)) } exports.postEventLineup = async (req,res) => { const {body} = req if (body.memberId == null) {res.status(400).end();return} await Promise.all(req.promises); const eventLineupEntries = req.event_lineup.eventLineupEntries const {newEventLineupEntries, deleteEventLineupEntries} = processPostedEventLineupEntries(body, eventLineupEntries, req.event_lineup) newEventLineupEntries.forEach(e=>{ teamsnap.saveEventLineupEntry(e, teamsnapCallback) }) deleteEventLineupEntries.forEach(e=>{ teamsnap.deleteEventLineupEntry(e, teamsnapCallback) }) const bulk_items = await teamsnap.bulkLoad( {teamId: req.params.team_id, types: ['eventLineup', 'eventLineupEntry'], scopeTo:'event', event__id:req.params.event_id,}, null, (err, items) => {teamsnapCallback(err, items, {req, source:"postEventLineup", method:'bulkLoad'})} ) groupedReturnedItems = groupTeamsnapItems(bulk_items) returnedEventLineupEntries = groupedReturnedItems.eventLineupEntries res.status(201).end(JSON.stringify(returnedEventLineupEntries)) } const processPostedEventLineupEntries = (body, eventLineupEntries, eventLineup) => { const newEventLineupEntries = [] const deleteEventLineupEntries = [] body.memberId.forEach((memberId, i)=>{ const lineupEntryId = body.eventLineupEntryId[i] const lineupEntryLabel = body.label[i] const lineupEntrySequence = body.sequence[i] const lineupEntryFlags = body.flags[i] if (lineupEntryId != '' && lineupEntryLabel != '') { // Update lineup entry try { const eventLineupEntry = eventLineupEntries.find((e)=>e.id==Number(lineupEntryId)) eventLineupEntry.sequence = lineupEntrySequence eventLineupEntry.label = compilePositionLabel(lineupEntryLabel, lineupEntryFlags) newEventLineupEntries.push(eventLineupEntry) } catch { console.log } } else if (lineupEntryId != '') { // Delete lineup entry const eventLineupEntry = eventLineupEntries.find((e)=>e.id==Number(lineupEntryId)) deleteEventLineupEntries.push(eventLineupEntry) } else if (lineupEntryLabel != '') { // Create lineup entry const eventLineupEntry = teamsnap.createEventLineupEntry() eventLineupEntry.eventLineupId = eventLineup.id eventLineupEntry.memberId = memberId eventLineupEntry.sequence = lineupEntrySequence eventLineupEntry.label = compilePositionLabel(lineupEntryLabel, lineupEntryFlags) newEventLineupEntries.push(eventLineupEntry) } else { // Skip lineup entry } }) return {newEventLineupEntries, eventLineupEntries, deleteEventLineupEntries} } exports.submitDeleteEventLineupEntries = async (req,res) => { await Promise.all(req.promises); const {event_lineup, event_lineup_entries} = req let event_id let memberIds if (!req.body || ! (req.body.event_id && req.body.memberIds)) { res.status(400).send('Malformed post') } else if (req.params.event_id != req.body.event_id) { // Load actual event. Do I want this to be an error? probably res.status(400).send('Event ID parameter does not match the POST body'); return } else { event_id = req.body.event_id memberIds = req.body.memberIds } const deletion_promises = [] event_lineup_entries.filter(entry =>memberIds.includes(entry.memberId.toString())).forEach( entry => { const promise = teamsnap.deleteEventLineupEntry(entry, teamsnapCallback) deletion_promises.push(promise) }) await Promise.all(deletion_promises) .then(res.status(202).send('OK')) }