11import "dotenv/config" ;
2- import { pgFindAirportFlights , pgHealthCheck , pgShutdown } from "@sr24/db/pg" ;
2+ import { pgFindAirportFlights , pgHealthCheck , pgShutdown , prisma } from "@sr24/db/pg" ;
33import { rdsConnect , rdsGetMultiple , rdsGetRing , rdsGetSingle , rdsGetTimeSeries , rdsHealthCheck , rdsShutdown } from "@sr24/db/redis" ;
44import cors from "cors" ;
55import express from "express" ;
66import rateLimit from "express-rate-limit" ;
77import helmet from "helmet" ;
8+ import { type AuthRequest , authHandler } from "./auth.js" ;
9+ import { errorHandler } from "./error.js" ;
810import { validateCallsign , validateICAO , validateNumber , validateString } from "./validation.js" ;
911import { getMetar , getTaf } from "./weather.js" ;
1012
@@ -29,18 +31,10 @@ app.use(cors());
2931app . use ( express . json ( ) ) ;
3032app . use ( limiter ) ;
3133
32- // Async error wrapper
33- const asyncHandler =
34- ( fn : ( req : express . Request , res : express . Response , next : express . NextFunction ) => Promise < void > | Promise < any > ) =>
35- ( req : express . Request , res : express . Response , next : express . NextFunction ) => {
36- // console.log(`Incoming request: ${req.method} ${req.originalUrl}`);
37- Promise . resolve ( fn ( req , res , next ) ) . catch ( next ) ;
38- } ;
39-
4034// Health check endpoints
4135app . get (
4236 "/health" ,
43- asyncHandler ( async ( _req , res ) => {
37+ errorHandler ( async ( _req , res ) => {
4438 const startTime = Date . now ( ) ;
4539 const health = {
4640 status : "ok" ,
@@ -82,7 +76,7 @@ app.get(
8276
8377app . get (
8478 "/health/live" ,
85- asyncHandler ( async ( _req , res ) => {
79+ errorHandler ( async ( _req , res ) => {
8680 res . json ( {
8781 status : "alive" ,
8882 timestamp : new Date ( ) . toISOString ( ) ,
@@ -92,7 +86,7 @@ app.get(
9286
9387app . get (
9488 "/health/ready" ,
95- asyncHandler ( async ( _req , res ) => {
89+ errorHandler ( async ( _req , res ) => {
9690 try {
9791 const redisHealthy = await rdsHealthCheck ( ) ;
9892 const pgHealthy = await pgHealthCheck ( ) ;
@@ -126,7 +120,7 @@ app.get(
126120
127121app . get (
128122 "/data/init" ,
129- asyncHandler ( async ( _req , res ) => {
123+ errorHandler ( async ( _req , res ) => {
130124 const all = await rdsGetSingle ( "ws:all" ) ;
131125 if ( ! all ) {
132126 res . status ( 404 ) . json ( { error : "Initial data not found" } ) ;
@@ -142,7 +136,7 @@ app.get(
142136
143137app . get (
144138 "/data/pilot/:id" ,
145- asyncHandler ( async ( req , res ) => {
139+ errorHandler ( async ( req , res ) => {
146140 const id = validateString ( req . params . id , "Pilot ID" , 1 , 10 ) ;
147141
148142 const pilot = await rdsGetSingle ( `pilot:${ id } ` ) ;
@@ -157,7 +151,7 @@ app.get(
157151
158152app . get (
159153 "/data/airport/:icao" ,
160- asyncHandler ( async ( req , res ) => {
154+ errorHandler ( async ( req , res ) => {
161155 const icao = validateICAO ( req . params . icao ) . toUpperCase ( ) ;
162156
163157 const airport = await rdsGetSingle ( `airport:${ icao } ` ) ;
@@ -172,7 +166,7 @@ app.get(
172166
173167app . get (
174168 "/data/weather/:icao" ,
175- asyncHandler ( async ( req , res ) => {
169+ errorHandler ( async ( req , res ) => {
176170 const icao = validateICAO ( req . params . icao ) . toUpperCase ( ) ;
177171 const metar = getMetar ( icao ) ;
178172 const taf = getTaf ( icao ) ;
@@ -183,7 +177,7 @@ app.get(
183177
184178app . get (
185179 "/data/controllers/:callsigns" ,
186- asyncHandler ( async ( req , res ) => {
180+ errorHandler ( async ( req , res ) => {
187181 const callsignArray = req . params . callsigns . split ( "," ) . map ( ( cs ) => validateCallsign ( cs . trim ( ) ) ) ;
188182
189183 if ( callsignArray . length === 0 ) {
@@ -204,7 +198,7 @@ app.get(
204198
205199app . get (
206200 "/data/track/:id" ,
207- asyncHandler ( async ( req , res ) => {
201+ errorHandler ( async ( req , res ) => {
208202 const id = validateString ( req . params . id , "Track ID" , 1 , 10 ) ;
209203
210204 // const trackPoints = await pgGetTrackPointsByid(id);
@@ -220,7 +214,7 @@ app.get(
220214
221215app . get (
222216 "/data/aircraft/:reg" ,
223- asyncHandler ( async ( req , res ) => {
217+ errorHandler ( async ( req , res ) => {
224218 const reg = validateString ( req . params . reg , "Aircraft Registration" , 1 , 10 ) . toUpperCase ( ) ;
225219
226220 const aircraft = await rdsGetSingle ( `static_fleet:${ reg } ` ) ;
@@ -235,7 +229,7 @@ app.get(
235229
236230app . get (
237231 "/data/dashboard/" ,
238- asyncHandler ( async ( _req , res ) => {
232+ errorHandler ( async ( _req , res ) => {
239233 const stats = await rdsGetSingle ( `dashboard:stats` ) ;
240234 const history = await rdsGetRing ( `dashboard:history` , 24 * 60 * 60 * 1000 ) ;
241235 const events = await rdsGetSingle ( `dashboard:events` ) ;
@@ -251,7 +245,7 @@ app.get(
251245
252246app . get (
253247 "/data/airport/:icao/flights" ,
254- asyncHandler ( async ( req , res ) => {
248+ errorHandler ( async ( req , res ) => {
255249 const icao = validateICAO ( req . params . icao ) . toUpperCase ( ) ;
256250 const direction = ( String ( req . query . direction || "dep" ) . toLowerCase ( ) === "arr" ? "arr" : "dep" ) as "dep" | "arr" ;
257251 const limit = validateNumber ( req . query . limit || 20 , "Limit" , 1 , 30 ) ;
@@ -263,6 +257,48 @@ app.get(
263257 } ) ,
264258) ;
265259
260+ app . get (
261+ "/user/settings" ,
262+ authHandler ,
263+ errorHandler ( async ( req : AuthRequest , res ) => {
264+ const cid = BigInt ( req . user ?. cid || 0 ) ;
265+
266+ const user = await prisma . user . findUnique ( {
267+ where : { cid } ,
268+ select : { settings : true } ,
269+ } ) ;
270+
271+ if ( ! user ) {
272+ res . status ( 404 ) . json ( { error : "User not found" } ) ;
273+ return ;
274+ }
275+
276+ res . json ( { settings : user . settings || { } } ) ;
277+ } ) ,
278+ ) ;
279+
280+ app . post (
281+ "/user/settings" ,
282+ authHandler ,
283+ errorHandler ( async ( req : AuthRequest , res ) => {
284+ const cid = BigInt ( req . user ?. cid || 0 ) ;
285+ const settings = req . body ;
286+
287+ if ( ! settings || typeof settings !== "object" ) {
288+ res . status ( 400 ) . json ( { error : "Invalid settings data" } ) ;
289+ return ;
290+ }
291+
292+ const user = await prisma . user . upsert ( {
293+ where : { cid } ,
294+ update : { settings } ,
295+ create : { cid, settings } ,
296+ } ) ;
297+
298+ res . json ( { settings : user . settings } ) ;
299+ } ) ,
300+ ) ;
301+
266302app . use ( ( _req , res ) => {
267303 res . status ( 404 ) . json ( { error : "Endpoint not found" } ) ;
268304} ) ;
0 commit comments