Spaces:
Sleeping
Sleeping
| import { Body, Controller, Get, HttpCode, HttpException, Post, Put, Req, UseGuards } from '@nestjs/common'; | |
| import type { Request } from 'express'; | |
| import type { User } from '../../types'; | |
| import { JwtAuthGuard } from '../auth/jwt-auth.guard'; | |
| import { CurrentUser } from '../auth/current-user.decorator'; | |
| import { ZodValidationPipe } from '../common/zod-validation.pipe'; | |
| import { AirtrailAddonGuard } from './airtrail-addon.guard'; | |
| import { getClientIp } from '../../services/auditLog'; | |
| import { airtrailSettingsSchema, type AirtrailSettings } from '@trek/shared'; | |
| import { | |
| getConnectionSettings, | |
| getConnectionStatus, | |
| getFlightsForPicker, | |
| saveSettings, | |
| testConnection, | |
| } from '../../services/airtrail/airtrailService'; | |
| import { runAirtrailSyncForUser } from '../../services/airtrail/airtrailSync'; | |
| /** | |
| * /api/integrations/airtrail — per-user AirTrail connection (#214). | |
| * | |
| * `status` and `test` answer 200 even on failure (the service shapes | |
| * `{ connected: false, error }`); `settings` PUT validates with a 400. The API | |
| * key is never echoed — `getSettings` returns it masked. The route group is | |
| * gated on the `airtrail` addon (404 when disabled). | |
| */ | |
| ('api/integrations/airtrail') | |
| (AirtrailAddonGuard, JwtAuthGuard) | |
| export class AirtrailController { | |
| ('settings') | |
| getSettings(() user: User) { | |
| return getConnectionSettings(user.id); | |
| } | |
| ('settings') | |
| async putSettings( | |
| () user: User, | |
| (new ZodValidationPipe(airtrailSettingsSchema)) body: AirtrailSettings, | |
| () req: Request, | |
| ) { | |
| const result = await saveSettings( | |
| user.id, | |
| body.url, | |
| body.apiKey, | |
| !!body.allowInsecureTls, | |
| getClientIp(req), | |
| ); | |
| if (!result.success) { | |
| throw new HttpException({ error: result.error }, 400); | |
| } | |
| return result.warning ? { success: true, warning: result.warning } : { success: true }; | |
| } | |
| ('status') | |
| getStatus(() user: User) { | |
| return getConnectionStatus(user.id); | |
| } | |
| ('flights') | |
| async flights(() user: User) { | |
| try { | |
| return { flights: await getFlightsForPicker(user.id) }; | |
| } catch (err: any) { | |
| throw new HttpException({ error: err?.message || 'Could not load AirTrail flights' }, err?.status === 400 ? 400 : 502); | |
| } | |
| } | |
| /** Pull this user's AirTrail edits into their linked reservations on demand. */ | |
| ('sync') | |
| (200) | |
| sync(() user: User) { | |
| return runAirtrailSyncForUser(user.id); | |
| } | |
| ('test') | |
| (200) | |
| test( | |
| () user: User, | |
| (new ZodValidationPipe(airtrailSettingsSchema)) body: AirtrailSettings, | |
| ) { | |
| return testConnection(user.id, body.url, body.apiKey, !!body.allowInsecureTls); | |
| } | |
| } | |