Borrado de archivos extra
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,194 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <libpq-fe.h>
|
|
||||||
#include <libxml/HTMLparser.h>
|
|
||||||
#include <libxml/xpath.h>
|
|
||||||
|
|
||||||
// Define the alumno struct
|
|
||||||
struct alumno {
|
|
||||||
char apellido_paterno[100];
|
|
||||||
char apellido_materno[100];
|
|
||||||
char curp[20];
|
|
||||||
char clave_carrera[2];
|
|
||||||
char plan[2];
|
|
||||||
char clave[6];
|
|
||||||
char nombre[100];
|
|
||||||
char correo[100];
|
|
||||||
char estatus;
|
|
||||||
char telefono[11];
|
|
||||||
int semestre;
|
|
||||||
char sexo;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to check for PostgreSQL connection errors
|
|
||||||
void check_conn_status(PGconn *conn) {
|
|
||||||
if (PQstatus(conn) != CONNECTION_OK) {
|
|
||||||
fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn));
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to check for PostgreSQL query execution errors
|
|
||||||
void check_exec_status(PGresult *res, PGconn *conn) {
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
|
|
||||||
fprintf(stderr, "Query failed: %s", PQerrorMessage(conn));
|
|
||||||
PQclear(res);
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to extract content from an HTML element by ID
|
|
||||||
char* get_element_content_by_id(htmlDocPtr doc, const char *id) {
|
|
||||||
xmlChar xpath[100];
|
|
||||||
snprintf((char *)xpath, sizeof(xpath), "//*[@id='%s']", id);
|
|
||||||
|
|
||||||
xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
|
|
||||||
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpath, xpathCtx);
|
|
||||||
|
|
||||||
if (xpathObj == NULL || xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) {
|
|
||||||
xmlXPathFreeObject(xpathObj);
|
|
||||||
xmlXPathFreeContext(xpathCtx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlNodePtr node = xpathObj->nodesetval->nodeTab[0];
|
|
||||||
xmlChar *content = xmlNodeGetContent(node);
|
|
||||||
|
|
||||||
xmlXPathFreeObject(xpathObj);
|
|
||||||
xmlXPathFreeContext(xpathCtx);
|
|
||||||
|
|
||||||
return (char *)content;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to parse HTML content using libxml2 and populate the alumno struct
|
|
||||||
void parse_html(const char *html, struct alumno *alum) {
|
|
||||||
htmlDocPtr doc = htmlReadMemory(html, strlen(html), NULL, NULL, HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING);
|
|
||||||
if (doc == NULL) {
|
|
||||||
fprintf(stderr, "Failed to parse HTML\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *content;
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblApPatAlumnoHP");
|
|
||||||
if (content) {
|
|
||||||
strncpy(alum->apellido_paterno, content, 100);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblApMatAlumnoHP");
|
|
||||||
if (content) {
|
|
||||||
strncpy(alum->apellido_materno, content, 100);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblCURPAlumnoHP");
|
|
||||||
if (content) {
|
|
||||||
strncpy(alum->curp, content, 20);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblCveCarrera");
|
|
||||||
if (content) {
|
|
||||||
strncpy(alum->clave_carrera, content, 2);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblAlupla");
|
|
||||||
if (content) {
|
|
||||||
strncpy(alum->plan, content, 4);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblCveUlsa");
|
|
||||||
if (content) {
|
|
||||||
strncpy(alum->clave, content, 7);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblNombreAlumnoHP");
|
|
||||||
if (content) {
|
|
||||||
strncpy(alum->nombre, content, 100);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblCorreoAlumnoHP");
|
|
||||||
if (content) {
|
|
||||||
strncpy(alum->correo, content, 100);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblStat");
|
|
||||||
if (content) {
|
|
||||||
alum->estatus = content[0];
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblTelefonoAlumnoHP");
|
|
||||||
if (content) {
|
|
||||||
strncpy(alum->telefono, content, 11);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblSem");
|
|
||||||
if (content) {
|
|
||||||
alum->semestre = atoi(content);
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblSexoAlumnoHP");
|
|
||||||
if (content) {
|
|
||||||
alum->sexo = content[0];
|
|
||||||
xmlFree(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlFreeDoc(doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
// PostgreSQL connection parameters
|
|
||||||
const char *conninfo = "dbname=sgi user=postgres password=h3rcul3s#$ hostaddr=200.13.89.8 port=5432";
|
|
||||||
PGconn *conn = PQconnectdb(conninfo);
|
|
||||||
|
|
||||||
// Check connection status
|
|
||||||
check_conn_status(conn);
|
|
||||||
|
|
||||||
// Execute SQL query to retrieve HTML content
|
|
||||||
PGresult *res = PQexec(conn, "SELECT datos_html FROM public.alumno_extraccion WHERE error_message IS NULL");
|
|
||||||
check_exec_status(res, conn);
|
|
||||||
|
|
||||||
// Process each row
|
|
||||||
int rows = PQntuples(res);
|
|
||||||
for (int i = 0; i < rows; i++) {
|
|
||||||
char *html_content = PQgetvalue(res, i, 0);
|
|
||||||
// printf("HTML Content: %s\n", html_content);
|
|
||||||
|
|
||||||
struct alumno alum;
|
|
||||||
memset(&alum, 0, sizeof(alum)); // Initialize the struct to zero
|
|
||||||
|
|
||||||
parse_html(html_content, &alum);
|
|
||||||
|
|
||||||
printf("Apellido Paterno: %s\n", alum.apellido_paterno);
|
|
||||||
printf("Apellido Materno: %s\n", alum.apellido_materno);
|
|
||||||
printf("CURP: %s\n", alum.curp);
|
|
||||||
printf("Clave Carrera: %s\n", alum.clave_carrera);
|
|
||||||
printf("Plan: %s\n", alum.plan);
|
|
||||||
printf("Clave: %s\n", alum.clave);
|
|
||||||
printf("Nombre: %s\n", alum.nombre);
|
|
||||||
printf("Correo: %s\n", alum.correo);
|
|
||||||
printf("Estatus: %c\n", alum.estatus);
|
|
||||||
printf("Telefono: %s\n", alum.telefono);
|
|
||||||
printf("Semestre: %d\n", alum.semestre);
|
|
||||||
printf("Sexo: %c\n", alum.sexo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up
|
|
||||||
PQclear(res);
|
|
||||||
PQfinish(conn);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,17 +0,0 @@
|
|||||||
import argparse
|
|
||||||
import getpass
|
|
||||||
|
|
||||||
def parse_arguments():
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("clave", help="Clave ULSA argument")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
clave = args.clave
|
|
||||||
if not clave.startswith('al') or not clave[2:].isdigit() or len(clave) != 8:
|
|
||||||
raise ValueError("Clave no válida. Debe comenzar con 'al' y tener 6 dígitos.")
|
|
||||||
|
|
||||||
contraseña = getpass.getpass("Contraseña: ")
|
|
||||||
if not clave or not contraseña:
|
|
||||||
raise ValueError("Clave y/o contraseña no válidos")
|
|
||||||
|
|
||||||
return clave, contraseña
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
def process_html(html_doc):
|
|
||||||
"""
|
|
||||||
Procesa el HTML de la página y extrae la información relevante
|
|
||||||
como materias, estados del servicio social, etc.
|
|
||||||
"""
|
|
||||||
soup = BeautifulSoup(html_doc, 'lxml')
|
|
||||||
table = soup.find('table', attrs={'id': 'ctl00_contenedor_HistorialAlumno1_gvMaterias'})
|
|
||||||
|
|
||||||
actualmente_cursadas = soup.find('table', attrs={'id': 'ctl00_contenedor_HistorialAlumno1_gvMatOrdinario'})
|
|
||||||
|
|
||||||
if table is None:
|
|
||||||
raise Exception("Tabla no encontrada en la página")
|
|
||||||
elif actualmente_cursadas is None:
|
|
||||||
raise Exception("Tabla de materias actualmente cursadas no encontrada en la página")
|
|
||||||
|
|
||||||
materias_sgu = []
|
|
||||||
headers = [header.text for header in table.find_all('th')]
|
|
||||||
|
|
||||||
for row in table.find_all('tr'):
|
|
||||||
cols = row.find_all('td')
|
|
||||||
if cols and not any(col.text == "Promedio:" for col in cols):
|
|
||||||
materias_sgu.append({ headers[i]: col.text for i, col in enumerate(cols) if not is_cell_empty(col.text) })
|
|
||||||
materias_actualmente_cursadas = []
|
|
||||||
headers = [header.text for header in actualmente_cursadas.find_all('th')]
|
|
||||||
for row in actualmente_cursadas.find_all('tr'):
|
|
||||||
cols = row.find_all('td')
|
|
||||||
if cols and not any(col.text == "No hay Datos" for col in cols):
|
|
||||||
materias_actualmente_cursadas.append({ headers[i]: col.text for i, col in enumerate(cols) if not is_cell_empty(col.text) })
|
|
||||||
|
|
||||||
periodo_actual = soup.find('span', attrs={'id': 'ctl00_contenedor_HistorialAlumno1_Header1_lblPeriodo'})
|
|
||||||
grupo_actual = soup.find('span', attrs={'id': 'ctl00_contenedor_HistorialAlumno1_Header1_lblgru'})
|
|
||||||
|
|
||||||
return clean_materias_sgu(materias_sgu), clean_materias_sgu(materias_actualmente_cursadas), f"'{periodo_actual.text}'", f"'{grupo_actual.text}'"
|
|
||||||
|
|
||||||
def is_cell_empty(cell_content):
|
|
||||||
"""
|
|
||||||
Verifica si el contenido de una celda está vacío o contiene solo espacios.
|
|
||||||
"""
|
|
||||||
return not cell_content.strip() or cell_content == u'\xa0'
|
|
||||||
|
|
||||||
def clean_materias_sgu(materias_sgu):
|
|
||||||
"""
|
|
||||||
Limpia y ajusta las materias obtenidas del SGU para su procesamiento posterior.
|
|
||||||
"""
|
|
||||||
for materia in materias_sgu:
|
|
||||||
if '\xa0' in materia:
|
|
||||||
materia['SEMESTRE'] = materia.pop('\xa0')
|
|
||||||
return materias_sgu
|
|
||||||
|
|
||||||
# Puedes agregar más funciones según sea necesario para procesar otros aspectos del HTML
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import psycopg2
|
|
||||||
from psycopg2.extras import DictCursor
|
|
||||||
|
|
||||||
def connect_to_database(dbname="sgi", user="postgres", password="h3rcul3s#$", host="200.13.89.8", port="5432"):
|
|
||||||
"""
|
|
||||||
Establece una conexión a la base de datos y la retorna.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
connection = psycopg2.connect(
|
|
||||||
dbname=dbname,
|
|
||||||
user=user,
|
|
||||||
password=password,
|
|
||||||
host=host,
|
|
||||||
port=port
|
|
||||||
)
|
|
||||||
return connection
|
|
||||||
except psycopg2.Error as e:
|
|
||||||
print(f"No se pudo conectar a la base de datos: {e}")
|
|
||||||
exit()
|
|
||||||
|
|
||||||
def query_all(sql):
|
|
||||||
with connect_to_database() as conn:
|
|
||||||
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
||||||
cur.execute(sql)
|
|
||||||
return cur.fetchall()
|
|
||||||
|
|
||||||
def query_single(sql):
|
|
||||||
with connect_to_database() as conn:
|
|
||||||
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
||||||
cur.execute(sql)
|
|
||||||
return cur.fetchone() # Returns a dictionary-like object
|
|
||||||
|
|
||||||
def execute_query(sql):
|
|
||||||
with connect_to_database() as conn:
|
|
||||||
with conn.cursor() as cur:
|
|
||||||
cur.execute(sql)
|
|
||||||
conn.commit() # Commit to save the insert operation
|
|
||||||
|
|
||||||
def log(message, status, error_message=None, clave=None, no_insertadas=[]):
|
|
||||||
with connect_to_database(dbname="adcfi", user="postgres", password="Ultr4p0d3r0s0##", host="200.13.89.42", port="5432") as conn:
|
|
||||||
with conn.cursor() as cur:
|
|
||||||
cur.execute(f"""
|
|
||||||
INSERT INTO calificaciones.calificaciones_log (response_status, error_message, user_ip, additional_info)
|
|
||||||
VALUES ({status}, {f"'{error_message}'" if error_message else 'NULL'}, '200.13.89.42', '{{"clave": "{clave}", "message": "{message}", "no insertadas": "[{', '.join(no_insertada for no_insertada in no_insertadas)}]"}}')
|
|
||||||
""")
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
from database_operations import query_all, query_single, execute_query
|
|
||||||
|
|
||||||
def actualizar_servicio(clave, Alumno_serviciosocial):
|
|
||||||
# Actualizar servicio social
|
|
||||||
execute_query(f'''
|
|
||||||
UPDATE "Alumno" SET "Alumno_serviciosocial" = {Alumno_serviciosocial} WHERE "Usuario_claveULSA" = {int(clave[2:])}
|
|
||||||
''')
|
|
||||||
|
|
||||||
def get_periodos(materias_sgu):
|
|
||||||
return query_all(f'''SELECT * FROM "Periodo" WHERE "Periodo_shortname" IN ({",".join(f"'{materia['PERIODO']}'" for materia in materias_sgu)})''')
|
|
||||||
|
|
||||||
def get_materias(materias_sgu):
|
|
||||||
return query_all('SELECT * FROM "Materia"')
|
|
||||||
def get_tipo_calificaciones(materias_sgu):
|
|
||||||
return query_all(f'''SELECT * FROM "TipoCalificacion"''')
|
|
||||||
def get_alumno(clave):
|
|
||||||
return query_single(f'SELECT "Carrera_id", "PlanEstudio_id" FROM "Alumno_view" WHERE "Usuario_claveULSA" = {clave[2:]}')
|
|
||||||
def get_grupo(grupo, carrera_id):
|
|
||||||
return query_single(f'''SELECT "Grupo_id" FROM "Grupo_view"
|
|
||||||
WHERE REGEXP_REPLACE("Grupo_desc", '[^\d]', '', 'g') = '{grupo}' AND (("Carrera_id" = {carrera_id}) OR "Carrera_esComun")
|
|
||||||
''')
|
|
||||||
def insert_materia(clave, materia_id, periodo_id, grupo_id):
|
|
||||||
execute_query(f'''INSERT INTO public."Alumno_Materia"("Usuario_claveULSA", "Materia_id", "Periodo_id", "Grupo_id")
|
|
||||||
VALUES ({int(clave[2:])}, {materia_id}, {periodo_id}, {grupo_id})
|
|
||||||
ON CONFLICT ("Usuario_claveULSA", "Materia_id", "Periodo_id") DO NOTHING;
|
|
||||||
''')
|
|
||||||
def insert_calificaciones(calificaciones):
|
|
||||||
execute_query(f'''
|
|
||||||
insert into "Alumno_Materia_Calificacion"
|
|
||||||
("Usuario_claveULSA", "Materia_id", "Periodo_id", "TipoCalificacion_id", "Calificacion_calif", "Calificacion_fecha", "Calificacion_comentario")
|
|
||||||
values {','.join(calificaciones)}
|
|
||||||
on conflict ("Usuario_claveULSA", "Materia_id", "Periodo_id", "TipoCalificacion_id")
|
|
||||||
DO UPDATE SET "Calificacion_calif" = EXCLUDED."Calificacion_calif", "Calificacion_comentario" = EXCLUDED."Calificacion_comentario";
|
|
||||||
''')
|
|
||||||
|
|
||||||
|
|
||||||
#alumno structure {apellido_paterno: str, apellido_materno: str, curp: str, clave_carrera: int, plan: int, clave: int, servicio_social: bool, nombre: str, correo: str}
|
|
||||||
def insert_alumno(alumno):
|
|
||||||
alumno_base = query_single(f'SELECT "Carrera_id", "PlanEstudio_id" FROM "Alumno_view" WHERE "Usuario_claveULSA" = {alumno["clave"]}')
|
|
||||||
if alumno_base:
|
|
||||||
return alumno_base
|
|
||||||
|
|
||||||
usuario_base = query_single(f"""SELECT * FROM "Usuario" WHERE "Usuario_curp" = '{alumno["curp"]}'""")
|
|
||||||
plan_estudio_base = query_single(f"""SELECT * FROM "PlanEstudio_view" WHERE "PlanEstudio_desc" LIKE '%{alumno["plan"]}' AND "Carrera_clave" = {alumno["clave_carrera"]}""")
|
|
||||||
|
|
||||||
if usuario_base:
|
|
||||||
execute_query(f'''
|
|
||||||
INSERT INTO public."Alumno"("Usuario_claveULSA", "Usuario_id", "PlanEstudio_id", "Alumno_fecha_ingreso", "Alumno_generacion", "Alumno_serviciosocial")
|
|
||||||
VALUES ({alumno["clave"]}, {usuario_base["Usuario_id"]}, {plan_estudio_base["PlanEstudio_id"]}, '{alumno['fecha_ingreso']}', '{alumno['fecha_ingreso']}', {alumno["servicio_social"]})
|
|
||||||
ON CONFLICT ("Usuario_claveULSA") DO NOTHING;
|
|
||||||
''')
|
|
||||||
execute_query(f'''
|
|
||||||
INSERT INTO "Alumno_SubEstadoAlumno" ("SubEstadoAlumno_id", "Usuario_claveULSA", "SEA_fecha", "SEA_actual")
|
|
||||||
VALUES (3, {alumno["clave"]},'{alumno['fecha_ingreso']}', true)
|
|
||||||
''')
|
|
||||||
|
|
||||||
alumno_base = query_single(f'SELECT "Carrera_id", "PlanEstudio_id" FROM "Alumno_view" WHERE "Usuario_claveULSA" = {alumno["clave"]}')
|
|
||||||
|
|
||||||
return alumno_base
|
|
||||||
|
|
||||||
usuario_base = query_single(f'''
|
|
||||||
INSERT INTO public."Usuario"("Usuario_nombre", "Usuario_apellidos", "Usuario_curp")
|
|
||||||
VALUES ('{alumno["nombre"]}', '{alumno["apellido_paterno"]} {alumno["apellido_materno"]}', '{alumno["curp"]}') RETURNING "Usuario_id"
|
|
||||||
''')
|
|
||||||
execute_query(f'''
|
|
||||||
INSERT INTO public."Alumno"("Usuario_claveULSA", "Usuario_id", "PlanEstudio_id", "Alumno_fecha_ingreso", "Alumno_generacion", "Alumno_serviciosocial")
|
|
||||||
VALUES ({alumno["clave"]}, {usuario_base["Usuario_id"]}, {plan_estudio_base["PlanEstudio_id"]}, '{alumno['fecha_ingreso']}', '{alumno['fecha_ingreso']}', {alumno["servicio_social"]})
|
|
||||||
ON CONFLICT ("Usuario_claveULSA") DO NOTHING;
|
|
||||||
''')
|
|
||||||
alumno_base = query_single(f'SELECT "Carrera_id", "PlanEstudio_id" FROM "Alumno_view" WHERE "Usuario_claveULSA" = {alumno["clave"]}')
|
|
||||||
|
|
||||||
return alumno_base
|
|
||||||
|
|
||||||
# insert actualmente_cursadas
|
|
||||||
def insert_actualmente_cursadas(clave, actualmente_cursadas, periodo_actual, grupo_actual):
|
|
||||||
grupo_base = query_single(f'SELECT "Grupo_id" FROM "Grupo" WHERE "Grupo_desc" = {grupo_actual}')
|
|
||||||
periodo_base = query_single(f'SELECT "Periodo_id" FROM "Periodo" WHERE "Periodo_shortname" = {periodo_actual}')
|
|
||||||
# only where materia["Clave"] is set
|
|
||||||
for materia in filter(lambda materia: "Clave" in materia, actualmente_cursadas):
|
|
||||||
# to varchar
|
|
||||||
materia_clave = f"'{materia['Clave']}'"
|
|
||||||
materia_base = query_single(f'SELECT "Materia_id" FROM "Materia" WHERE {materia_clave} = ANY("Materia_claves")')
|
|
||||||
if materia_base:
|
|
||||||
execute_query(f'''
|
|
||||||
INSERT INTO public."Alumno_Materia"("Usuario_claveULSA", "Materia_id", "Periodo_id", "Grupo_id")
|
|
||||||
VALUES ({clave[2:]}, {materia_base["Materia_id"]}, {periodo_base["Periodo_id"]}, {grupo_base["Grupo_id"]})
|
|
||||||
ON CONFLICT ("Usuario_claveULSA", "Materia_id", "Periodo_id") DO NOTHING;
|
|
||||||
''')
|
|
||||||
|
|
||||||
|
|
||||||
def insert_datos(alumno):
|
|
||||||
execute_query(f'''
|
|
||||||
INSERT INTO public."pos_ultima_extraccion"("Usuario_claveULSA", "telefono", "correo", "estatus", "promedio", "sexo", "semestre")
|
|
||||||
VALUES ({alumno["clave"]}, '{alumno["telefono"]}', '{alumno["correo"]}', '{alumno["estatus"]}', {alumno["promedio"]} , '{alumno["sexo"]}', {alumno["semestre"]})
|
|
||||||
ON CONFLICT ("Usuario_claveULSA") DO UPDATE SET "telefono" = EXCLUDED."telefono", "correo" = EXCLUDED."correo", "estatus" = EXCLUDED."estatus", "promedio" = EXCLUDED."promedio",
|
|
||||||
"actualizacion" = now();
|
|
||||||
''')
|
|
||||||
|
|
||||||
|
|
||||||
35
lib/log.py
35
lib/log.py
@@ -1,35 +0,0 @@
|
|||||||
import psycopg2
|
|
||||||
from psycopg2.extras import DictCursor
|
|
||||||
|
|
||||||
def connect_to_database(dbname="sgi", user="postgres", password="sys4lci", host="200.13.89.27", port="5432"):
|
|
||||||
"""
|
|
||||||
Establece una conexión a la base de datos y la retorna.
|
|
||||||
"""
|
|
||||||
connection = psycopg2.connect(
|
|
||||||
dbname=dbname,
|
|
||||||
user=user,
|
|
||||||
password=password,
|
|
||||||
host=host,
|
|
||||||
port=port
|
|
||||||
)
|
|
||||||
return connection
|
|
||||||
|
|
||||||
|
|
||||||
def query_all(sql):
|
|
||||||
with connect_to_database() as conn:
|
|
||||||
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
||||||
cur.execute(sql)
|
|
||||||
return cur.fetchall()
|
|
||||||
|
|
||||||
def query_single(sql):
|
|
||||||
with connect_to_database() as conn:
|
|
||||||
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
||||||
cur.execute(sql)
|
|
||||||
return cur.fetchone() # Returns a dictionary-like object
|
|
||||||
|
|
||||||
def execute_query(sql):
|
|
||||||
with connect_to_database() as conn:
|
|
||||||
with conn.cursor() as cur:
|
|
||||||
cur.execute(sql)
|
|
||||||
conn.commit() # Commit to save the insert operation
|
|
||||||
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
from selenium import webdriver
|
|
||||||
from selenium.webdriver.chrome.service import Service
|
|
||||||
from selenium.webdriver.chrome.options import Options
|
|
||||||
|
|
||||||
def configure_selenium():
|
|
||||||
options = Options()
|
|
||||||
options.add_argument("--headless")
|
|
||||||
options.add_argument("--disable-gpu")
|
|
||||||
options.add_argument("--no-sandbox")
|
|
||||||
options.add_argument("--disable-dev-shm-usage")
|
|
||||||
options.add_argument("--window-size=1920x1080")
|
|
||||||
|
|
||||||
PATH = "/usr/bin/chromedriver"
|
|
||||||
service = Service(PATH)
|
|
||||||
driver = webdriver.Chrome(service=service, options=options)
|
|
||||||
return driver
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
from selenium.webdriver.common.by import By
|
|
||||||
from selenium.webdriver.support.ui import WebDriverWait
|
|
||||||
from selenium.webdriver.support import expected_conditions as EC
|
|
||||||
|
|
||||||
def navigate_to_url(driver, url, clave, contraseña):
|
|
||||||
formatted_url = f"https://{clave}:{contraseña}@{url}"
|
|
||||||
driver.get(formatted_url)
|
|
||||||
driver.get(f'https://{url}')
|
|
||||||
# If dentro del código no existe un elemento con el id ctl00_lnkHome
|
|
||||||
if not WebDriverWait(driver, 10).until(
|
|
||||||
EC.presence_of_element_located((By.ID, "ctl00_lnkHome"))
|
|
||||||
):
|
|
||||||
raise Exception("No se pudo iniciar sesión.")
|
|
||||||
|
|
||||||
# wait until it appears this element.id = ctl00_contenedor_HistorialAlumno1_lblApPatAlumnoHP and get it
|
|
||||||
|
|
||||||
def wait_for_element(driver, element_id):
|
|
||||||
return WebDriverWait(driver, 10).until(
|
|
||||||
EC.presence_of_element_located((By.ID, element_id))
|
|
||||||
)
|
|
||||||
|
|
||||||
servicio_social = wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_Header1_lblSS")
|
|
||||||
alumno = {
|
|
||||||
"apellido_paterno": wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_lblApPatAlumnoHP").text,
|
|
||||||
"apellido_materno": wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_lblApMatAlumnoHP").text,
|
|
||||||
"curp": wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_lblCURPAlumnoHP").text,
|
|
||||||
"clave_carrera": int(wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_Header1_lblCveCarrera").text),
|
|
||||||
"plan": int(wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_Header1_lblAlupla").text),
|
|
||||||
"clave": int(wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_Header1_lblCveUlsa").text),
|
|
||||||
"servicio_social": servicio_social.text == "Realizado",
|
|
||||||
"nombre":wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_lblNombreAlumnoHP").text,
|
|
||||||
"correo": wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_lblCorreoAlumnoHP").text,
|
|
||||||
'estatus' : wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_Header1_lblStat").text,
|
|
||||||
"telefono": wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_lblTelefonoAlumnoHP").text,
|
|
||||||
"semestre": int(wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_Header1_lblSem").text),
|
|
||||||
"sexo": wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_lblSexoAlumnoHP").text,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
click_element(driver, element_id="ctl00_contenedor_HistorialAlumno1_lblBtnSeccionHAcademico")
|
|
||||||
|
|
||||||
historial_academico = driver.page_source
|
|
||||||
|
|
||||||
alumno['promedio'] = float(wait_for_element(driver, "ctl00_contenedor_HistorialAlumno1_lblPromedioAlumnoHA").text)
|
|
||||||
|
|
||||||
return alumno, historial_academico
|
|
||||||
|
|
||||||
def click_element(driver, element_id):
|
|
||||||
elemento = WebDriverWait(driver, 10).until(
|
|
||||||
EC.presence_of_element_located((By.ID, element_id))
|
|
||||||
)
|
|
||||||
elemento.click()
|
|
||||||
|
|
||||||
|
|
||||||
16
logs.py
16
logs.py
@@ -1,16 +0,0 @@
|
|||||||
import psycopg2
|
|
||||||
from psycopg2.extras import DictCursor
|
|
||||||
|
|
||||||
conn = psycopg2.connect(
|
|
||||||
dbname='adcfi',
|
|
||||||
user='postgres',
|
|
||||||
password='Ultr4p0d3r0s0##',
|
|
||||||
host='200.13.89.42',
|
|
||||||
port='5432'
|
|
||||||
)
|
|
||||||
|
|
||||||
with conn.cursor(cursor_factory=DictCursor) as cur:
|
|
||||||
cur.execute("SELECT * FROM calificaciones.calificaciones_log ORDER BY log_timestamp DESC LIMIT 10")
|
|
||||||
|
|
||||||
for row in cur:
|
|
||||||
print(row)
|
|
||||||
105
main.py
105
main.py
@@ -1,105 +0,0 @@
|
|||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
from flask import Flask, request, jsonify
|
|
||||||
from waitress import serve
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
# Agregar el directorio lib al path de Python
|
|
||||||
lib_path = Path(__file__).parent / 'lib'
|
|
||||||
sys.path.append(str(lib_path))
|
|
||||||
|
|
||||||
# Ahora puedes importar los módulos desde el directorio lib
|
|
||||||
from selenium_setup import configure_selenium
|
|
||||||
from argument_parser import parse_arguments
|
|
||||||
from web_navigation import navigate_to_url, click_element
|
|
||||||
from data_processing import process_html
|
|
||||||
from database_operations import log
|
|
||||||
from funciones import *
|
|
||||||
|
|
||||||
def main(clave, contraseña):
|
|
||||||
# Configurar Selenium y navegar a la URL
|
|
||||||
driver = configure_selenium()
|
|
||||||
url = "sgu.ulsa.edu.mx/psulsa/alumnos/consultainformacionalumnos/consultainformacion.aspx"
|
|
||||||
datos_alumno, historial_academico = navigate_to_url(driver, url, clave, contraseña)
|
|
||||||
materias_sgu, actualmente_cursadas, periodo_actual, grupo_actual = process_html(historial_academico)
|
|
||||||
insert_actualmente_cursadas(clave, actualmente_cursadas, periodo_actual, grupo_actual)
|
|
||||||
|
|
||||||
# Obtener datos de la base
|
|
||||||
periodos_base = get_periodos(materias_sgu)
|
|
||||||
|
|
||||||
# obtener la fecha mínima del arreglo de diccionarios de periodos en su campo "Periodo_fecha_inicio"
|
|
||||||
fecha_mínima = min(periodos_base, key=lambda x: x['Periodo_fecha_inicial'])['Periodo_fecha_inicial']
|
|
||||||
# déjalo en el primer día del mes
|
|
||||||
datos_alumno['fecha_ingreso'] = fecha_mínima.replace(day=1)
|
|
||||||
|
|
||||||
materias_base = get_materias(materias_sgu)
|
|
||||||
tipo_calificaciones_base = get_tipo_calificaciones(materias_sgu)
|
|
||||||
alumno_base = insert_alumno(datos_alumno)
|
|
||||||
|
|
||||||
# Actualizar servicio social
|
|
||||||
actualizar_servicio(clave, datos_alumno['servicio_social'])
|
|
||||||
|
|
||||||
#insert datos
|
|
||||||
insert_datos(datos_alumno)
|
|
||||||
|
|
||||||
calificaciones = []
|
|
||||||
no_insertadas = []
|
|
||||||
|
|
||||||
for materia_sgu in materias_sgu:
|
|
||||||
materia_base = next((materia_base for materia_base in materias_base if materia_sgu['Cve ULSA'] in materia_base['Materia_claves'] or (materia_sgu['Cve SEP'] in materia_base["Materia_claves"] and alumno_base['PlanEstudio_id'] == materia_base['PlanEstudio_id'])), None)
|
|
||||||
periodo_base = next((periodo_base for periodo_base in periodos_base if periodo_base['Periodo_shortname'] == materia_sgu['PERIODO']), None)
|
|
||||||
tipo_calificacion_base = next((calificacion_base for calificacion_base in tipo_calificaciones_base if calificacion_base['TipoCalificacion_desc_corta'] == materia_sgu['EXAMEN']), None)
|
|
||||||
if 'GRUPO' in materia_sgu.keys():
|
|
||||||
grupo = get_grupo(materia_sgu['GRUPO'], alumno_base['Carrera_id'])
|
|
||||||
else:
|
|
||||||
grupo = None
|
|
||||||
|
|
||||||
if materia_base and periodo_base and tipo_calificacion_base:
|
|
||||||
calificaciones.append(f"({clave[2:]}, {materia_base['Materia_id']}, {periodo_base['Periodo_id']}, {tipo_calificacion_base['TipoCalificacion_id']}, {materia_sgu['CALIF']}, CURRENT_DATE, 'SGU')")
|
|
||||||
|
|
||||||
if not materia_base or not periodo_base or not tipo_calificacion_base or not grupo:
|
|
||||||
no_insertadas.append(f'''Materia: {materia_base['Materia_id'] if materia_base else materia_sgu['Cve ULSA']} - Periodo_base: {periodo_base['Periodo_id'] if periodo_base else materia_sgu['PERIODO']} Tipo_calificacion_base: {tipo_calificacion_base['TipoCalificacion_id'] if tipo_calificacion_base else materia_sgu['EXAMEN']} Grupo: {grupo['Grupo_id'] if grupo else materia_sgu['GRUPO'] if 'GRUPO' in materia_sgu.keys() else 'None' } ''')
|
|
||||||
continue
|
|
||||||
|
|
||||||
insert_materia(clave, materia_base['Materia_id'], periodo_base['Periodo_id'], grupo['Grupo_id'])
|
|
||||||
|
|
||||||
|
|
||||||
if not calificaciones or len(calificaciones) == 0:
|
|
||||||
raise Exception("No hay calificaciones para insertar o actualizar.")
|
|
||||||
|
|
||||||
# Insertar calificaciones
|
|
||||||
insert_calificaciones(calificaciones)
|
|
||||||
return clave, no_insertadas
|
|
||||||
|
|
||||||
@app.route('/calificaciones', methods=['POST'])
|
|
||||||
def calificaciones():
|
|
||||||
try:
|
|
||||||
# Obtener la clave y la contraseña de la solicitud POST
|
|
||||||
clave = request.form.get('clave')
|
|
||||||
contraseña = request.form.get('contraseña')
|
|
||||||
|
|
||||||
# Verificar si la clave y la contraseña existen
|
|
||||||
if clave is None or contraseña is None:
|
|
||||||
return "Error: La clave y/o contraseña no fueron proporcionadas en la solicitud."
|
|
||||||
|
|
||||||
# Procesar los datos (aquí llamamos a la función main)
|
|
||||||
clave, no_insertadas = main(clave, contraseña)
|
|
||||||
|
|
||||||
# Registro de éxito
|
|
||||||
log("Proceso terminado con éxito.", 200, None, clave, no_insertadas)
|
|
||||||
|
|
||||||
# Retornar respuesta exitosa como JSON
|
|
||||||
return jsonify({"mensaje": "Proceso terminado con éxito.", "clave": clave, "no_insertadas": no_insertadas, "success": True})
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
# remove all ' from the error message
|
|
||||||
e = e.replace("'", "")
|
|
||||||
log(str(e), 500, e, None)
|
|
||||||
|
|
||||||
# Retornar mensaje de error como JSON
|
|
||||||
return jsonify({"mensaje": str(e), "success": False})
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
serve(app, host='0.0.0.0', port=5000)
|
|
||||||
217
sgu.py
217
sgu.py
@@ -1,217 +0,0 @@
|
|||||||
import numpy as np
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
import psycopg2
|
|
||||||
from selenium import webdriver
|
|
||||||
from selenium.webdriver.chrome.service import Service
|
|
||||||
from selenium.webdriver.chrome.options import Options
|
|
||||||
from selenium.webdriver.common.by import By
|
|
||||||
from selenium.webdriver.support.ui import WebDriverWait
|
|
||||||
from selenium.webdriver.support import expected_conditions as EC
|
|
||||||
import argparse
|
|
||||||
import getpass
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Configuración de Selenium
|
|
||||||
options = Options()
|
|
||||||
options.add_argument("--headless")
|
|
||||||
options.add_argument("--disable-gpu")
|
|
||||||
options.add_argument("--no-sandbox")
|
|
||||||
options.add_argument("--disable-dev-shm-usage")
|
|
||||||
options.add_argument("--window-size=1920x1080")
|
|
||||||
|
|
||||||
PATH = "/usr/bin/chromedriver"
|
|
||||||
service = Service(PATH)
|
|
||||||
driver = webdriver.Chrome(service=service, options=options)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error configurando el navegador: {e}")
|
|
||||||
exit()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Parseo de argumentos
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("clave", help="Clave ULSA argument")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
clave = args.clave
|
|
||||||
# Solicitar la contraseña de manera segura
|
|
||||||
contraseña = getpass.getpass("Contraseña: ")
|
|
||||||
|
|
||||||
if not clave or not contraseña:
|
|
||||||
raise ValueError("Clave y/o contraseña no válidos")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error en los argumentos: {e}")
|
|
||||||
driver.quit()
|
|
||||||
exit()
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Navegar a la URL
|
|
||||||
url = "sgu.ulsa.edu.mx/psulsa/alumnos/consultainformacionalumnos/consultainformacion.aspx"
|
|
||||||
formatted_url = f"https://{clave}:{contraseña}@{url}"
|
|
||||||
driver.get(formatted_url)
|
|
||||||
driver.get(f'https://{url}')
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error navegando a la URL: {e}")
|
|
||||||
driver.quit()
|
|
||||||
exit()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# If dentro del código existe un (case insensitive) Unauthorized
|
|
||||||
if "Unauthorized" in driver.page_source:
|
|
||||||
raise Exception("Credenciales inválidas")
|
|
||||||
|
|
||||||
elemento = WebDriverWait(driver, 10).until(
|
|
||||||
EC.presence_of_element_located((By.ID, "ctl00_contenedor_HistorialAlumno1_lblBtnSeccionHAcademico"))
|
|
||||||
)
|
|
||||||
elemento.click()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error interactuando con la página: {e}")
|
|
||||||
driver.quit()
|
|
||||||
exit()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Procesamiento de HTML con BeautifulSoup
|
|
||||||
html_doc = driver.page_source
|
|
||||||
soup = BeautifulSoup(html_doc, 'lxml')
|
|
||||||
table = soup.find('table', attrs={'id': 'ctl00_contenedor_HistorialAlumno1_gvMaterias'})
|
|
||||||
|
|
||||||
if table is None:
|
|
||||||
raise Exception("Tabla no encontrada en la página")
|
|
||||||
|
|
||||||
materias_sgu = []
|
|
||||||
|
|
||||||
headers = [header.text for header in table.find_all('th')]
|
|
||||||
|
|
||||||
def is_cell_empty(cell_content):
|
|
||||||
return not cell_content.strip() or cell_content == u'\xa0'
|
|
||||||
|
|
||||||
for row in table.find_all('tr'):
|
|
||||||
cols = row.find_all('td')
|
|
||||||
if cols and not any(is_cell_empty(col.text) for col in cols):
|
|
||||||
materias_sgu.append({headers[i]: col.text for i, col in enumerate(cols)})
|
|
||||||
|
|
||||||
for materia in materias_sgu:
|
|
||||||
materia['SEMESTRE'] = materia.pop('\xa0')
|
|
||||||
|
|
||||||
|
|
||||||
servicio_social = soup.find('span', attrs={'id': 'ctl00_contenedor_HistorialAlumno1_Header1_lblSS'}).text
|
|
||||||
# puede ser Realizado, No Realizado
|
|
||||||
if servicio_social == "No Realizado":
|
|
||||||
Alumno_serviciosocial = False
|
|
||||||
elif servicio_social == "Realizado":
|
|
||||||
Alumno_serviciosocial = True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error procesando HTML: {e}")
|
|
||||||
exit()
|
|
||||||
finally:
|
|
||||||
driver.quit()
|
|
||||||
|
|
||||||
# Conexión a la base de datos y operaciones
|
|
||||||
conexion = psycopg2.connect(
|
|
||||||
dbname="sgi",
|
|
||||||
user="postgres",
|
|
||||||
password="sys4lci",
|
|
||||||
host="200.13.89.27",
|
|
||||||
port="5432"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Ejecutar la consulta para actualizar public."Alumno"."Alumno_serviciosocial"
|
|
||||||
try:
|
|
||||||
with conexion.cursor() as cursor:
|
|
||||||
cursor.execute(f'UPDATE public."Alumno" SET "Alumno_serviciosocial" = {Alumno_serviciosocial} WHERE "Usuario_claveULSA" = \'{clave[2:]}\'')
|
|
||||||
conexion.commit()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error al actualizar el servicio social: {e}")
|
|
||||||
if conexion:
|
|
||||||
conexion.rollback()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Ejecutar la consulta para obtener los periodos
|
|
||||||
with conexion.cursor() as cursor:
|
|
||||||
cursor.execute('SELECT * FROM "Periodo"')
|
|
||||||
Periodos = cursor.fetchall()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error obteniendo los periodos de la base de datos: {e}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Ejecutar la consulta para obtener los tipos de calificación
|
|
||||||
with conexion.cursor() as cursor:
|
|
||||||
cursor.execute('SELECT * FROM "TipoCalificacion"')
|
|
||||||
TiposCalificacion = cursor.fetchall()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error obteniendo los tipos de calificación de la base de datos: {e}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Ejecutar la consulta para obtener las materias base
|
|
||||||
with conexion.cursor() as cursor:
|
|
||||||
cursor.execute('SELECT * FROM "Materia"')
|
|
||||||
materias_base = cursor.fetchall()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error obteniendo las materias de la base de datos: {e}")
|
|
||||||
try:
|
|
||||||
# Procesar y preparar las calificaciones para inserción/actualización
|
|
||||||
calificaciones = []
|
|
||||||
with conexion.cursor() as cursor:
|
|
||||||
cursor.execute(f'''
|
|
||||||
SELECT "Carrera_id", "PlanEstudio_id"
|
|
||||||
FROM "Alumno_view"
|
|
||||||
WHERE "Usuario_claveULSA" = {clave[2:]}
|
|
||||||
''')
|
|
||||||
Alumno_base = cursor.fetchone()
|
|
||||||
for materia_sgu in materias_sgu:
|
|
||||||
materia_base = next((materia_base for materia_base in materias_base if (materia_sgu['Cve ULSA'] in materia_base[-1] or materia_sgu['Cve SEP'] in materia_base[-1]) and (Alumno_base[1] == materia_base[0])), None)
|
|
||||||
if not materia_base:
|
|
||||||
continue
|
|
||||||
|
|
||||||
Periodo_base = next((Periodo_base for Periodo_base in Periodos if Periodo_base[-2] == materia_sgu['PERIODO']), None)
|
|
||||||
if not Periodo_base:
|
|
||||||
continue
|
|
||||||
|
|
||||||
Calificacion_base = next((Calificacion_base for Calificacion_base in TiposCalificacion if Calificacion_base[-2] == materia_sgu['EXAMEN']), None)
|
|
||||||
if not Calificacion_base:
|
|
||||||
raise Exception(f"No se encontró el tipo de calificación {materia_sgu['EXAMEN']} en la base de datos")
|
|
||||||
|
|
||||||
# buscar en la base de datos el grupo WHERE Grupo_desc = materia_sgu['GRUPO'] and if is not in the base insert it (note: semestre when printed in the console is '\xa0': '5')
|
|
||||||
with conexion.cursor() as cursor:
|
|
||||||
cursor.execute(f'''
|
|
||||||
SELECT "Grupo_id"
|
|
||||||
FROM "Grupo_view"
|
|
||||||
WHERE REGEXP_REPLACE("Grupo_desc", '[^\d]', '', 'g') = '{materia_sgu["GRUPO"]}' AND (("Carrera_id" = {Alumno_base[0]}) OR "Carrera_esComun")
|
|
||||||
''')
|
|
||||||
Grupo = cursor.fetchone()
|
|
||||||
if Grupo:
|
|
||||||
cursor.execute(f'''
|
|
||||||
INSERT INTO public."Alumno_Materia"("Usuario_claveULSA", "Materia_id", "Periodo_id", "Grupo_id")
|
|
||||||
VALUES ({clave[2:]}, {materia_base[0]}, {Periodo_base[0]}, {Grupo[0]})
|
|
||||||
ON CONFLICT ("Usuario_claveULSA", "Materia_id", "Periodo_id") DO NOTHING
|
|
||||||
;
|
|
||||||
''')
|
|
||||||
|
|
||||||
conexion.commit()
|
|
||||||
|
|
||||||
if not materia_base or not Periodo_base or not Calificacion_base:
|
|
||||||
print(f"No se encontraron coincidencias para la materia {materia_sgu['Cve ULSA']} o el periodo {materia_sgu['PERIODO']} o el tipo de calificación {materia_sgu['EXAMEN']}")
|
|
||||||
continue # Saltar esta iteración si alguna coincidencia falla
|
|
||||||
calificaciones.append(f"({clave[2:]}, {materia_base[0]}, {Periodo_base[0]}, {Calificacion_base[0]}, {materia_sgu['CALIF']}, CURRENT_DATE, 'SGU')")
|
|
||||||
|
|
||||||
if not calificaciones or len(calificaciones) == 0:
|
|
||||||
raise Exception("No hay calificaciones para insertar o actualizar.")
|
|
||||||
|
|
||||||
# Inserción/actualización de calificaciones en la base de datos
|
|
||||||
with conexion.cursor() as cursor:
|
|
||||||
cursor.execute(f'''
|
|
||||||
insert into "Alumno_Materia_Calificacion"
|
|
||||||
("Usuario_claveULSA", "Materia_id", "Periodo_id", "TipoCalificacion_id", "Calificacion_calif", "Calificacion_fecha", "Calificacion_comentario")
|
|
||||||
values
|
|
||||||
{','.join(calificaciones)}
|
|
||||||
on conflict ("Usuario_claveULSA", "Materia_id", "Periodo_id", "TipoCalificacion_id")
|
|
||||||
DO UPDATE SET "Calificacion_calif" = EXCLUDED."Calificacion_calif", "Calificacion_comentario" = EXCLUDED."Calificacion_comentario";
|
|
||||||
''')
|
|
||||||
conexion.commit()
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error al insertar/actualizar las calificaciones: {e} Stack: {e.__traceback__}")
|
|
||||||
# print the whole stack
|
|
||||||
if conexion:
|
|
||||||
conexion.rollback() # Revertir cambios en caso de error
|
|
||||||
|
|
||||||
conexion.close()
|
|
||||||
Reference in New Issue
Block a user