Adding dayjs module to allow timezone handling by default and replaced node_module with this module
This commit is contained in:
parent
5653d98161
commit
09e4b3a1b8
11 changed files with 108 additions and 47 deletions
|
|
@ -8,7 +8,7 @@ services:
|
||||||
- 3306:3306
|
- 3306:3306
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
|
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
|
||||||
timeout: 20s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
|
||||||
http:
|
http:
|
||||||
|
|
|
||||||
20
src/common/dayjs.ts
Normal file
20
src/common/dayjs.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
|
||||||
|
import utc from 'dayjs/plugin/utc'
|
||||||
|
import timezone from 'dayjs/plugin/timezone'
|
||||||
|
import 'dayjs/locale/nl'
|
||||||
|
|
||||||
|
dayjs.extend(isSameOrBefore)
|
||||||
|
dayjs.extend(utc)
|
||||||
|
dayjs.extend(timezone)
|
||||||
|
dayjs.locale('nl')
|
||||||
|
|
||||||
|
dayjs.tz.setDefault('Europe/Amsterdam')
|
||||||
|
|
||||||
|
const dayjsTz = (
|
||||||
|
date?: string | number | Date | dayjs.Dayjs | null | undefined
|
||||||
|
) => {
|
||||||
|
return dayjs(date).tz()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default dayjsTz
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||
import dayjs from 'dayjs'
|
import dayjs from './dayjs'
|
||||||
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
|
|
||||||
import { hashPassword } from './password'
|
|
||||||
dayjs.extend(isSameOrBefore)
|
|
||||||
|
|
||||||
import { DateRange, Opponent, Reservation } from './reservation'
|
import { DateRange, Opponent, Reservation } from './reservation'
|
||||||
|
|
||||||
export enum ValidationErrorCode {
|
export enum ValidationErrorCode {
|
||||||
|
|
@ -61,9 +57,8 @@ const validateRequestBody = async (
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const hashedPassword = await hashPassword(password)
|
|
||||||
const reservation = new Reservation(
|
const reservation = new Reservation(
|
||||||
{ username, password: hashedPassword },
|
{ username, password },
|
||||||
convertDateRangeStringToObject(dateRange),
|
convertDateRangeStringToObject(dateRange),
|
||||||
opponent
|
opponent
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import dayjs, { Dayjs } from 'dayjs'
|
import { Dayjs } from 'dayjs'
|
||||||
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
|
import dayjs from './dayjs'
|
||||||
import { query } from './database'
|
import { query } from './database'
|
||||||
dayjs.extend(isSameOrBefore)
|
|
||||||
|
|
||||||
const RESERVATION_AVAILABLE_WITHIN_DAYS = 7
|
const RESERVATION_AVAILABLE_WITHIN_DAYS = 7
|
||||||
|
|
||||||
|
|
@ -16,8 +15,8 @@ export interface Opponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DateRange {
|
export interface DateRange {
|
||||||
start: dayjs.Dayjs
|
start: Dayjs
|
||||||
end: dayjs.Dayjs
|
end: Dayjs
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Reservation {
|
export class Reservation {
|
||||||
|
|
@ -81,7 +80,7 @@ export class Reservation {
|
||||||
return {
|
return {
|
||||||
user: {
|
user: {
|
||||||
username: this.user.username,
|
username: this.user.username,
|
||||||
password: this.user.password ? '?' : null,
|
password: this.user.password,
|
||||||
},
|
},
|
||||||
opponent: this.opponent,
|
opponent: this.opponent,
|
||||||
booked: this.booked,
|
booked: this.booked,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ import { Runner } from './runner'
|
||||||
let runner: Runner | undefined
|
let runner: Runner | undefined
|
||||||
const getRunner = () => {
|
const getRunner = () => {
|
||||||
if (!runner) {
|
if (!runner) {
|
||||||
runner = new Runner({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] })
|
runner = new Runner({
|
||||||
|
headless: true,
|
||||||
|
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return runner
|
return runner
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import dayjs, { Dayjs } from 'dayjs'
|
import { Dayjs } from 'dayjs'
|
||||||
|
import dayjs from './dayjs'
|
||||||
import puppeteer, {
|
import puppeteer, {
|
||||||
Browser,
|
Browser,
|
||||||
BrowserConnectOptions,
|
BrowserConnectOptions,
|
||||||
|
|
@ -36,7 +37,7 @@ export class Runner {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async login(username: string, password: string) {
|
private async login(username: string, password: string) {
|
||||||
asyncLocalStorage.getStore()?.debug('Logging in')
|
asyncLocalStorage.getStore()?.debug('Logging in', { username })
|
||||||
await this.page?.goto('https://squashcity.baanreserveren.nl/')
|
await this.page?.goto('https://squashcity.baanreserveren.nl/')
|
||||||
await this.page
|
await this.page
|
||||||
?.waitForSelector('input[name=username]')
|
?.waitForSelector('input[name=username]')
|
||||||
|
|
@ -53,10 +54,11 @@ export class Runner {
|
||||||
await this.confirmReservation()
|
await this.confirmReservation()
|
||||||
reservation.booked = true
|
reservation.booked = true
|
||||||
return true
|
return true
|
||||||
} catch (err) {
|
} catch (err: unknown) {
|
||||||
asyncLocalStorage
|
asyncLocalStorage.getStore()?.error('Error making reservation', {
|
||||||
.getStore()
|
reservation: reservation.format(),
|
||||||
?.error('Error making reservation', reservation.format())
|
error: err,
|
||||||
|
})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +84,12 @@ export class Runner {
|
||||||
asyncLocalStorage
|
asyncLocalStorage
|
||||||
.getStore()
|
.getStore()
|
||||||
?.debug('Date is on different page, increase month')
|
?.debug('Date is on different page, increase month')
|
||||||
await this.page?.waitForSelector('td.month.next').then((d) => d?.click())
|
await this.page
|
||||||
|
?.waitForSelector('td.month.next')
|
||||||
|
.then((d) => d?.click())
|
||||||
|
.catch(() => {
|
||||||
|
throw new Error('Could not click correct month')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.page
|
await this.page
|
||||||
|
|
@ -92,11 +99,18 @@ export class Runner {
|
||||||
)}`
|
)}`
|
||||||
)
|
)
|
||||||
.then((d) => d?.click())
|
.then((d) => d?.click())
|
||||||
await this.page?.waitForSelector(
|
.catch(() => {
|
||||||
`td#cal_${date.get('year')}_${date.get('month') + 1}_${date.get(
|
throw new Error('Could not click correct day')
|
||||||
'date'
|
})
|
||||||
)}.selected`
|
await this.page
|
||||||
)
|
?.waitForSelector(
|
||||||
|
`td#cal_${date.get('year')}_${date.get('month') + 1}_${date.get(
|
||||||
|
'date'
|
||||||
|
)}.selected`
|
||||||
|
)
|
||||||
|
.catch(() => {
|
||||||
|
throw new Error("Selected day didn't change")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private async selectAvailableTime(res: Reservation): Promise<void> {
|
private async selectAvailableTime(res: Reservation): Promise<void> {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import dayjs from 'dayjs'
|
import dayjs from '../common/dayjs'
|
||||||
import { Reservation } from '../common/reservation'
|
import { Reservation } from '../common/reservation'
|
||||||
import { Runner } from '../common/runner'
|
import { Runner } from '../common/runner'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,27 +9,35 @@ exports[`scheduler should handle valid requests outside of reservation window 1`
|
||||||
"end": {
|
"end": {
|
||||||
"$D": 16,
|
"$D": 16,
|
||||||
"$H": 1,
|
"$H": 1,
|
||||||
"$L": "en",
|
"$L": "nl",
|
||||||
"$M": 0,
|
"$M": 0,
|
||||||
"$W": 0,
|
"$W": 0,
|
||||||
"$d": {},
|
"$d": {},
|
||||||
"$m": 15,
|
"$m": 15,
|
||||||
"$ms": 0,
|
"$ms": 0,
|
||||||
|
"$offset": 60,
|
||||||
"$s": 0,
|
"$s": 0,
|
||||||
"$x": {},
|
"$u": false,
|
||||||
|
"$x": {
|
||||||
|
"$timezone": "Europe/Amsterdam",
|
||||||
|
},
|
||||||
"$y": 2022,
|
"$y": 2022,
|
||||||
},
|
},
|
||||||
"start": {
|
"start": {
|
||||||
"$D": 16,
|
"$D": 16,
|
||||||
"$H": 1,
|
"$H": 1,
|
||||||
"$L": "en",
|
"$L": "nl",
|
||||||
"$M": 0,
|
"$M": 0,
|
||||||
"$W": 0,
|
"$W": 0,
|
||||||
"$d": {},
|
"$d": {},
|
||||||
"$m": 0,
|
"$m": 0,
|
||||||
"$ms": 0,
|
"$ms": 0,
|
||||||
|
"$offset": 60,
|
||||||
"$s": 0,
|
"$s": 0,
|
||||||
"$x": {},
|
"$u": false,
|
||||||
|
"$x": {
|
||||||
|
"$timezone": "Europe/Amsterdam",
|
||||||
|
},
|
||||||
"$y": 2022,
|
"$y": 2022,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -41,27 +49,33 @@ exports[`scheduler should handle valid requests outside of reservation window 1`
|
||||||
{
|
{
|
||||||
"$D": 16,
|
"$D": 16,
|
||||||
"$H": 1,
|
"$H": 1,
|
||||||
"$L": "en",
|
"$L": "nl",
|
||||||
"$M": 0,
|
"$M": 0,
|
||||||
"$W": 0,
|
"$W": 0,
|
||||||
"$d": {},
|
"$d": {},
|
||||||
"$m": 0,
|
"$m": 0,
|
||||||
"$ms": 0,
|
"$ms": 0,
|
||||||
|
"$offset": 60,
|
||||||
"$s": 0,
|
"$s": 0,
|
||||||
"$x": {},
|
"$x": {
|
||||||
|
"$timezone": "Europe/Amsterdam",
|
||||||
|
},
|
||||||
"$y": 2022,
|
"$y": 2022,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$D": 16,
|
"$D": 16,
|
||||||
"$H": 1,
|
"$H": 1,
|
||||||
"$L": "en",
|
"$L": "nl",
|
||||||
"$M": 0,
|
"$M": 0,
|
||||||
"$W": 0,
|
"$W": 0,
|
||||||
"$d": {},
|
"$d": {},
|
||||||
"$m": 15,
|
"$m": 15,
|
||||||
"$ms": 0,
|
"$ms": 0,
|
||||||
|
"$offset": 60,
|
||||||
"$s": 0,
|
"$s": 0,
|
||||||
"$x": {},
|
"$x": {
|
||||||
|
"$timezone": "Europe/Amsterdam",
|
||||||
|
},
|
||||||
"$y": 2022,
|
"$y": 2022,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -73,14 +87,17 @@ exports[`scheduler should handle valid requests outside of reservation window 1`
|
||||||
"scheduledFor": {
|
"scheduledFor": {
|
||||||
"$D": 9,
|
"$D": 9,
|
||||||
"$H": 0,
|
"$H": 0,
|
||||||
"$L": "en",
|
"$L": "nl",
|
||||||
"$M": 0,
|
"$M": 0,
|
||||||
"$W": 0,
|
"$W": 0,
|
||||||
"$d": {},
|
"$d": {},
|
||||||
"$m": 0,
|
"$m": 0,
|
||||||
"$ms": 0,
|
"$ms": 0,
|
||||||
|
"$offset": 60,
|
||||||
"$s": 0,
|
"$s": 0,
|
||||||
"$x": {},
|
"$x": {
|
||||||
|
"$timezone": "Europe/Amsterdam",
|
||||||
|
},
|
||||||
"$y": 2022,
|
"$y": 2022,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -96,27 +113,35 @@ exports[`scheduler should handle valid requests within reservation window 1`] =
|
||||||
"end": {
|
"end": {
|
||||||
"$D": 1,
|
"$D": 1,
|
||||||
"$H": 1,
|
"$H": 1,
|
||||||
"$L": "en",
|
"$L": "nl",
|
||||||
"$M": 0,
|
"$M": 0,
|
||||||
"$W": 6,
|
"$W": 6,
|
||||||
"$d": {},
|
"$d": {},
|
||||||
"$m": 30,
|
"$m": 30,
|
||||||
"$ms": 0,
|
"$ms": 0,
|
||||||
|
"$offset": 60,
|
||||||
"$s": 0,
|
"$s": 0,
|
||||||
"$x": {},
|
"$u": false,
|
||||||
|
"$x": {
|
||||||
|
"$timezone": "Europe/Amsterdam",
|
||||||
|
},
|
||||||
"$y": 2022,
|
"$y": 2022,
|
||||||
},
|
},
|
||||||
"start": {
|
"start": {
|
||||||
"$D": 1,
|
"$D": 1,
|
||||||
"$H": 1,
|
"$H": 1,
|
||||||
"$L": "en",
|
"$L": "nl",
|
||||||
"$M": 0,
|
"$M": 0,
|
||||||
"$W": 6,
|
"$W": 6,
|
||||||
"$d": {},
|
"$d": {},
|
||||||
"$m": 15,
|
"$m": 15,
|
||||||
"$ms": 0,
|
"$ms": 0,
|
||||||
|
"$offset": 60,
|
||||||
"$s": 0,
|
"$s": 0,
|
||||||
"$x": {},
|
"$u": false,
|
||||||
|
"$x": {
|
||||||
|
"$timezone": "Europe/Amsterdam",
|
||||||
|
},
|
||||||
"$y": 2022,
|
"$y": 2022,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import dayjs from 'dayjs'
|
import dayjs from '../../../src/common/dayjs'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
validateJSONRequest,
|
validateJSONRequest,
|
||||||
|
|
@ -9,7 +9,7 @@ describe('request', () => {
|
||||||
const testDate = dayjs().add(1, 'day')
|
const testDate = dayjs().add(1, 'day')
|
||||||
|
|
||||||
describe('validateJSONRequest', () => {
|
describe('validateJSONRequest', () => {
|
||||||
test('should return ReservationRequest', () => {
|
test('should return ReservationRequest', async () => {
|
||||||
const body = {
|
const body = {
|
||||||
username: 'collin',
|
username: 'collin',
|
||||||
password: '123abc',
|
password: '123abc',
|
||||||
|
|
@ -23,7 +23,9 @@ describe('request', () => {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(() => validateJSONRequest(body)).not.toThrow()
|
const res = await validateJSONRequest(body)
|
||||||
|
expect(res).toBeDefined()
|
||||||
|
expect(res.dateRange.start.format()).toEqual(testDate.format())
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should throw error for undefined body', async () => {
|
test('should throw error for undefined body', async () => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import dayjs, { Dayjs } from 'dayjs'
|
import { Dayjs } from 'dayjs'
|
||||||
|
import dayjs from '../../../src/common/dayjs'
|
||||||
import { DateRange, Reservation } from '../../../src/common/reservation'
|
import { DateRange, Reservation } from '../../../src/common/reservation'
|
||||||
|
|
||||||
describe('Reservation', () => {
|
describe('Reservation', () => {
|
||||||
|
|
@ -20,6 +21,7 @@ describe('Reservation', () => {
|
||||||
|
|
||||||
expect(res.possibleDates).toHaveLength(5)
|
expect(res.possibleDates).toHaveLength(5)
|
||||||
|
|
||||||
|
console.log(res.possibleDates[0].format())
|
||||||
expect(res.possibleDates[0]).toEqual(startDate)
|
expect(res.possibleDates[0]).toEqual(startDate)
|
||||||
expect(res.possibleDates[1]).toEqual(startDate.add(15, 'minute'))
|
expect(res.possibleDates[1]).toEqual(startDate.add(15, 'minute'))
|
||||||
expect(res.possibleDates[2]).toEqual(startDate.add(30, 'minute'))
|
expect(res.possibleDates[2]).toEqual(startDate.add(30, 'minute'))
|
||||||
|
|
@ -45,6 +47,7 @@ describe('Reservation', () => {
|
||||||
|
|
||||||
const zeroTime = (date: Dayjs): Dayjs =>
|
const zeroTime = (date: Dayjs): Dayjs =>
|
||||||
date.hour(0).minute(0).second(0).millisecond(0)
|
date.hour(0).minute(0).second(0).millisecond(0)
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
{
|
{
|
||||||
date: dayjs().add(8, 'days'),
|
date: dayjs().add(8, 'days'),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import dayjs from 'dayjs'
|
import dayjs from '../../../src/common/dayjs'
|
||||||
import {
|
import {
|
||||||
ValidationError,
|
ValidationError,
|
||||||
ValidationErrorCode,
|
ValidationErrorCode,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue