From 1abaa934b06f914a085faf67234ce5dee5d104d5 Mon Sep 17 00:00:00 2001 From: Collin Duncan <3679940+cgduncan7@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:19:01 +0200 Subject: [PATCH] Adding proxy to find members --- src/app.module.ts | 2 + src/members/controller.ts | 17 ++++++ src/members/module.ts | 13 +++++ src/members/service.ts | 105 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 src/members/controller.ts create mode 100644 src/members/module.ts create mode 100644 src/members/service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 5b678ee..69545ab 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -9,6 +9,7 @@ import { EmailModule } from './email/module' import { LoggerMiddleware } from './logger/middleware' import { LoggerModule } from './logger/module' import { DatabaseLoggerService } from './logger/service.database_logger' +import { MembersModule } from './members/module' import { NtfyModule } from './ntfy/module' import { RecurringReservationsModule } from './recurringReservations/module' import { ReservationsModule } from './reservations/module' @@ -55,6 +56,7 @@ import { WaitingListModule } from './waitingList/module' RunnerModule, LoggerModule, EmailModule, + MembersModule, WaitingListModule, NtfyModule, ], diff --git a/src/members/controller.ts b/src/members/controller.ts new file mode 100644 index 0000000..d7086b7 --- /dev/null +++ b/src/members/controller.ts @@ -0,0 +1,17 @@ +import { Controller, Get, Inject, Query } from '@nestjs/common' + +import { MembersService } from './service' + +@Controller('members') +export class MembersController { + constructor( + @Inject(MembersService) + private readonly membersService: MembersService, + ) {} + + @Get() + async getMembers(@Query('name') name?: string) { + if (name == null || name.length == 0) return [] + return await this.membersService.findMembers(name) + } +} diff --git a/src/members/module.ts b/src/members/module.ts new file mode 100644 index 0000000..6746d33 --- /dev/null +++ b/src/members/module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common' +import { ConfigModule } from '@nestjs/config' + +import { LoggerModule } from '../logger/module' +import { MembersController } from './controller' +import { MembersService } from './service' + +@Module({ + imports: [LoggerModule, ConfigModule], + providers: [MembersService], + controllers: [MembersController], +}) +export class MembersModule {} diff --git a/src/members/service.ts b/src/members/service.ts new file mode 100644 index 0000000..608d323 --- /dev/null +++ b/src/members/service.ts @@ -0,0 +1,105 @@ +import { Inject, Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import { Axios } from 'axios' +import { stringify } from 'querystring' + +import { LoggerService } from '../logger/service.logger' + +export class Member { + id: string + name: string + + constructor(id: number, name: string) { + this.id = `${id}` + this.name = name + } +} + +interface MembersResponse { + members: [number, string][] + count: number + max: number + total: number + queries: unknown[] +} + +@Injectable() +export class MembersService { + private readonly membersClient: Axios + private sessionCookie: string + constructor( + @Inject(LoggerService) + private readonly loggerService: LoggerService, + + @Inject(ConfigService) + private readonly configService: ConfigService, + ) { + this.sessionCookie = this.generateSessionCookie() + this.membersClient = new Axios({ + baseURL: 'https://squashcity.baanreserveren.nl/', + headers: { + Accept: 'application/json', + Cookie: this.sessionCookie, + }, + }) + } + + private generateSessionCookie(): string { + const length = 26 + const acceptedChars = 'abcdefghijklmnopqrstuvwxyz0123456789' + let sessionCookie = `PHPSESSID=` + for (let i = 0; i < length; i++) { + sessionCookie += + acceptedChars[Math.floor(Math.random() * acceptedChars.length)] + } + return sessionCookie + } + + private sanitizeName(name: string): string { + const memberIdRegex = /\(P[0-9]+\)/ + return name.replace(memberIdRegex, '').trim() + } + + private async login(): Promise { + const username = this.configService.getOrThrow( + 'BAANRESERVEREN_USERNAME', + ) + const password = this.configService.getOrThrow( + 'BAANRESERVEREN_PASSWORD', + ) + + await this.membersClient.post( + '/auth/login', + stringify({ username, password }), + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }, + ) + } + + async findMembers(query: string, redirected = false): Promise { + this.loggerService.debug('Finding members', { query }) + const response = await this.membersClient.get( + '/members/find/ajax', + { + headers: { + Accept: 'text/html', + }, + params: { query }, + maxRedirects: 0, + }, + ) + if (!redirected && response.status >= 300 && response.status < 400) { + this.loggerService.log('Not logged in, logging in and re-requesting') + await this.login() + return await this.findMembers(query, true) + } + const jsonData: MembersResponse = JSON.parse(response.data) + this.loggerService.debug('Found members', { ...jsonData }) + return jsonData.members.map( + ([id, name]) => new Member(id, this.sanitizeName(name)), + ) + } +}