From 9d518a40155680cb7a631512bbeb89394b0cebcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20L=C3=B6w?= Date: Sat, 9 Jan 2021 23:17:13 +0100 Subject: [PATCH] mensa and index: use the reimplemented Mensa API which now uses the same json format as the THI API --- rogue-thi-app/lib/reimplemented-api-client.js | 30 ++++++++ rogue-thi-app/pages/api/mensa.js | 68 +++++++++++++++++++ rogue-thi-app/pages/index.js | 17 ++--- rogue-thi-app/pages/mensa.js | 6 +- 4 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 rogue-thi-app/lib/reimplemented-api-client.js diff --git a/rogue-thi-app/lib/reimplemented-api-client.js b/rogue-thi-app/lib/reimplemented-api-client.js new file mode 100644 index 00000000..19c1f260 --- /dev/null +++ b/rogue-thi-app/lib/reimplemented-api-client.js @@ -0,0 +1,30 @@ +import MemoryCache from './memory-cache' +import LocalStorageCache from './localstorage-cache' + +const CACHE_NAMESPACE = 'reimplemented-api-client' +const CACHE_TTL = 10 * 60 * 1000 + +const KEY_GET_MENSA_PLAN = 'getMensaPlan' + +let cache +if (typeof localStorage === 'undefined') { + cache = new MemoryCache({ + ttl: CACHE_TTL + }) +} else { + cache = new LocalStorageCache({ + namespace: CACHE_NAMESPACE, + ttl: CACHE_TTL + }) +} + +export async function getMensaPlan () { + let res = cache.get(KEY_GET_MENSA_PLAN) + if (!res) { + res = await fetch('/api/mensa').then(res => res.json()) + } + + cache.set(KEY_GET_MENSA_PLAN, res) + + return res.data +} \ No newline at end of file diff --git a/rogue-thi-app/pages/api/mensa.js b/rogue-thi-app/pages/api/mensa.js index e6330333..c9e7f1a7 100644 --- a/rogue-thi-app/pages/api/mensa.js +++ b/rogue-thi-app/pages/api/mensa.js @@ -7,6 +7,73 @@ const URL_EN = 'https://www.max-manager.de/daten-extern/sw-erlangen-nuernberg/xm const cache = new MemoryCache({ ttl: CACHE_TTL }) +const dayTexts = [ + 'Sonntag', + 'Montag', + 'Dienstag', + 'Mittwoch', + 'Donnerstag', + 'Freitag', + 'Samstag', +] +function pad2(val) { + return val.toString().padStart(2, '0') +} +function dateToTHIFormat(date) { + return `${pad2(date.getDate())}.${pad2(date.getMonth() + 1)}.${pad2(date.getFullYear())}`; +} +function convertToTHIFormat (sourceData) { + let sourceDays = sourceData.speiseplan.tag + if(!Array.isArray(sourceDays)) + sourceDays = [sourceDays] + + const days = sourceData.speiseplan.tag.map(day => { + const date = new Date(day._attributes.timestamp * 1000) + + let sourceItems = day.item + if(!Array.isArray(sourceItems)) + sourceItems = [sourceItems] + + const items = {} + const addInReg = /\s*\((.*?)\)\s*/ + sourceItems.forEach((item, i) => { + let text = item.title._text + let addIns = new Set() + while(addInReg.test(text)) { + const [addInText, addIn] = text.match(addInReg) + text = text.replace(addInText, ' ') + + const newAddins = addIn.split(',') + newAddins.forEach(newAddin => addIns.add(newAddin)) + } + + items[i] = { + zusatz: [...addIns].join(','), + name: [ + '', + text.trim(), + item.preis1._text, + item.preis2._text, + item.preis3._text, + ] + } + }) + + return { + tag: `${dayTexts[date.getDay()]} ${dateToTHIFormat(date)}`, + gerichte: items, + } + }) + + const now = new Date() + return { + data: days, + status: 0, + date: dateToTHIFormat(now), + time: `${pad2(now.getHours())}:${pad2(now.getMinutes())}:${pad2(now.getSeconds())}`, + } +} + async function fetchPlan (lang) { const url = (lang || 'de') === 'de' ? URL_DE : URL_EN @@ -15,6 +82,7 @@ async function fetchPlan (lang) { if (!plan) { const resp = await fetch(url) plan = xmljs.xml2js(await resp.text(), { compact: true }) + plan = convertToTHIFormat(plan) cache.set(url, plan) } diff --git a/rogue-thi-app/pages/index.js b/rogue-thi-app/pages/index.js index 65eee58b..5818003a 100644 --- a/rogue-thi-app/pages/index.js +++ b/rogue-thi-app/pages/index.js @@ -31,7 +31,8 @@ import styles from '../styles/Home.module.css' import AppNavbar from '../lib/AppNavbar' import InstallPrompt from '../lib/InstallPrompt' import { obtainSession, forgetSession } from '../lib/thi-session-handler' -import { getTimetable, getMensaPlan, getPersonalData } from '../lib/thi-api-client' +import { getTimetable, getPersonalData } from '../lib/thi-api-client' +import { getMensaPlan } from '../lib/reimplemented-api-client' import { formatNearDate, formatFriendlyTime } from '../lib/date-utils' const IMPRINT_URL = process.env.NEXT_PUBLIC_IMPRINT_URL @@ -57,7 +58,7 @@ async function getTimetablePreview (session) { } async function getMensaPlanPreview (session) { - const days = await getMensaPlan(session) + const days = await getMensaPlan() return Object.values(days[0].gerichte) .map(x => x.name[1]) @@ -109,20 +110,20 @@ export default function Home () { const router = useRouter() useEffect(async () => { - const session = await obtainSession(router) - try { - setTimetable(await getTimetablePreview(session)) + setMensaPlan(await getMensaPlanPreview()) } catch (e) { console.error(e) - setTimetableError(e) + setMensaPlanError(e) } + const session = await obtainSession(router) + try { - setMensaPlan(await getMensaPlanPreview(session)) + setTimetable(await getTimetablePreview(session)) } catch (e) { console.error(e) - setMensaPlanError(e) + setTimetableError(e) } }, []) diff --git a/rogue-thi-app/pages/mensa.js b/rogue-thi-app/pages/mensa.js index ba4fea13..9deb58d6 100644 --- a/rogue-thi-app/pages/mensa.js +++ b/rogue-thi-app/pages/mensa.js @@ -15,8 +15,7 @@ import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons' import styles from '../styles/Timetable.module.css' import AppNavbar from '../lib/AppNavbar' -import { obtainSession } from '../lib/thi-session-handler' -import { getMensaPlan } from '../lib/thi-api-client' +import { getMensaPlan } from '../lib/reimplemented-api-client' import { formatNearDate } from '../lib/date-utils' import allergenMap from '../data/allergens.json' @@ -45,8 +44,7 @@ export default function Timetable () { useEffect(async () => { try { - const session = await obtainSession(router) - const data = await getMensaPlan(session) + const data = await getMensaPlan() const days = data.map(x => ({ date: parseGermanDate(x.tag),