refactor(trips): the trip span check and the feed token strip move into trips helpers

This commit is contained in:
Maurice
2026-10-12 21:13:57 +00:00
parent 7454c8f95f
commit f470ae029d
3 changed files with 73 additions and 30 deletions
+35
View File
@@ -0,0 +1,35 @@
import { ValidationError } from '../common/domain-errors';
import { MAX_TRIP_DAYS, tripSpanDays } from '@trek/shared';
/**
* Pure helpers of the trips domain, moved out of trips.service.ts. Nothing
* here touches the DB, so they stay plain exports rather than methods on
* TripsService.
*/
/**
* The date range is refused, not cut short: generateDays used to clip the day
* rows at the limit while the trip kept its full end date, so everything past
* the cut-off had dates but no day to go on (#2403). An inverted range is
* refused here as well, because a start date moved past the stored end date
* arrives on its own and would otherwise empty the trip.
*/
export function assertTripSpan(startDate: string, endDate: string) {
const span = tripSpanDays(startDate, endDate);
if (span < 1) throw new ValidationError('End date must be after start date');
if (span > MAX_TRIP_DAYS) throw new ValidationError(`A trip can span at most ${MAX_TRIP_DAYS} days`);
}
/**
* Strips `feed_token` from a trip row on its way out.
*
* The column is the sole credential for the anonymous /api/feed/trip/:token.ics
* route, and `SELECT t.*` hands it to every reader of the trip. Gating the
* token endpoint on `share_manage` means nothing while any member can read the
* same value out of the trip payload, so the two go together. No TREK client
* reads the field (it is absent from client/ and shared/ entirely).
*/
export function withoutFeedToken<T>(row: T): T {
if (row && typeof row === 'object') delete (row as { feed_token?: unknown }).feed_token;
return row;
}
+4 -30
View File
@@ -27,11 +27,9 @@ import { Tours } from '../../db/entities/Tours.entity';
import { TourWaypoints } from '../../db/entities/TourWaypoints.entity';
import type { TourWaypointRow } from '../../db/repositories/TourWaypoints.repository';
import {
MAX_TRIP_DAYS,
addIsoDays,
planDayGrid,
resolveDayGridRange,
tripSpanDays,
type ActiveTrip,
type DayGridPlan,
type DayGridRemoval,
@@ -53,34 +51,7 @@ import { NotFoundError, ValidationError } from '../common/domain-errors';
import { UnitOfWork } from '../database/unit-of-work';
import { legacyBoundIntegerText } from '../common/row-id';
import { appClock } from '../common/timezoneService';
/**
* The date range is refused, not cut short: generateDays used to clip the day
* rows at the limit while the trip kept its full end date, so everything past
* the cut-off had dates but no day to go on (#2403). An inverted range is
* refused here as well, because a start date moved past the stored end date
* arrives on its own and would otherwise empty the trip.
*/
function assertTripSpan(startDate: string, endDate: string) {
const span = tripSpanDays(startDate, endDate);
if (span < 1) throw new ValidationError('End date must be after start date');
if (span > MAX_TRIP_DAYS) throw new ValidationError(`A trip can span at most ${MAX_TRIP_DAYS} days`);
}
/**
* Strips `feed_token` from a trip row on its way out.
*
* The column is the sole credential for the anonymous /api/feed/trip/:token.ics
* route, and `SELECT t.*` hands it to every reader of the trip. Gating the
* token endpoint on `share_manage` means nothing while any member can read the
* same value out of the trip payload, so the two go together. No TREK client
* reads the field (it is absent from client/ and shared/ entirely).
*/
export function withoutFeedToken<T>(row: T): T {
if (row && typeof row === 'object') delete (row as Record<string, unknown>).feed_token;
return row;
}
import { assertTripSpan } from './trips.helpers';
interface CreateTripData {
title: string;
@@ -1003,3 +974,6 @@ export class TripsService {
// trip aggregate; re-exported here because nine files already import them from
// this module.
export { NotFoundError, ValidationError };
// Lives in trips.helpers.ts; re-exported for the importers that read it from here.
export { withoutFeedToken } from './trips.helpers';