Spaces:
Sleeping
Sleeping
File size: 2,782 Bytes
57a889c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | 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).
*/
@Controller('api/integrations/airtrail')
@UseGuards(AirtrailAddonGuard, JwtAuthGuard)
export class AirtrailController {
@Get('settings')
getSettings(@CurrentUser() user: User) {
return getConnectionSettings(user.id);
}
@Put('settings')
async putSettings(
@CurrentUser() user: User,
@Body(new ZodValidationPipe(airtrailSettingsSchema)) body: AirtrailSettings,
@Req() 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 };
}
@Get('status')
getStatus(@CurrentUser() user: User) {
return getConnectionStatus(user.id);
}
@Get('flights')
async flights(@CurrentUser() 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. */
@Post('sync')
@HttpCode(200)
sync(@CurrentUser() user: User) {
return runAirtrailSyncForUser(user.id);
}
@Post('test')
@HttpCode(200)
test(
@CurrentUser() user: User,
@Body(new ZodValidationPipe(airtrailSettingsSchema)) body: AirtrailSettings,
) {
return testConnection(user.id, body.url, body.apiKey, !!body.allowInsecureTls);
}
}
|