Compare commits
3 commits
main
...
safe_waiti
| Author | SHA1 | Date | |
|---|---|---|---|
| f99550d879 | |||
|
|
bedd062aa0 | ||
| 736e1f4d39 |
5 changed files with 142 additions and 5 deletions
|
|
@ -41,7 +41,7 @@ export class NtfyClient {
|
|||
throw new Error(`${response.status} - ${response.statusText}`)
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
this.loggerService.error('ntfy client failed', { error: error instanceof Error ? error.message : JSON.stringify(error) })
|
||||
this.loggerService.error('ntfy client failed', { error })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,6 +107,39 @@ export class NtfyProvider implements OnApplicationBootstrap {
|
|||
)
|
||||
}
|
||||
|
||||
async sendPerformingRiskyReservationNotification(
|
||||
reservationId: string,
|
||||
startTime: Dayjs,
|
||||
endTime: Dayjs,
|
||||
) {
|
||||
const url = `${this.configService.get(
|
||||
'BASE_URL',
|
||||
)}/reservations/${reservationId}`
|
||||
await this.publishQueue.add(
|
||||
...NtfyProvider.defaultJob({
|
||||
title: 'Handling risky reservation. Waiting for confirmation',
|
||||
message: `Waiting for ${reservationId} - ${startTime.format()} to ${endTime.format()}`,
|
||||
actions: [
|
||||
{
|
||||
action: 'http',
|
||||
label: 'Accept',
|
||||
url: `${url}/resume`,
|
||||
method: 'POST',
|
||||
clear: true,
|
||||
},
|
||||
{
|
||||
action: 'http',
|
||||
label: 'Reject',
|
||||
url,
|
||||
method: 'DELETE',
|
||||
clear: true,
|
||||
},
|
||||
],
|
||||
tags: [MessageTags.warning, MessageTags.passport_control],
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
async sendErrorPerformingReservationNotification(
|
||||
reservationId: string,
|
||||
startTime: Dayjs,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export enum MessageTags {
|
|||
clock11 = 'clock11',
|
||||
clock1130 = 'clock1130',
|
||||
badminton = 'badminton',
|
||||
passport_control = 'passport_control',
|
||||
}
|
||||
|
||||
export enum MessagePriority {
|
||||
|
|
@ -59,13 +60,60 @@ export enum MessagePriority {
|
|||
max = 5,
|
||||
}
|
||||
|
||||
type MessageActionType = 'broadcast' | 'copy' | 'http' | 'view'
|
||||
|
||||
export interface MessageActionConfig {
|
||||
action: MessageActionType
|
||||
/**
|
||||
* Label displayed on the action button
|
||||
*/
|
||||
label: string
|
||||
/**
|
||||
* Clear notification after action button is tapped
|
||||
*/
|
||||
clear?: boolean
|
||||
}
|
||||
|
||||
export interface BroadcastActionConfig extends MessageActionConfig {
|
||||
action: 'broadcast'
|
||||
intent?: string
|
||||
extras?: Record<string, string>
|
||||
}
|
||||
|
||||
export interface CopyActionConfig extends MessageActionConfig {
|
||||
action: 'copy'
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface HttpActionConfig extends MessageActionConfig {
|
||||
action: 'http'
|
||||
url: string
|
||||
/**
|
||||
* @default 'POST'
|
||||
*/
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' // there are more but if I use them I'll have gone insane
|
||||
headers?: Record<string, string>
|
||||
body?: string
|
||||
}
|
||||
export interface ViewActionConfig extends MessageActionConfig {
|
||||
action: 'view'
|
||||
url: string
|
||||
clear?: boolean
|
||||
}
|
||||
|
||||
export type MessageAction =
|
||||
| BroadcastActionConfig
|
||||
| CopyActionConfig
|
||||
| HttpActionConfig
|
||||
| ViewActionConfig
|
||||
|
||||
export interface MessageConfig {
|
||||
topic: string
|
||||
message?: string
|
||||
title?: string
|
||||
tags?: MessageTags[]
|
||||
priority?: MessagePriority
|
||||
actions?: object[]
|
||||
actions?: MessageAction[]
|
||||
markdown?: boolean
|
||||
icon?: string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ import { LoggerService } from '../logger/service.logger'
|
|||
import { BaanReserverenService } from '../runner/baanreserveren/service'
|
||||
import { Reservation, ReservationStatus } from './entity'
|
||||
|
||||
export enum ReservationDangerLevel {
|
||||
Safe = 'safe',
|
||||
Risky = 'risky',
|
||||
Lethal = 'lethal',
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ReservationsService {
|
||||
constructor(
|
||||
|
|
@ -93,6 +99,19 @@ export class ReservationsService {
|
|||
return await this.reservationsRepository.save(res)
|
||||
}
|
||||
|
||||
getDangerLevel(reservation: Reservation) {
|
||||
// don't book something within the ~~danger zone~~
|
||||
const now = dayjs()
|
||||
const hourDiff = now.diff(reservation.dateRangeStart, 'hours')
|
||||
if (hourDiff > 8) {
|
||||
return ReservationDangerLevel.Safe
|
||||
} else if (hourDiff >= 5) {
|
||||
return ReservationDangerLevel.Risky
|
||||
} else {
|
||||
return ReservationDangerLevel.Lethal
|
||||
}
|
||||
}
|
||||
|
||||
async update(reservationId: string, update: Partial<Reservation>) {
|
||||
return await this.reservationsRepository.update(reservationId, update)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,11 @@ import {
|
|||
RESERVATIONS_QUEUE_NAME,
|
||||
ReservationsQueue,
|
||||
} from '../reservations/config'
|
||||
import { ReservationsService } from '../reservations/service'
|
||||
import { Reservation } from '../reservations/entity'
|
||||
import {
|
||||
ReservationDangerLevel,
|
||||
ReservationsService,
|
||||
} from '../reservations/service'
|
||||
import { WaitingListDetails } from './types'
|
||||
|
||||
const EMAIL_SUBJECT_REGEX = new RegExp(
|
||||
|
|
@ -90,12 +94,45 @@ export class WaitingListService {
|
|||
return
|
||||
}
|
||||
|
||||
// don't book something within the ~~danger zone~~
|
||||
const partitioned = reservations.reduce<{
|
||||
safe: Reservation[]
|
||||
risky: Reservation[]
|
||||
lethal: Reservation[]
|
||||
}>(
|
||||
(acc, res) => {
|
||||
switch (this.reservationsService.getDangerLevel(res)) {
|
||||
case ReservationDangerLevel.Safe:
|
||||
return {
|
||||
safe: [...acc.safe, res],
|
||||
risky: acc.risky,
|
||||
lethal: acc.lethal,
|
||||
}
|
||||
case ReservationDangerLevel.Risky:
|
||||
return {
|
||||
safe: acc.safe,
|
||||
risky: [...acc.risky, res],
|
||||
lethal: acc.lethal,
|
||||
}
|
||||
case ReservationDangerLevel.Lethal:
|
||||
return {
|
||||
safe: acc.safe,
|
||||
risky: acc.risky,
|
||||
lethal: [...acc.lethal, res],
|
||||
}
|
||||
}
|
||||
},
|
||||
{ safe: [], risky: [], lethal: [] },
|
||||
)
|
||||
|
||||
this.loggerService.debug(
|
||||
`Found ${reservations.length} reservations on waiting list`,
|
||||
`Found the reservations in given categories: ${JSON.stringify(
|
||||
partitioned,
|
||||
)}`,
|
||||
)
|
||||
|
||||
await this.reservationsQueue.addBulk(
|
||||
reservations.map((r) => ({
|
||||
partitioned.safe.map((r) => ({
|
||||
data: { reservation: r, speedyMode: false },
|
||||
opts: { attempts: 1 },
|
||||
})),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue