diff --git a/requirements.txt b/requirements.txt index 79c2127..55ff0ee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,14 @@ aiosmtplib==2.0.2 annotated-types==0.6.0 anyio==3.7.1 +beautifulsoup4==4.12.2 +bs4==0.0.1 astroid==3.0.1 bcrypt==4.0.1 blinker==1.6.3 certifi==2023.7.22 cffi==1.16.0 -charset-normalizer==3.3.0 +charset-normalizer==3.3.2 click==8.1.7 coverage==7.3.2 cryptography==41.0.4 @@ -59,12 +61,15 @@ requests==2.31.0 rsa==4.9 six==1.16.0 sniffio==1.3.0 +soupsieve==2.5 SQLAlchemy==2.0.22 starlette==0.27.0 testcontainers==3.7.1 tomlkit==0.12.2 typing_extensions==4.8.0 -urllib3==2.0.7 +ujson==5.8.0 +Unidecode==1.3.7 +urllib3==2.1.0 uvicorn==0.23.2 watchfiles==0.21.0 websocket-client==1.6.4 diff --git a/src/constants/errorMessages.py b/src/constants/errorMessages.py index e733a3f..82c34a6 100644 --- a/src/constants/errorMessages.py +++ b/src/constants/errorMessages.py @@ -1,3 +1,5 @@ +INVALID_SCHEDULE_DAY = "INVALID SCHEDULE DAY" +ERROR_RETRIEVING_SCHEDULE = "ERROR RETRIEVING SCHEDULE" USER_ID_REQUIRED = "USER ID FIELD REQUIRED" VIDEO_ID_REQUIRED = "VIDEO ID FIELD REQUIRED" CONTENT_REQUIRED = "CONTENT FIELD REQUIRED" diff --git a/src/controller/scheduleController.py b/src/controller/scheduleController.py new file mode 100644 index 0000000..9a955a0 --- /dev/null +++ b/src/controller/scheduleController.py @@ -0,0 +1,55 @@ +import requests +from typing import Optional +from fastapi import APIRouter +from bs4 import BeautifulSoup +from unidecode import unidecode +from starlette.responses import JSONResponse + +from utils import enumeration +from constants import errorMessages + +schedule = APIRouter( + prefix="/schedule" +) + +@schedule.get("/") +async def get_schedule_day(day: Optional[str] = None): + if day: + day = unidecode(day).upper() + if not enumeration.ScheduleDaysEnum.has_value(day): + return JSONResponse(status_code=400, content={ "detail": errorMessages.INVALID_SCHEDULE_DAY }) + + try: + re = requests.get('https://unbtv.unb.br/grade') + html = re.text + + soup = BeautifulSoup(html, 'html.parser') + tables = soup.find_all("table") + + schedule_data = {} + current_day = None + + for table in tables: + for row in table.find_all("tr"): + if len(row.find_all("td")) == 1: + cell = row.find_all("td")[0] + schedule_day = unidecode(cell.text.replace("-FEIRA", "")) + + if day: + if current_day: + return schedule_data + if day == schedule_day: + current_day = schedule_day + schedule_data[schedule_day] = [] + else: + current_day = schedule_day + schedule_data[schedule_day] = [] + else: + if current_day: + day_schedule = [item.text for item in row.find_all("td")[:2]] + if (day_schedule[0].strip() != "" and day_schedule[1].strip() != ""): + schedule_data[current_day].append({ "time": day_schedule[0], "activity": day_schedule[1] }) + + return schedule_data + except: + return JSONResponse(status_code=400, content={ "error": errorMessages.ERROR_RETRIEVING_SCHEDULE }) diff --git a/src/main.py b/src/main.py index 09e708d..98c0647 100644 --- a/src/main.py +++ b/src/main.py @@ -5,7 +5,7 @@ load_dotenv() -from controller import commentController +from controller import commentController, scheduleController from database import SessionLocal, engine from model import commentModel @@ -23,13 +23,13 @@ allow_headers=["*"], ) +app.include_router(prefix="/api", router=commentController.comment) +app.include_router(prefix="/api", router=scheduleController.schedule) + @app.get("/") async def root(): return {"message": "Hello from Video Service"} - -app.include_router(prefix="/api", router=commentController.comment) - if __name__ == '__main__': # pragma: no cover port = 8001 if (len(sys.argv) == 2): diff --git a/src/utils/enumeration.py b/src/utils/enumeration.py new file mode 100644 index 0000000..30ac49a --- /dev/null +++ b/src/utils/enumeration.py @@ -0,0 +1,14 @@ +from enum import Enum + +class ScheduleDaysEnum(Enum): + SEGUNDA = "SEGUNDA" + TERCA = "TERCA" + QUARTA = "QUARTA" + QUINTA = "QUINTA" + SEXTA = "SEXTA" + SABADO = "SABADO" + DOMINGO = "DOMINGO" + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_schedule.py b/tests/test_schedule.py new file mode 100644 index 0000000..e45753b --- /dev/null +++ b/tests/test_schedule.py @@ -0,0 +1,29 @@ +import pytest +from fastapi.testclient import TestClient + +from src.main import app +from src.constants import errorMessages + +client = TestClient(app) + +class TestSchedule: + def test_schedule_get_schedule_day(self): + response = client.get("/api/schedule/") + data = response.json() + assert response.status_code == 200 + assert len(list(data.keys())) == 7 + assert all([a == b for a, b in zip(list(data.keys()), ['SEGUNDA', 'TERCA', 'QUARTA', 'QUINTA', 'SEXTA', 'SABADO', 'DOMINGO'])]) + + def test_schedule_get_schedule_specific_day_invalid(self): + params = { 'day': 'INVALID' } + response = client.get("/api/schedule/", params=params) + data = response.json() + assert response.status_code == 400 + assert data['detail'] == errorMessages.INVALID_SCHEDULE_DAY + + def test_schedule_get_schedule_specific_day(self): + params = { 'day': 'segunda' } + response = client.get("/api/schedule/", params=params) + data = response.json() + assert response.status_code == 200 + assert len(data) > 0 \ No newline at end of file