Add script for importing match schedule and logging
Some checks failed
Code Analysis and Production Deploy / analyze (push) Has been skipped
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Successful in 2m2s
Code Analysis and Production Deploy / analyze (pull_request) Failing after 33s
Code Analysis and Production Deploy / deploy-production (pull_request) Has been skipped
Code Analysis and Production Deploy / deploy-test (pull_request) Has been skipped
Require Package Version Change / check (pull_request) Failing after 10s
Some checks failed
Code Analysis and Production Deploy / analyze (push) Has been skipped
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Successful in 2m2s
Code Analysis and Production Deploy / analyze (pull_request) Failing after 33s
Code Analysis and Production Deploy / deploy-production (pull_request) Has been skipped
Code Analysis and Production Deploy / deploy-test (pull_request) Has been skipped
Require Package Version Change / check (pull_request) Failing after 10s
- Created `import-spielplan.js` to fetch and parse the match schedule from the specified URL, saving the output as JSON. - Added `run-spielplan-import.sh` to automate the execution of the import script and log output. - Introduced `spielplan.html` file to store the downloaded HTML content for further processing.
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { getUserFromToken, hasAnyRole } from '../../utils/auth.js'
|
||||
import {
|
||||
createSpielplanJsonFromCsv,
|
||||
getCurrentSeasonSlug,
|
||||
getSpielplanSeasonJsonPathForCsvPath,
|
||||
inferSeasonSlugFromRows
|
||||
} from '../../utils/spielplan-data.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
@@ -104,11 +110,20 @@ export default defineEventHandler(async (event) => {
|
||||
const uniquePaths = [...new Set([...internalPaths])]
|
||||
const writeResults = []
|
||||
const writeErrors = []
|
||||
const jsonWriteResults = []
|
||||
|
||||
for (const targetPath of uniquePaths) {
|
||||
try {
|
||||
await writeFileAtomicAndVerify(targetPath, content)
|
||||
writeResults.push(targetPath)
|
||||
if (filename === 'spielplan.csv') {
|
||||
const spielplanJson = createSpielplanJsonFromCsv(content)
|
||||
const seasonSlug = inferSeasonSlugFromRows(spielplanJson.data) || getCurrentSeasonSlug()
|
||||
const jsonContent = `${JSON.stringify(spielplanJson, null, 2)}\n`
|
||||
const jsonPath = getSpielplanSeasonJsonPathForCsvPath(targetPath, seasonSlug)
|
||||
await writeFileAtomicAndVerify(jsonPath, jsonContent)
|
||||
jsonWriteResults.push(jsonPath)
|
||||
}
|
||||
} catch (e) {
|
||||
writeErrors.push({ targetPath, error: e?.message || String(e) })
|
||||
}
|
||||
@@ -125,7 +140,8 @@ export default defineEventHandler(async (event) => {
|
||||
return {
|
||||
success: true,
|
||||
message: 'Datei erfolgreich gespeichert',
|
||||
writtenTo: writeResults
|
||||
writtenTo: writeResults,
|
||||
jsonWrittenTo: jsonWriteResults
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,61 +1,39 @@
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { listSpielplanSeasons, readSpielplanData } from '../utils/spielplan-data.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const filePath = path.join(process.cwd(), 'public', 'data', 'spielplan.csv')
|
||||
|
||||
// Prüfe ob Datei existiert
|
||||
try {
|
||||
await fs.access(filePath)
|
||||
} catch (_error) {
|
||||
const query = getQuery(event)
|
||||
const [spielplan, seasons] = await Promise.all([
|
||||
readSpielplanData({ season: query.season }),
|
||||
listSpielplanSeasons()
|
||||
])
|
||||
|
||||
if (!spielplan.data.length || !spielplan.headers.length) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Spielplan-Datei nicht gefunden',
|
||||
data: []
|
||||
message: 'Spielplan-Datei nicht gefunden oder leer',
|
||||
data: [],
|
||||
headers: []
|
||||
}
|
||||
}
|
||||
|
||||
// CSV-Datei lesen
|
||||
const csvContent = await fs.readFile(filePath, 'utf-8')
|
||||
const lines = csvContent.split('\n').filter(line => line.trim() !== '')
|
||||
|
||||
if (lines.length < 2) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Spielplan-Datei ist leer oder unvollständig',
|
||||
data: []
|
||||
}
|
||||
}
|
||||
|
||||
// Header-Zeile parsen
|
||||
const headers = lines[0].split(';').map(header => header.trim())
|
||||
|
||||
// Datenzeilen parsen
|
||||
const data = lines.slice(1).map(line => {
|
||||
const values = line.split(';').map(value => value.trim())
|
||||
const row = {}
|
||||
|
||||
headers.forEach((header, index) => {
|
||||
row[header] = values[index] || ''
|
||||
})
|
||||
|
||||
return row
|
||||
})
|
||||
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Spielplan erfolgreich geladen',
|
||||
data: data,
|
||||
headers: headers
|
||||
data: spielplan.data,
|
||||
headers: spielplan.headers,
|
||||
source: spielplan.source,
|
||||
filePath: spielplan.filePath,
|
||||
season: spielplan.season,
|
||||
seasons
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden des Spielplans:', error)
|
||||
return {
|
||||
success: false,
|
||||
message: 'Fehler beim Laden des Spielplans',
|
||||
data: []
|
||||
data: [],
|
||||
headers: []
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { readSpielplanData } from '../../utils/spielplan-data.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
@@ -13,56 +14,15 @@ export default defineEventHandler(async (event) => {
|
||||
})
|
||||
}
|
||||
|
||||
// Lade Spielplandaten - bevorzugt aus server/data
|
||||
let csvPath = path.join(process.cwd(), 'server/data/spielplan.csv')
|
||||
try {
|
||||
await fs.access(csvPath)
|
||||
} catch {
|
||||
csvPath = path.join(process.cwd(), 'public/data/spielplan.csv')
|
||||
}
|
||||
|
||||
let csvContent
|
||||
try {
|
||||
csvContent = await fs.readFile(csvPath, 'utf-8')
|
||||
} catch (_error) {
|
||||
const spielplan = await readSpielplanData({ season: query.season })
|
||||
if (!spielplan.data.length || !spielplan.headers.length) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Spielplandaten nicht gefunden'
|
||||
})
|
||||
}
|
||||
|
||||
// Parse CSV
|
||||
const lines = csvContent.split('\n').filter(line => line.trim())
|
||||
if (lines.length < 2) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'Keine Spielplandaten verfügbar'
|
||||
})
|
||||
}
|
||||
|
||||
// Automatische Erkennung des Trennzeichens
|
||||
const firstLine = lines[0]
|
||||
const tabCount = (firstLine.match(/\t/g) || []).length
|
||||
const semicolonCount = (firstLine.match(/;/g) || []).length
|
||||
const delimiter = tabCount > semicolonCount ? '\t' : ';'
|
||||
|
||||
// nosemgrep: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring
|
||||
console.log(`Verwendetes Trennzeichen: ${delimiter === '\t' ? 'Tab' : 'Semikolon'}`)
|
||||
|
||||
const headers = firstLine.split(delimiter)
|
||||
console.log('CSV-Header:', headers)
|
||||
|
||||
const dataRows = lines.slice(1).map(line => {
|
||||
const values = line.split(delimiter)
|
||||
const row = {}
|
||||
headers.forEach((header, index) => {
|
||||
row[header] = values[index] || ''
|
||||
})
|
||||
return row
|
||||
})
|
||||
|
||||
console.log('Anzahl Datenzeilen:', dataRows.length)
|
||||
console.log('Erste Datenzeile:', dataRows[0])
|
||||
|
||||
const dataRows = spielplan.data
|
||||
|
||||
// Filtere Daten basierend auf Team
|
||||
let filteredData = dataRows
|
||||
@@ -175,33 +135,6 @@ export default defineEventHandler(async (event) => {
|
||||
})
|
||||
}
|
||||
|
||||
// Filtere nach aktueller Saison (2025/26)
|
||||
const currentSaisonStart = new Date(2025, 6, 1) // 01.07.2025
|
||||
const currentSaisonEnd = new Date(2026, 5, 30) // 30.06.2026
|
||||
|
||||
filteredData = filteredData.filter(row => {
|
||||
const termin = row.Termin
|
||||
if (!termin) return false
|
||||
|
||||
try {
|
||||
let spielDatum
|
||||
|
||||
if (termin.includes(' ')) {
|
||||
const datumTeil = termin.split(' ')[0]
|
||||
const [tag, monat, jahr] = datumTeil.split('.')
|
||||
spielDatum = new Date(jahr, monat - 1, tag)
|
||||
} else {
|
||||
spielDatum = new Date(termin)
|
||||
}
|
||||
|
||||
if (isNaN(spielDatum.getTime())) return false
|
||||
|
||||
return spielDatum >= currentSaisonStart && spielDatum <= currentSaisonEnd
|
||||
} catch (_error) {
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
// Sammle Halle-Informationen für die jeweilige Mannschaft
|
||||
const hallenMap = new Map()
|
||||
|
||||
|
||||
24
server/api/spielplan/seasons.get.js
Normal file
24
server/api/spielplan/seasons.get.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { getCurrentSeasonSlug, listSpielplanSeasons } from '../../utils/spielplan-data.js'
|
||||
|
||||
export default defineEventHandler(async () => {
|
||||
try {
|
||||
const seasons = await listSpielplanSeasons()
|
||||
const currentSeason = getCurrentSeasonSlug()
|
||||
const defaultSeason = seasons.find((season) => season.slug === currentSeason)?.slug || seasons[0]?.slug || null
|
||||
|
||||
return {
|
||||
success: true,
|
||||
seasons,
|
||||
currentSeason,
|
||||
defaultSeason
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Spielplan-Saisons:', error)
|
||||
return {
|
||||
success: false,
|
||||
seasons: [],
|
||||
currentSeason: getCurrentSeasonSlug(),
|
||||
defaultSeason: null
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user