mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
83 lines
3.9 KiB
TypeScript
83 lines
3.9 KiB
TypeScript
import { Body, Controller, Delete, Query, Get, Headers, Param, Post, Put, UseGuards } from '@nestjs/common';
|
|
import type { User } from '../../types';
|
|
import { AccommodationsService, type StayInput } from './accommodations.service';
|
|
import { AccommodationCreateDto, AccommodationUpdateDto } from './accommodations.dto';
|
|
import { JwtAuthGuard } from '../auth-core/jwt-auth.guard';
|
|
import { CurrentUser } from '../auth-core/current-user.decorator';
|
|
import { RequirePermission, TripAccessGuard } from '../permissions/trip-access.guard';
|
|
|
|
/**
|
|
* /api/trips/:tripId/accommodations — trip-scoped lodging blocks.
|
|
*
|
|
* Byte-identical to the legacy accommodations sub-router (server/src/routes/
|
|
* days.ts): trip access (404 "Trip not found"), the 'day_edit' permission on
|
|
* mutations (403), the bespoke 400 (missing refs) and 404 (validateRefs / not
|
|
* found) bodies, create 201 / rest 200, and the cascade broadcasts (a created
|
|
* accommodation also emits reservation:created; a delete emits the linked
|
|
* reservation/budget deletions) with the forwarded X-Socket-Id.
|
|
*
|
|
* A booking also writes the day stop that puts it on the route. What that did to
|
|
* the day plan goes to every socket, the sender's included, and the answers
|
|
* carry the stop alongside the existing fields as well, for a session whose
|
|
* socket is down at that moment.
|
|
*
|
|
* The handlers are adapters: the whole write, its checks and its events live in
|
|
* AccommodationsService's stay use cases, which the MCP tools call as well.
|
|
*/
|
|
@Controller('api/trips/:tripId/accommodations')
|
|
// TripAccessGuard resolves :tripId and 404s a trip the user cannot reach; mutations
|
|
// add @RequirePermission('day_edit'), the same action string the service's canEdit
|
|
// passes, so the HTTP and MCP paths cannot demand different rights.
|
|
@UseGuards(JwtAuthGuard, TripAccessGuard)
|
|
export class AccommodationsController {
|
|
constructor(private readonly accommodations: AccommodationsService) {}
|
|
|
|
@Get()
|
|
async list(@CurrentUser() user: User, @Param('tripId') tripId: string) {
|
|
return { accommodations: await this.accommodations.list(tripId) };
|
|
}
|
|
|
|
@RequirePermission('day_edit')
|
|
@Post()
|
|
async create(
|
|
@CurrentUser() user: User,
|
|
@Param('tripId') tripId: string,
|
|
@Body() rawBody: AccommodationCreateDto,
|
|
@Headers('x-socket-id') socketId?: string,
|
|
) {
|
|
const { accommodation, mirror } = await this.accommodations.createStay(tripId, rawBody as StayInput, this.accommodations.restWriter(tripId, user, socketId));
|
|
// The stop rides in the answer as well, for the session that booked the night
|
|
// with its socket down: over the socket it would already have it.
|
|
return { accommodation, assignment: mirror.created };
|
|
}
|
|
|
|
@RequirePermission('day_edit')
|
|
@Put(':id')
|
|
async update(
|
|
@CurrentUser() user: User,
|
|
@Param('tripId') tripId: string,
|
|
@Param('id') id: string,
|
|
@Body() rawBody: AccommodationUpdateDto,
|
|
@Headers('x-socket-id') socketId?: string,
|
|
) {
|
|
const { accommodation, mirror } = await this.accommodations.updateStay(tripId, id, rawBody as StayInput, this.accommodations.restWriter(tripId, user, socketId));
|
|
return { accommodation, assignment: mirror.created, movedAssignment: mirror.moved, removedAssignments: mirror.removed };
|
|
}
|
|
|
|
@RequirePermission('day_edit')
|
|
@Delete(':id')
|
|
async remove(
|
|
@CurrentUser() user: User,
|
|
@Param('tripId') tripId: string,
|
|
@Param('id') id: string,
|
|
@Headers('x-socket-id') socketId?: string,
|
|
@Query('keepStop') keepStop?: string,
|
|
) {
|
|
// Turning a night back into a pause in road trip mode: the booking goes, the
|
|
// stop stays and becomes the traveller's. Everywhere else a cancelled booking
|
|
// takes the stop it brought with it.
|
|
const { mirror } = await this.accommodations.deleteStay(tripId, id, this.accommodations.restWriter(tripId, user, socketId), { keepStop: keepStop === 'true' });
|
|
return { success: true, removedAssignments: mirror.removed, updatedAssignments: mirror.updated };
|
|
}
|
|
}
|