draw.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import fs from 'fs'
  2. import Excel from './excel'
  3. import Draw from '../models/draw'
  4. import MatchList from '../models/matchList'
  5. import PlayerList from '../models/playerList'
  6. import moment from 'moment'
  7. import { normalize } from './helpers'
  8. import { session } from '../index'
  9. function initials (player) {
  10. const fnInitials = player.firstName
  11. .split('-')
  12. .map(element=>element
  13. .split(' ')
  14. .map(element => element[0]+'.')
  15. .join(' ')
  16. ).join('-')
  17. const fnInitialsDP = player.firstNameDP
  18. .split('-')
  19. .map(element=>element
  20. .split(' ')
  21. .map(element => element[0]+'.')
  22. .join(' ')
  23. ).join('-')
  24. return player.doubles ? `${player.name} ${fnInitials} / ${player.nameDP} ${fnInitialsDP}` : `${name} ${fnInitials}`
  25. }
  26. async function getDraws (req, res) {
  27. try {
  28. const draws = await Draw.find()
  29. return res.json(draws)
  30. } catch (error) {
  31. return res.status(400).json({ msg: error.toString() })
  32. }
  33. }
  34. async function getDraw (req, res) {
  35. try {
  36. const key = req.query.drawId ? { _id: req.query.drawId } : {}
  37. const draw = await MatchList.findOne(key).sort({ imported: -1 })
  38. return res.json(draw)
  39. } catch (error) {
  40. return res.status(400).json({ msg: error.toString() })
  41. }
  42. }
  43. async function downloadDraw (req, res) {
  44. try {
  45. const { drawId } = req.params
  46. const filename = `DisplayDraw-${drawId}-${moment().format('YYYYMMDDTHHmmss')}.xls`
  47. const drawFile = fs.createWriteStream(`swisstennis_files/${filename}`)
  48. const drawDisplay = await session.get(`https://comp.swisstennis.ch/advantage/servlet/DisplayDraw.xls?eventId=${drawId}&lang=D`, {stream: true})
  49. await drawDisplay.pipe(drawFile)
  50. const streamDone = new Promise((resolve, reject) => {
  51. drawFile.on('finish', resolve)
  52. drawFile.on('error', reject)
  53. })
  54. await streamDone
  55. const stats = fs.statSync(`swisstennis_files/${filename}`)
  56. return res.json({ filename, size: stats.size, mtime: stats.mtime })
  57. } catch (error) {
  58. return res.status(400).json({ msg: error.toString() })
  59. }
  60. }
  61. async function parseDraw (req,res) {
  62. try {
  63. console.log('Parsing file', req.params.filename)
  64. const filePath = `swisstennis_files/${req.params.filename}`
  65. const dateString = req.params.filename.match(/(\d{4}\d{2}\d{2}T\d{2}\d{2}\d{2})/)[1]
  66. const fileDate = moment(dateString)
  67. const stat = fs.statSync(filePath)
  68. const fileNewer = await Draw.find({ imported: { $gte: fileDate } })
  69. if (fileNewer.length) {
  70. throw Error('File has to be newer.')
  71. }
  72. console.log('About to read the draw.')
  73. const worksheets = await Excel.readWorkbook(`swisstennis_files/${req.params.filename}`)
  74. const worksheet = worksheets.Tableaux
  75. if (worksheet[0].length !== 1 || worksheet[1].length !== 1 || worksheet[2].length !== 1 || worksheet[3].length !== 0) {
  76. throw Error(`Wrong file structure.`)
  77. }
  78. const category = normalize(worksheet[2][0])
  79. const doubles = !!category.match(/DM.*|[MW]D.*/)
  80. const drawSize = ( worksheet.length - 4 + 1 ) / 2 // 4 header lines, 1 empty line between each player (n-1)
  81. const draw = worksheet.slice(4)
  82. const rounds = Math.log2(drawSize)
  83. const playerList = await PlayerList.findOne().sort({imported: -1}).populate('players')
  84. const players = playerList.players.filter(player => player.category === category)
  85. const matchList = await MatchList.findOne().sort({imported: -1}).populate('matches')
  86. const matches = matchList.matches
  87. const drawMatches = []
  88. for (var round = 0; round < rounds; round += 1) {
  89. const matchPositionOffset = Math.pow(2, round)
  90. const playerOffset = 2 * matchPositionOffset
  91. const roundOffset = playerOffset/2 - 1
  92. const matchIncrement = 2 * playerOffset
  93. for (var seq = 0; seq < drawSize / Math.pow(2, round + 1); seq += 1) {
  94. const matchPosition = roundOffset + seq * matchIncrement
  95. // Data from spreadsheet cells
  96. const player1String = normalize(draw[matchPosition][round])
  97. const player2String = normalize(draw[matchPosition + playerOffset][round])
  98. const winnerString = normalize(draw[matchPositionOffset + matchPosition][round + 1])
  99. const timePlaceResultString = normalize(draw[matchPositionOffset + matchPosition + 1][round + 1])
  100. const drawPlayerRegex = /^(?:\((\d+)\))?\s*\(([RN]\d\s?(?:\d+)?|NC)\) (.+)$/
  101. const drawDoubleRegex = /^(?:\((\d+)\))?\s*\(([RN]\d\s?(?:\d+)?|NC)\/([RN]\d\s?(?:\d+)?|NC)\) ([^\/]+)\s*\/\s*([^\/]+)$/
  102. const player1Match = doubles ? player1String.match(drawDoubleRegex) : player1String.match(drawDoubleRegex)
  103. const player2Match = doubles ? player2String.match(drawDoubleRegex) : player2String.match(drawDoubleRegex)
  104. console.log(player1Match, player2Match)
  105. const player1 = (round === 0) ?
  106. players.find(player => player1Match && (category === player.category) && (player1Match[3] === player.fullName)) :
  107. players.find(player => (category === player.category) && (player1String === initials(player)))
  108. const player2 = (round === 0) ?
  109. players.find(player => player2Match && (category === player.category) && (player2Match[3] === player.fullName)) :
  110. players.find(player => (category === player.category) && (player2String === initials(player)))
  111. const timePlace = timePlaceResultString.match(/^(\d{2}\/\d{2}\/\d{2})?\s+(\d{2}:\d{2})?\s*\(([^\)]+)\)?$/)
  112. const result = normalize(draw[matchPosition + playerOffset/2 + 1][round + 1]).match(/^((?:WO)?\s*(?:\d+\/\d+\s*)*)$/)
  113. const winner = winnerString
  114. const idString = (player1 && player2)
  115. const match = {
  116. created: new Date(),
  117. idString: '',
  118. category,
  119. place: timePlace && timePlace[3] || null,
  120. date: timePlace && timePlace[1] && timePlace[2] && moment(`${timePlace[1]} ${timePlace[2]}`, 'DD/MM/YY HH:mm') || null,
  121. round: round + 1,
  122. player1: player1 && player1._id || null,
  123. player2: player2 && player2._id || null,
  124. winner: winner || null,
  125. result: result && result[0] || null,
  126. doubles
  127. }
  128. drawMatches.push(match)
  129. }
  130. }
  131. console.log('matches:', drawMatches.length)
  132. return res.json({ drawMatches })
  133. } catch (error) {
  134. res.status(400).json({ msg: error.toString() })
  135. }
  136. }
  137. async function deleteDraw (req, res) {
  138. try {
  139. const { drawId } = req.params
  140. if (!drawId) {
  141. throw Error('No drawId given.')
  142. }
  143. const draw = await MatchList.findOne({ _id: drawId })
  144. if (!draw) {
  145. throw Error('Draw not found.')
  146. }
  147. draw.remove()
  148. return res.json({ _id: drawId })
  149. } catch (error) {
  150. return res.status(400).json({ msg: error.toString() })
  151. }
  152. }
  153. export default { getDraws, getDraw, downloadDraw, parseDraw, deleteDraw }