Compare commits
3 commits
a85f743be4
...
f99550d879
| Author | SHA1 | Date | |
|---|---|---|---|
| f99550d879 | |||
|
|
bedd062aa0 | ||
| 736e1f4d39 |
4 changed files with 147 additions and 6 deletions
|
|
@ -60,11 +60,15 @@ export class NtfyProvider implements OnApplicationBootstrap {
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendBootstrappedNotification() {
|
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(
|
await this.publishQueue.add(
|
||||||
...NtfyProvider.defaultJob({
|
...NtfyProvider.defaultJob({
|
||||||
title: 'Autobaan up and running',
|
title: 'Autobaan up and running',
|
||||||
message: `Version ${gitCommit}`,
|
message: `Version ${version}`,
|
||||||
tags: [MessageTags.badminton],
|
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(
|
async sendErrorPerformingReservationNotification(
|
||||||
reservationId: string,
|
reservationId: string,
|
||||||
startTime: Dayjs,
|
startTime: Dayjs,
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ export enum MessageTags {
|
||||||
clock11 = 'clock11',
|
clock11 = 'clock11',
|
||||||
clock1130 = 'clock1130',
|
clock1130 = 'clock1130',
|
||||||
badminton = 'badminton',
|
badminton = 'badminton',
|
||||||
|
passport_control = 'passport_control',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MessagePriority {
|
export enum MessagePriority {
|
||||||
|
|
@ -59,13 +60,60 @@ export enum MessagePriority {
|
||||||
max = 5,
|
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 {
|
export interface MessageConfig {
|
||||||
topic: string
|
topic: string
|
||||||
message?: string
|
message?: string
|
||||||
title?: string
|
title?: string
|
||||||
tags?: MessageTags[]
|
tags?: MessageTags[]
|
||||||
priority?: MessagePriority
|
priority?: MessagePriority
|
||||||
actions?: object[]
|
actions?: MessageAction[]
|
||||||
markdown?: boolean
|
markdown?: boolean
|
||||||
icon?: string
|
icon?: string
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@ import { LoggerService } from '../logger/service.logger'
|
||||||
import { BaanReserverenService } from '../runner/baanreserveren/service'
|
import { BaanReserverenService } from '../runner/baanreserveren/service'
|
||||||
import { Reservation, ReservationStatus } from './entity'
|
import { Reservation, ReservationStatus } from './entity'
|
||||||
|
|
||||||
|
export enum ReservationDangerLevel {
|
||||||
|
Safe = 'safe',
|
||||||
|
Risky = 'risky',
|
||||||
|
Lethal = 'lethal',
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ReservationsService {
|
export class ReservationsService {
|
||||||
constructor(
|
constructor(
|
||||||
|
|
@ -93,6 +99,19 @@ export class ReservationsService {
|
||||||
return await this.reservationsRepository.save(res)
|
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>) {
|
async update(reservationId: string, update: Partial<Reservation>) {
|
||||||
return await this.reservationsRepository.update(reservationId, update)
|
return await this.reservationsRepository.update(reservationId, update)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,11 @@ import {
|
||||||
RESERVATIONS_QUEUE_NAME,
|
RESERVATIONS_QUEUE_NAME,
|
||||||
ReservationsQueue,
|
ReservationsQueue,
|
||||||
} from '../reservations/config'
|
} from '../reservations/config'
|
||||||
import { ReservationsService } from '../reservations/service'
|
import { Reservation } from '../reservations/entity'
|
||||||
|
import {
|
||||||
|
ReservationDangerLevel,
|
||||||
|
ReservationsService,
|
||||||
|
} from '../reservations/service'
|
||||||
import { WaitingListDetails } from './types'
|
import { WaitingListDetails } from './types'
|
||||||
|
|
||||||
const EMAIL_SUBJECT_REGEX = new RegExp(
|
const EMAIL_SUBJECT_REGEX = new RegExp(
|
||||||
|
|
@ -90,12 +94,45 @@ export class WaitingListService {
|
||||||
return
|
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(
|
this.loggerService.debug(
|
||||||
`Found ${reservations.length} reservations on waiting list`,
|
`Found the reservations in given categories: ${JSON.stringify(
|
||||||
|
partitioned,
|
||||||
|
)}`,
|
||||||
)
|
)
|
||||||
|
|
||||||
await this.reservationsQueue.addBulk(
|
await this.reservationsQueue.addBulk(
|
||||||
reservations.map((r) => ({
|
partitioned.safe.map((r) => ({
|
||||||
data: { reservation: r, speedyMode: false },
|
data: { reservation: r, speedyMode: false },
|
||||||
opts: { attempts: 1 },
|
opts: { attempts: 1 },
|
||||||
})),
|
})),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue