from fastapi import FastAPI, Query,Path from fastapi.responses import HTMLResponse from pydantic import BaseModel,Field from typing import Annotated from bs4 import BeautifulSoup,ResultSet import requests from hashlib import md5 from enum import Enum EVA_MAIN_URL:str = "https://eva.fing.edu.uy" EVA_CATEGORY_URL:str = f"{EVA_MAIN_URL}/course/index.php?categoryid={{cat_id}}" EVA_COURSE_URL:str=f"{EVA_MAIN_URL}/course/view.php?id={{course_id}}" EVA_FORUM_URL:str=f"{EVA_MAIN_URL}/mod/forum/view.php?id={{forum_id}}" EVA_RESOURCES_URL:str=f"{EVA_MAIN_URL}/course/resources.php?id={{course_id}}" app:FastAPI = FastAPI(title="EVA API(No oficial)") class Estado(Enum): ABIERTO = 1 CERRADO = 0 class TipoMaterial(Enum): PÁGINA = 0 ARCHIVO = 1 FORO = 2 CARPETA = 3 URL = 4 class Instituto(BaseModel): id:int nombre:str class Curso(BaseModel): estado:Estado = Estado.CERRADO nombre:str id:int class Material(BaseModel): tema:str tipo:TipoMaterial = TipoMaterial.PÁGINA estado:Estado = Estado.CERRADO descripcion: str | None = None def insertar_dentro(lista:list[str],opcion) -> any: return {lista.pop(0):{"info": {'url':opcion.get('value'), 'id':int(opcion.get('value').split("=",1)[-1])} } if len(lista)==0 else insertar_dentro(lista,opcion)} def parse_dict(d1:dict,d2:dict)->dict: claves_repetidas =list( set(d1.keys()) & set(d2.keys())) claves_d1_unicas = list(set(d1.keys())-set(d2.keys())) claves_d2_unicas = list(set(d2.keys())-set(d1.keys())) nuevo_diccionario = {} for key in claves_repetidas: nuevo_diccionario[key] = parse_dict(d1[key],d2[key]) for key in claves_d1_unicas: nuevo_diccionario[key]= d1[key] for key in claves_d2_unicas: nuevo_diccionario[key]= d2[key] return nuevo_diccionario def obtener_institutos() -> dict: response = requests.get(EVA_CATEGORY_URL.format(cat_id=2)) scraper = BeautifulSoup(response.text,'html.parser') opciones:ResultSet = scraper.find_all("option") selecciones:dict = {} for opcion in list(opciones): carpeta:list[str]= opcion.getText().split(" / ") if len(carpeta)<=1: continue a = insertar_dentro(carpeta,opcion) selecciones = parse_dict(selecciones,a) return selecciones def obtener_cursos(category_id:str|int)->list[Curso]: def format_option(opcion): opcion = opcion.parent is_locked = len(opcion.find_all("i"))<2 nombre=opcion.find('div',class_='coursename').getText() id=int(opcion.find('a').get('href').split("=")[-1]) return Curso(**{ "estado":Estado.CERRADO if is_locked else Estado.ABIERTO, "nombre":nombre, "id":id }) response = requests.get(EVA_CATEGORY_URL.format(cat_id=category_id)) scraper = BeautifulSoup(response.text,'html.parser') opciones:ResultSet = scraper.find_all('div',class_="coursename") fixed_opciones = list(map(format_option,opciones)) return fixed_opciones def obtener_recursos(course_id:str|int)->list[Material]: def format_recourse(recurso): datos = recurso.find_all("td") tema = datos[0].getText() info = datos[1] tipo:str = info.find("img").get("alt") url = info.find("a").get("href") tema += info.find("a").getText() if tipo=="URL" else '' descripcion=datos[2].getText() return Material(**{"tema":tema.strip(), "tipo":TipoMaterial[tipo.upper()], "url":url, "descripcion":descripcion}) response = requests.get(EVA_RESOURCES_URL.format(course_id=course_id)) scraper = BeautifulSoup(response.text,'html.parser') recursos = scraper.find("table",class_="generaltable mod_index").find_all("tr")[1:] recursos_formateados = list(map(format_recourse,recursos)) return recursos_formateados def obtener_hilos(foro_id:int)->list: response = requests.get(EVA_FORUM_URL.format(forum_id=foro_id)) #scraper = BeautifulSoup(response.text,'html.parser') return HTMLResponse(content=response.text,status_code=200); return str(scraper) @app.get('/institutos',tags=["institutos"],description="Lista los institutos",response_model=dict,name="Institutos") def ob_ins(): return obtener_institutos() @app.get('/cursos/{instituto_id}',tags=["cursos"],response_model=list[Curso]) def get_courses(instituto_id:Annotated[int,Path(title="ID del instituto",description="ID DEL INSTITUTO")]): return obtener_cursos(instituto_id) @app.get('/recursos/{curso_id}',tags=["cursos","recursos"],response_model=list[Material],description="Obtiene los recursos del curso") def get_recursos(curso_id:Annotated[int,Path(title="ID del curso")]): return obtener_recursos(curso_id) @app.get('/foros/{foro_id}') def get_foro_data(foro_id:Annotated[int,Path(title="ID del foro")]): return obtener_hilos(foro_id)