diff --git a/src/app.ts b/src/app.ts index 6db82dc..014aad7 100644 --- a/src/app.ts +++ b/src/app.ts @@ -85,7 +85,6 @@ class App { this.app.use('/movies', moviesRouter); this.app.use('/theaters', theatersRouter); - } private errorHandler() { diff --git a/src/controllers/theaters/theaters.controller.ts b/src/controllers/theaters/theaters.controller.ts index 838f088..35c3e4e 100644 --- a/src/controllers/theaters/theaters.controller.ts +++ b/src/controllers/theaters/theaters.controller.ts @@ -66,4 +66,22 @@ export default class TheatersController implements BaseController { } } + public async getAvailableTheatersEscapeGame(res: Response): Promise { + try { + const data = await this.scrappingService.AvailableTheatersEscapeGame(); + return res.status(StatusCodes.OK).json(data); + + }catch(error) { + const e = error as Error; + + this.logger.warn('getTheatersNames'); + this.logger.warn(e.message); + + return res.status(StatusCodes.BAD_REQUEST).json({ + message: ReasonPhrases.BAD_REQUEST, + errors: e.message, + }) + } + } + } \ No newline at end of file diff --git a/src/docs/swagger-output.json b/src/docs/swagger-output.json index 3e59eca..899a852 100644 --- a/src/docs/swagger-output.json +++ b/src/docs/swagger-output.json @@ -39,6 +39,20 @@ } } }, + "/status": { + "get": { + "tags": [ + "/" + ], + "summary": "Redirect to the health status page", + "description": "", + "responses": { + "default": { + "description": "" + } + } + } + }, "/movies": { "get": { "tags": [ @@ -251,7 +265,7 @@ } } }, - "/movies/{theater}": { + "/movies/{theaterSlug}": { "get": { "tags": [ "Movies" @@ -260,7 +274,7 @@ "description": "Fetch all the available movies at a given theater", "parameters": [ { - "name": "theater", + "name": "theaterSlug", "in": "path", "required": true, "schema": { @@ -710,7 +724,7 @@ } }, { - "name": "theater", + "name": "theaterSlug", "in": "query", "schema": { "type": "string" @@ -1000,7 +1014,17 @@ } } }, - "/theaters/infos/{theater}": { + "/theaters/escape-game": { + "get": { + "description": "", + "responses": { + "default": { + "description": "" + } + } + } + }, + "/theaters/infos/{theaterSlug}": { "get": { "tags": [ "Theaters" @@ -1009,7 +1033,7 @@ "description": "Fetch informations about a specified theater giving his name", "parameters": [ { - "name": "theater", + "name": "theaterSlug", "in": "path", "required": true, "schema": { @@ -1431,6 +1455,5 @@ } } } - }, - "url": "http://51.91.76.77:3123" + } } \ No newline at end of file diff --git a/src/models/theater-escape-game.model.ts b/src/models/theater-escape-game.model.ts new file mode 100644 index 0000000..91968f3 --- /dev/null +++ b/src/models/theater-escape-game.model.ts @@ -0,0 +1,11 @@ +export default interface TheaterEscapeGameModel { + theaterName : string , + name: string, + img: string, + price: number, + groupSizeMin: number, + groupSizeMax: number, + difficulty: number, + description: string, + minAge: number, +} \ No newline at end of file diff --git a/src/routes/theaters.ts b/src/routes/theaters.ts index 2c66cd2..a985341 100644 --- a/src/routes/theaters.ts +++ b/src/routes/theaters.ts @@ -47,6 +47,18 @@ router.get( } ); +router.get('/escape-game', + + ExpressValidatorMiddleware, + + async function (req, res, _next) { + const response = theatersController.getAvailableTheatersEscapeGame(res); + return response; + } + +); + + router.get( '/infos/:theaterSlug', diff --git a/src/services/scapping/scrapping.servive.ts b/src/services/scapping/scrapping.servive.ts index 4130b9d..7f3336c 100644 --- a/src/services/scapping/scrapping.servive.ts +++ b/src/services/scapping/scrapping.servive.ts @@ -9,6 +9,7 @@ import TheaterInfosModel from "../../models/theater-info.model"; import TheaterNameModel from "@/models/theater-name.model"; import axios, { AxiosError, AxiosResponse } from "axios"; import * as cheerio from 'cheerio'; +import TheaterEscapeGameModel from "@/models/theater-escape-game.model"; export default class ScrappingService implements BaseService { @@ -431,6 +432,81 @@ export default class ScrappingService implements BaseService { return theaterInfos; } + public async escapeGameByTheaters() { + let response: AxiosResponse; + try { + response = await axios.get(infos.baseUrl); + } catch (error) { + + const e = error as AxiosError; + + this.logger.fatal('theatersNames'); + this.logger.fatal(e); + + throw Error(e.message); + } + + // escape game by theaters + + + } + + public async AvailableTheatersEscapeGame(): Promise { + let response: AxiosResponse; + try { + response = await axios.get(`${infos.baseUrl}/escape-game/`); + } catch (error) { + + const e = error as AxiosError; + + this.logger.fatal('theatersNames'); + this.logger.fatal(e); + + throw Error(e.message); + } + const theaterEscapeGame: TheaterEscapeGameModel[] = []; + const htmlRoot = cheerio.load(response.data); + + const avalaibleTheatherNames = htmlRoot("ul.theaters li").map((index, element) => htmlRoot(element).data("set") as String); + + avalaibleTheatherNames.each((_, theaterName) => { + + htmlRoot(`article[data-${theaterName}]`).each((index, element) => { + const name = htmlRoot(element).children("h1").text(); + + const e = htmlRoot(element).children(); + + const description = e.find(".info-bloc p").text(); + const difficulty = e.find("li.full").length; + const groupSizeMin = parseInt(e.find(".price").text().match(/Groupe de (\d+)/)?.[1] || "0"); + const groupSizeMax = parseInt(e.find(".price").text().match(/à (\d+) personnes/)?.[1] || "0"); + const price = parseInt(e.find(".price").text().match(/Tarif unique (\d+)/)?.[1] || "0") + const minAge = parseInt(e.find(".age-info").text().match(/\d+/)?.[0] || "0"); + const image = e.find("figure img").attr("src"); + + theaterEscapeGame.push( + { + theaterName: theaterName as string, + name: name, + img: image!, + price: price, + groupSizeMin: groupSizeMin, + groupSizeMax: groupSizeMax, + difficulty: difficulty, + description: description, + minAge: minAge, + } + ); + + }); + + + }); + + return theaterEscapeGame; + + } + } diff --git a/src/tests/api/theaters-route.test.ts b/src/tests/api/theaters-route.test.ts index 32ee21d..e838a77 100644 --- a/src/tests/api/theaters-route.test.ts +++ b/src/tests/api/theaters-route.test.ts @@ -4,7 +4,7 @@ import request from 'supertest'; describe('Testing theaters routes', () => { const reqApp = request(app); - + test('if /GET is working', async () => { const res = await reqApp.get('/'); @@ -27,8 +27,8 @@ describe('Testing theaters routes', () => { test('if /GET theaters/infos/ is working', async () => { const res = await reqApp.get('/theaters/infos/wologuede'); - - + + expect(res.statusCode).toBe(200); }); @@ -37,7 +37,7 @@ describe('Testing theaters routes', () => { test('if /GET theaters/infos/ with bad theater slug is not working', async () => { const res = await reqApp.get('/theaters/infos/123'); - + expect(res.statusCode).not.toBe(200); }); @@ -45,9 +45,9 @@ describe('Testing theaters routes', () => { test('if /GET theaters/infos/ with bad lang is not working', async () => { - const res = await reqApp.get('/theaters/infos/wologuede?lang=zk'); + const res = await reqApp.get('/theaters/infos/wologuede?lang=zk'); - expect(res.statusCode).not.toBe(200); + expect(res.statusCode).not.toBe(200); }); @@ -60,5 +60,12 @@ describe('Testing theaters routes', () => { }); + test('if /GET theaters/escap-game is working ', async () => { + + const res = await reqApp.get('/theaters/escape-game'); + + expect(res.statusCode).toBe(200); + }) + }) diff --git a/src/tests/services/scrapping.service.test.ts b/src/tests/services/scrapping.service.test.ts index 2f876e9..635fdaa 100644 --- a/src/tests/services/scrapping.service.test.ts +++ b/src/tests/services/scrapping.service.test.ts @@ -12,7 +12,7 @@ describe('Test on Scapping Service', () => { const names = await scrappingService.theatersNames(); expect(names.length).toBeGreaterThan(0); - + const name = names[0]; expect(name.country).toBeDefined(); expect(name.cities.length).toBeGreaterThan(0); @@ -25,7 +25,7 @@ describe('Test on Scapping Service', () => { return scrappingService.theaterMovies('wologuede').then((movies) => { expect(movies.length).toBeGreaterThan(0); - + }); }); @@ -70,7 +70,7 @@ describe('Test on Scapping Service', () => { test('if movieInfoBySlug is not working with bad slug', async () => { return scrappingService.movieInfoBySlug('zkk').then((info) => { - + expect(info).toBeNull(); }); @@ -174,11 +174,11 @@ describe('Test on Scapping Service', () => { expect(movies.length).toBeGreaterThan(0); const movie = movies[0]; - + expect(movie.title).not.toBeNull(); expect(movie.slug).toBeDefined(); expect(movie.img).toBeDefined(); - + }); }); @@ -190,13 +190,21 @@ describe('Test on Scapping Service', () => { expect(movies.length).toBeGreaterThan(0); - const movie = movies[0]; + const movie = movies[0]; expect(movie.title).not.toBeNull(); expect(movie.img).toBeDefined(); expect(movie.slug).toBeDefined(); - + }); }); + + + test("if available escape game theaters is wroking ", async () => { + return scrappingService.AvailableTheatersEscapeGame().then((theaterEscapeGame => { + expect(theaterEscapeGame.length).toBeGreaterThan(0); + }) + ); + }) })