78 lines
1.7 KiB
TypeScript
78 lines
1.7 KiB
TypeScript
import { IsEmail, IsISO8601, IsOptional, IsString, Matches, MaxLength } from 'class-validator'
|
|
|
|
// IANA timezone sanity check (Area/Location, optionally a third segment). Not a
|
|
// full tz-database membership test — Luxon rejects unknown zones downstream.
|
|
const TZ = /^[A-Za-z]+\/[A-Za-z0-9_+-]+(\/[A-Za-z0-9_+-]+)?$/
|
|
|
|
export class SlotsQueryDto {
|
|
@IsISO8601()
|
|
from!: string
|
|
|
|
@IsISO8601()
|
|
to!: string
|
|
|
|
@IsString()
|
|
@MaxLength(64)
|
|
@Matches(TZ, { message: 'timezone must be an IANA zone like Europe/Copenhagen' })
|
|
timezone!: string
|
|
}
|
|
|
|
export class CreateHoldDto {
|
|
@IsISO8601()
|
|
startUtc!: string
|
|
|
|
// Optional captcha token (e.g. Cloudflare Turnstile). Enforced server-side
|
|
// only when a captcha provider is configured; ignored otherwise.
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(4096)
|
|
captchaToken?: string
|
|
}
|
|
|
|
export class CreateBookingDto {
|
|
@IsISO8601()
|
|
startUtc!: string
|
|
|
|
@IsString()
|
|
@MaxLength(120)
|
|
attendeeName!: string
|
|
|
|
@IsEmail()
|
|
@MaxLength(254)
|
|
attendeeEmail!: string
|
|
|
|
@IsString()
|
|
@MaxLength(64)
|
|
@Matches(TZ, { message: 'attendeeTimezone must be an IANA zone like Europe/Copenhagen' })
|
|
attendeeTimezone!: string
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(2000)
|
|
attendeeNotes?: string
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(64)
|
|
holdId?: string
|
|
|
|
// Optional captcha token (e.g. Cloudflare Turnstile). Enforced server-side
|
|
// only when a captcha provider is configured; ignored otherwise.
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(4096)
|
|
captchaToken?: string
|
|
}
|
|
|
|
export class CancelBookingDto {
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
reason?: string
|
|
}
|
|
|
|
export class RescheduleBookingDto {
|
|
@IsISO8601()
|
|
startUtc!: string
|
|
}
|