| | 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)) |
| | |
| | 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) |