Compare commits

...
Sign in to create a new pull request.

3 commits

4 changed files with 147 additions and 6 deletions

View file

@ -60,11 +60,15 @@ export class NtfyProvider implements OnApplicationBootstrap {
}
async sendBootstrappedNotification() {
const gitCommit = this.configService.get<string>('GIT_COMMIT')
const version =
this.configService.get<string>('GIT_COMMIT') ??
this.configService.get('LOCAL') === 'true'
? 'LOCAL'
: 'unknown'
await this.publishQueue.add(
...NtfyProvider.defaultJob({
title: 'Autobaan up and running',
message: `Version ${gitCommit}`,
message: `Version ${version}`,
tags: [MessageTags.badminton],
}),
)
@ -103,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,

View file

@ -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
}

View file

@ -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)
}

View file

@ -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 },
})),