feat(weather): OWM-Fallback über Server-.env wenn kein User-Key

Wetter-Proxy auf /api/weather/current nutzt optionalen Nutzer-Key aus
den Einstellungen, sonst OpenWeatherMapAPIKey aus der Umgebung.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-30 12:37:58 +02:00
co-authored by Cursor
parent 69d5203305
commit 03bb55f9a1
8 changed files with 160 additions and 48 deletions
+8 -1
View File
@@ -1,15 +1,21 @@
import express from 'express'
import cors from 'cors'
import dotenv from 'dotenv'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import authRouter from './routes/auth.js'
import logbooksRouter from './routes/logbooks.js'
import syncRouter from './routes/sync.js'
import collaborationRouter from './routes/collaboration.js'
import signRouter from './routes/sign.js'
import pushRouter from './routes/push.js'
import weatherRouter from './routes/weather.js'
import { prisma } from './db.js'
dotenv.config()
const __dirname = dirname(fileURLToPath(import.meta.url))
dotenv.config({ path: resolve(__dirname, '../../.env') })
dotenv.config({ path: resolve(__dirname, '../.env') })
const app = express()
const PORT = process.env.PORT || 5000
@@ -24,6 +30,7 @@ app.use('/api/sync', syncRouter)
app.use('/api/collaboration', collaborationRouter)
app.use('/api/sign', signRouter)
app.use('/api/push', pushRouter)
app.use('/api/weather', weatherRouter)
// Health check endpoint
app.get('/api/health', async (req, res) => {
+59
View File
@@ -0,0 +1,59 @@
import { Router } from 'express'
const router = Router()
const requireUser = (req: any, res: any, next: any) => {
const userId = req.headers['x-user-id']
if (!userId) {
return res.status(401).json({ error: 'Unauthorized: X-User-Id header missing' })
}
req.userId = userId
next()
}
function resolveOwmApiKey(userProvidedKey: unknown): string | null {
if (typeof userProvidedKey === 'string' && userProvidedKey.trim()) {
return userProvidedKey.trim()
}
const fromEnv =
process.env.OpenWeatherMapAPIKey?.trim() ||
process.env.OPENWEATHERMAP_API_KEY?.trim()
return fromEnv || null
}
router.get('/current', requireUser, async (req: any, res) => {
try {
const { lat, lon, q } = req.query
const apiKey = resolveOwmApiKey(req.headers['x-owm-api-key'])
if (!apiKey) {
return res.status(503).json({
error: 'No OpenWeatherMap API key configured (user settings or server environment)'
})
}
let url: URL
if (lat && lon) {
url = new URL('https://api.openweathermap.org/data/2.5/weather')
url.searchParams.set('lat', String(lat))
url.searchParams.set('lon', String(lon))
} else if (q && typeof q === 'string' && q.trim()) {
url = new URL('https://api.openweathermap.org/data/2.5/weather')
url.searchParams.set('q', q.trim())
} else {
return res.status(400).json({ error: 'lat and lon, or q (location name) is required' })
}
url.searchParams.set('appid', apiKey)
url.searchParams.set('units', 'metric')
const owmRes = await fetch(url)
const data = await owmRes.json()
return res.status(owmRes.status).json(data)
} catch (error: any) {
console.error('Error fetching OpenWeatherMap data:', error)
return res.status(502).json({ error: error.message || 'Weather lookup failed' })
}
})
export default router