From a7e78f292280383dc2d79d5ece2ac8a620fe5625 Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Fri, 5 Apr 2024 15:42:15 -0300 Subject: [PATCH 01/14] =?UTF-8?q?descripci=C3=B3n=20por=20nombre=20en=20ad?= =?UTF-8?q?m=20perfiles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/static/scripts/administracion-perfiles.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/static/scripts/administracion-perfiles.js b/frontend/static/scripts/administracion-perfiles.js index c84a3d2..5b16a44 100644 --- a/frontend/static/scripts/administracion-perfiles.js +++ b/frontend/static/scripts/administracion-perfiles.js @@ -119,7 +119,7 @@ gEt("administrar-perfiles").onclick = (e) => { ); let perfilElegido = tabla.entidades[indicePerfilElegido]; - modal.titulo = "Editar el perfil \"" + perfilElegido.descripcion+'"'; + modal.titulo = "Editar el perfil \"" + perfilElegido.descripcion + '"'; modal.contenido = [ new Formulario( "administracion-perfiles-editar", @@ -154,7 +154,7 @@ gEt("administrar-perfiles").onclick = (e) => { tab.rows[ indicePerfilElegido + 1 ].cells[0].innerHTML = `
${JSON.parse(txt).descripcion}
`; + }">
${JSON.parse(txt).descripcion}
`; tab.rows[indicePerfilElegido + 1].cells[1].innerText = JSON.parse(txt).permisoID == 1 ? "Usuario" @@ -221,7 +221,7 @@ gEt("botonAgregar").onclick = (e) => { [ { name: "nombre", - textoEtiqueta: "Nombre", + textoEtiqueta: "Descripción", type: "text", }, { From b51c319241c21968f9c428df391ed5de7cca1567 Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Fri, 5 Apr 2024 17:25:04 -0300 Subject: [PATCH 02/14] permisos en algunos lugares que faltaba y test rehecho --- api/v1/categoria.js | 14 +- api/v1/etiqueta.js | 5 +- api/v1/parametro.js | 50 +++---- api/v1/perfil.js | 180 +++++++++++----------- api/v1/post.js | 32 +++- api/v1/pregunta.js | 22 ++- package.json | 4 +- test.js | 355 -------------------------------------------- testApi.js | 73 +++++++++ 9 files changed, 238 insertions(+), 497 deletions(-) delete mode 100644 test.js create mode 100644 testApi.js diff --git a/api/v1/categoria.js b/api/v1/categoria.js index 657ccc4..adb086d 100644 --- a/api/v1/categoria.js +++ b/api/v1/categoria.js @@ -1,9 +1,9 @@ import * as express from "express"; import { - Etiqueta, - Categoria, - } from "./model.js"; - import { mensajeError401, mensajeError403, mensajeError404 } from "./mensajesError.js"; + Etiqueta, + Categoria, +} from "./model.js"; +import { mensajeError401, mensajeError403, mensajeError404 } from "./mensajesError.js"; const router = express.Router(); @@ -67,8 +67,8 @@ router.post("/", async (req, res) => { res.status(400).send(error.message); } }); - - // Ruta para actualizar una categoría por su ID + +// Ruta para actualizar una categoría por su ID router.patch("/:id", async (req, res) => { if (req.session.usuario.perfil.permiso.ID < 3) { res.status(401).send(mensajeError401); @@ -106,7 +106,7 @@ router.delete("/:id", async (req, res) => { res.status(500).send(error.message); } }); - + diff --git a/api/v1/etiqueta.js b/api/v1/etiqueta.js index 1afa45d..8371a46 100644 --- a/api/v1/etiqueta.js +++ b/api/v1/etiqueta.js @@ -199,7 +199,10 @@ router.delete("/:etiquetaID/suscripcion", function (req, res) { }); router.get("/masUsadas", function (req, res) { - + if (req.session.usuario.perfil.permiso.ID < 3) { + res.status(401).send(mensajeError401); + return; + } EtiquetasPregunta.findAll({ attributes: ["etiquetumID", [Sequelize.fn('COUNT', Sequelize.col('etiquetumID')), 'cantidad']], diff --git a/api/v1/parametro.js b/api/v1/parametro.js index d28289d..770db9e 100644 --- a/api/v1/parametro.js +++ b/api/v1/parametro.js @@ -3,7 +3,7 @@ import { Parametro, } from "./model.js"; -import {setModera, setRechazaPost, setReportaPost, setResultadosPorPagina} from "./parametros.js" +import { setModera, setRechazaPost, setReportaPost, setResultadosPorPagina } from "./parametros.js" import { mensajeError401 } from "./mensajesError.js"; const router = express.Router(); @@ -27,38 +27,31 @@ Parametro.findAll().then((ps) => { router.get("/", function (req, res) { + if (req.session.usuario.perfil.permiso.ID < 3) { + res.status(401).send(mensajeError401); + return; + } Parametro.findAll({ attributes: ["ID", "descripcion", "valor"] }).then((parametros) => { res.send(parametros); }); - - router.patch("/:ID", function (req, res) { - if (req.session.usuario.perfil.permiso.ID < 3) { - res.status(401).send(mensajeError401); - return; - } - if (!req.session.usuario) { - res - .status(403) - .send("No se poseen permisos de administración o sesión válida activa"); - return; - } else if (req.session.usuario.perfil.permiso.ID < 3) { - res - .status(403) - .send("No se poseen permisos de administración o sesión válida activa"); - return; - } - Parametro.findByPk(req.params.ID).then((p) => { - p.valor = req.body.valor; - p.save(); - res.status(200).send(p); - if (req.params.ID == 1) - setResultadosPorPagina(parseInt(req.body.valor)); - if (req.params.ID == 2) setModera(req.body.valor == "1"); - if (req.params.ID == 3) setRechazaPost(parseInt(req.body.valor)); - if (req.params.ID == 4) setReportaPost(parseInt(req.body.valor)); - }); +}); + +router.patch("/:ID", function (req, res) { + if (req.session.usuario.perfil.permiso.ID < 3) { + res.status(401).send(mensajeError401); + return; + } + Parametro.findByPk(req.params.ID).then((p) => { + p.valor = req.body.valor; + p.save(); + res.status(200).send(p); + if (req.params.ID == 1) + setResultadosPorPagina(parseInt(req.body.valor)); + if (req.params.ID == 2) setModera(req.body.valor == "1"); + if (req.params.ID == 3) setRechazaPost(parseInt(req.body.valor)); + if (req.params.ID == 4) setReportaPost(parseInt(req.body.valor)); }); }); @@ -66,4 +59,5 @@ router.get("/", function (req, res) { + export { router }; \ No newline at end of file diff --git a/api/v1/perfil.js b/api/v1/perfil.js index c383849..c0137f5 100644 --- a/api/v1/perfil.js +++ b/api/v1/perfil.js @@ -9,101 +9,105 @@ const router = express.Router(); // Ruta para crear un nuevo perfil router.post("/", async (req, res) => { - if (req.session.usuario.perfil.permiso.ID < 3) { - res.status(401).send(mensajeError401); - return; - } - const { nombre, color, permisoID } = req.body; - try { - const nuevoPerfil = await Perfil.create({ - descripcion: nombre, - color: color, - permisoID: permisoID, - }); - res.status(201).json(nuevoPerfil); - } catch (error) { - res.status(400).send(error.message); - } - }); - - // Ruta para actualizar un perfil por su ID - router.patch("/:id", async (req, res) => { - if (req.session.usuario.perfil.permiso.ID < 3) { - res.status(401).send(mensajeError401); - return; - } - const { id } = req.params; - const { nombre, color, permisoID } = req.body; - try { - const perfil = await Perfil.findByPk(id); - if (perfil) { - perfil.descripcion = nombre; - perfil.color = color; - perfil.permisoID = permisoID; - await perfil.save(); - if (req.session.usuario.perfil.ID == id) - req.session.usuario.perfil.color = color; - res.json(perfil); - } else { - res.status(404).send(mensajeError404); - } - } catch (error) { - res.status(400).send(error.message); - } - }); - - // Ruta para desactivar un perfil por su ID - router.patch("/:id/activado", async (req, res) => { - if (req.session.usuario.perfil.permiso.ID < 3) { - res.status(401).send(mensajeError401); - return; + if (req.session.usuario.perfil.permiso.ID < 3) { + res.status(401).send(mensajeError401); + return; + } + const { nombre, color, permisoID } = req.body; + try { + const nuevoPerfil = await Perfil.create({ + descripcion: nombre, + color: color, + permisoID: permisoID, + }); + res.status(201).json(nuevoPerfil); + } catch (error) { + res.status(400).send(error.message); + } +}); + +// Ruta para actualizar un perfil por su ID +router.patch("/:id", async (req, res) => { + if (req.session.usuario.perfil.permiso.ID < 3) { + res.status(401).send(mensajeError401); + return; + } + const { id } = req.params; + const { nombre, color, permisoID } = req.body; + try { + const perfil = await Perfil.findByPk(id); + if (perfil) { + perfil.descripcion = nombre; + perfil.color = color; + perfil.permisoID = permisoID; + await perfil.save(); + if (req.session.usuario.perfil.ID == id) + req.session.usuario.perfil.color = color; + res.json(perfil); + } else { + res.status(404).send(mensajeError404); } - const { id } = req.params; - try { - const perfil = await Perfil.findByPk(id); - if (perfil) { - perfil.activado = !perfil.activado; - await perfil.save(); - res.json(perfil); - } else { - res.status(404).send(mensajeError404); - } - } catch (error) { - res.status(400).send(error.message); + } catch (error) { + res.status(400).send(error.message); + } +}); + +// Ruta para desactivar un perfil por su ID +router.patch("/:id/activado", async (req, res) => { + if (req.session.usuario.perfil.permiso.ID < 3) { + res.status(401).send(mensajeError401); + return; + } + const { id } = req.params; + try { + const perfil = await Perfil.findByPk(id); + if (perfil) { + perfil.activado = !perfil.activado; + await perfil.save(); + res.json(perfil); + } else { + res.status(404).send(mensajeError404); } - }); + } catch (error) { + res.status(400).send(error.message); + } +}); + - - router.get("/", async (req, res) => { - try { - if(req.query.todos){ - const perfiles = await Perfil.findAll({ - include: { - model: Permiso, - attributes: ["ID", "descripcion"] - }, - attributes: ["ID", "color", "permisoID", "descripcion", "activado"] - }); - res.status(200).send(perfiles); - return; - } - let PAGINACION = getPaginacion(); - let pagina = req.query.pagina ? req.query.pagina : 0; - const perfiles = await Perfil.findAndCountAll({ - include: { +router.get("/", async (req, res) => { + if (req.session.usuario.perfil.permiso.ID < 3) { + res.status(401).send(mensajeError401); + return; + } + try { + if (req.query.todos) { + const perfiles = await Perfil.findAll({ + include: { model: Permiso, attributes: ["ID", "descripcion"] }, - attributes: ["ID", "color", "permisoID", "descripcion", "activado"], - limit: PAGINACION.resultadosPorPagina, - offset: - (+pagina * PAGINACION.resultadosPorPagina) + attributes: ["ID", "color", "permisoID", "descripcion", "activado"] }); - res.setHeader('untfaq-cantidad-paginas', Math.ceil(perfiles.count / parseInt(PAGINACION.resultadosPorPagina))); - res.status(200).send(perfiles.rows); - } catch (error) { - res.status(500).send(error.message); + res.status(200).send(perfiles); + return; } - }); + let PAGINACION = getPaginacion(); + let pagina = req.query.pagina ? req.query.pagina : 0; + const perfiles = await Perfil.findAndCountAll({ + include: { + model: Permiso, + attributes: ["ID", "descripcion"] + }, + attributes: ["ID", "color", "permisoID", "descripcion", "activado"], + limit: PAGINACION.resultadosPorPagina, + offset: + (+pagina * PAGINACION.resultadosPorPagina) + }); + res.setHeader('untfaq-cantidad-paginas', Math.ceil(perfiles.count / parseInt(PAGINACION.resultadosPorPagina))); + res.status(200).send(perfiles.rows); + } catch (error) { + res.status(500).send(error.message); + } +}); export { router }; \ No newline at end of file diff --git a/api/v1/post.js b/api/v1/post.js index 8dc3703..b928404 100644 --- a/api/v1/post.js +++ b/api/v1/post.js @@ -31,14 +31,14 @@ router.post("/:votadoID/valoracion", function (req, res) { // TODO Refactor: ver si es posible traer solo un si existe let IDvotado = req.params.votadoID; - Post.findByPk(IDvotado,{include:{model:Usuario,as:'duenio',attributes:['DNI']}}) + Post.findByPk(IDvotado, { include: { model: Usuario, as: 'duenio', attributes: ['DNI'] } }) .then((post) => { if (!post) { res.status(404).send(mensajeError404); return; } - if(post.duenio.DNI==req.session.usuario.DNI){ + if (post.duenio.DNI == req.session.usuario.DNI) { res.status(400).send('No puede votar su propio contenido.'); return; } @@ -53,7 +53,7 @@ router.post("/:votadoID/valoracion", function (req, res) { }).then((voto) => { // TODO Refactor: !req.body.valoracion ?? // TODO Docs: Comentar esta condición - if(!voto && req.body.valoracion == "null"){ + if (!voto && req.body.valoracion == "null") { res.status(400).send(mensajeError400); return; } @@ -62,12 +62,12 @@ router.post("/:votadoID/valoracion", function (req, res) { if (voto) { voto.valoracion = req.body.valoracion; - esperarA=voto.save(); + esperarA = voto.save(); //Notificación } else { // * si no exite el voto lo crea con lo que mandó - // if (req.body.valoracion) { - // } - esperarA=Promise.all([ + // if (req.body.valoracion) { + // } + esperarA = Promise.all([ Voto.create({ valoracion: req.body.valoracion, votadoID: IDvotado, @@ -80,7 +80,7 @@ router.post("/:votadoID/valoracion", function (req, res) { ]) } - esperarA.then(()=>res.status(201).send("Voto registrado.")) + esperarA.then(() => res.status(201).send("Voto registrado.")) }); }) .catch((err) => { @@ -236,6 +236,10 @@ router.patch('/:ID/restaurar', (req, res) => { router.get('/reporte', function (req, res) { + if (req.session.usuario.perfil.permiso.ID < 2) { + res.status(403).send(mensajeError403); + return; + } let pagina = req.query.pagina || 0; let PAGINACION = getPaginacion(); ReportePost.findAndCountAll({ @@ -312,6 +316,10 @@ router.get('/reporte', function (req, res) { }) router.get("/borrados", function (req, res) { + if (req.session.usuario.perfil.permiso.ID < 2) { + res.status(403).send(mensajeError403); + return; + } Post.findAll({ where: { eliminadorDNI: { @@ -373,6 +381,10 @@ router.get("/borrados", function (req, res) { router.get("/masNegativos", function (req, res) { + if (req.session.usuario.perfil.permiso.ID < 3) { + res.status(403).send(mensajeError403); + return; + } Post.findAll({ attributes: [[Sequelize.fn('SUM', Sequelize.col('valoracion')), 'valoracion'], 'cuerpo', 'ID'], include: [ @@ -435,6 +447,10 @@ router.get("/masNegativos", function (req, res) { router.get("/estadisticas", async function (req, res) { + if (req.session.usuario.perfil.permiso.ID < 2) { + res.status(403).send(mensajeError403); + return; + } //con promises en vez de await porque son muchas consultas y tarda mucho si no las hace en paralelo const obtenerEstadisticas = async () => { const estadisticas = [ diff --git a/api/v1/pregunta.js b/api/v1/pregunta.js index fc0e3e9..67988d7 100644 --- a/api/v1/pregunta.js +++ b/api/v1/pregunta.js @@ -3,7 +3,7 @@ import { Sequelize } from "sequelize"; import { moderarWithRetry } from "./ia.js"; import { Usuario, - ReportePost,TipoReporte, + ReportePost, TipoReporte, Pregunta, SuscripcionesPregunta, Post, @@ -260,10 +260,12 @@ router.put('/:ID', function (req, res) { Pregunta.findByPk(req.params.ID, { include: [ - { model: Post, include:[ - {model: Usuario, as: 'eliminador' } - ,{model:ReportePost,include:{model:TipoReporte, as:'tipo',where:{ID:2}, attributes:[]}} // ! 2 es pregunta repetida - ] }, + { + model: Post, include: [ + { model: Usuario, as: 'eliminador' } + , { model: ReportePost, include: { model: TipoReporte, as: 'tipo', where: { ID: 2 }, attributes: [] } } // ! 2 es pregunta repetida + ] + }, { model: Respuesta, as: 'respuestas', include: Post }, // TODO Refactor: Algún ENUM de tipos de reportes ] @@ -281,10 +283,10 @@ router.put('/:ID', function (req, res) { if (pre.respuestas.length) { esperarA.push(...pre.respuestas.map(resp => resp.setPregunta(preguntaReemplazoID).then(r => r.save()))); } - + esperarA.push(pre.post.setEliminador(usuarioActual.DNI).then(p => p.save())); - - esperarA.push(pre.post.getReportePosts().then(reportes=>Promise.all(reportes.map(reporte => reporte.destroy())))); + + esperarA.push(pre.post.getReportePosts().then(reportes => Promise.all(reportes.map(reporte => reporte.destroy())))); Promise.all(esperarA).then(() => { res.send(); @@ -384,6 +386,10 @@ router.delete("/:preguntaID/suscripcion", function (req, res) { }); router.get("/masVotadas", function (req, res) { + if (req.session.usuario.perfil.permiso.ID < 3) { + res.status(403).send(mensajeError403); + return; + } let resultadosPorPagina = getPaginacion().resultadosPorPagina; const respuestasCount = [ Sequelize.literal( diff --git a/package.json b/package.json index eb2038d..224469f 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "server.js", "type": "module", "scripts": { - "test": "mocha test.js --timeout 15000", + "test": "mocha testApi.js --timeout 15000", "start": "nodemon server.js" }, "keywords": [], @@ -33,4 +33,4 @@ "devDependencies": { "nodemon": "3.0.2" } -} +} \ No newline at end of file diff --git a/test.js b/test.js deleted file mode 100644 index 64facc7..0000000 --- a/test.js +++ /dev/null @@ -1,355 +0,0 @@ -import axios from 'axios'; -import assert from 'assert'; - -const baseURL = 'http://localhost:8080'; // Update the port or base URL according to your API - -let sessionCookie = null; - -const makeRequest = async (method, url, data = {}, headers = {}) => { - try { - const response = await axios({ - method, - url: baseURL + url, - data, - headers: { - ...headers, - Cookie: sessionCookie, - }, - }); - - if (response.headers['set-cookie']) { - sessionCookie = response.headers['set-cookie'][0].split(';')[0]; - } - - return response; - } catch (error) { - return error.response || { status: 500 }; // Default status code if response is undefined - } -}; - -describe('Express API Tests', () => { - // Test: User Login (Expecting 200) - it('post - login200', async () => { - const response = await makeRequest('post', '/api/sesion', { - DNI: '41097334', - contrasenia: '12345678', - }); - - assert.strictEqual(response.status, 200); - }); - - // Test: User Report (Expecting 404) - it('post - usuarioReporte404', async () => { - const response = await makeRequest('post', '/api/usuario/4/reporte'); - - assert.strictEqual(response.status, 404); - }); - - // Test: User Report (Expecting 201) - it('post - usuarioReporte201', async () => { - const response = await makeRequest('post', '/api/usuario/41097335/reporte'); - - assert.strictEqual(response.status, 201); - }); - - // Test: Answer Report (Expecting 404) - it('post - reporteRespuesta404', async () => { - const response = await makeRequest('post', '/api/respuesta/9999999999999/reporte', { - tipo: 1, - }); - - assert.strictEqual(response.status, 404); - }); - - // Test: Question Report (Expecting 404) - it('post - reportePregunta404', async () => { - const response = await makeRequest('post', '/api/pregunta/9999999999999/reporte', { - tipo: 1, - }); - - assert.strictEqual(response.status, 404); - }); - - // Test: Answer Report (Expecting 201) - it('post - reporteRespuesta201', async () => { - const response = await makeRequest('post', '/api/post/23/reporte', { - tipo: 1, - }); - - assert.strictEqual(response.status, 201); - }); - - // Test: Question Report (Expecting 201) - it('post - reportePregunta201', async () => { - const response = await makeRequest('post', '/api/post/9/reporte', { - tipo: 1, - }); - - assert.strictEqual(response.status, 201); - }); - - // Test: Question without Report (Expecting 201) - it('post - pregunta200SinReporte', async () => { - const response = await makeRequest('post', '/api/pregunta', { - titulo: '¿Que días se rinde Análisis Matemático?', - cuerpo: 'Así me organizo mejor.', - etiquetasIDs:[3,4,5] - }); - - assert.strictEqual(response.status, 201); - }); - - // Test: Question (Expecting 400) - it('post - pregunta400', async () => { - const response = await makeRequest('post', '/api/pregunta', { - titulo: '¿Que días se rinde Análisis Matemático?', - cuerpo: 'hijos de puta', - etiquetasIDs:[3,4,5] - }); - - assert.strictEqual(response.status, 400); - }); - - // Test: Update Question (Expecting 200) - it('patch - pregunta200', async () => { - const response = await makeRequest('patch', '/api/pregunta', { - ID: 9, - cuerpo: 'probando', - titulo: '¿que dia se rinde analisis?', - etiquetasIDs:[3,4,6] - }); - - assert.strictEqual(response.status, 200); - }); - - // Test: Update Question (Expecting 403) - it('patch - pregunta403', async () => { - const response = await makeRequest('patch', '/api/pregunta', { - ID: 3, - cuerpo: 'probando', - titulo: '¿que dia se rinde analisis?', - etiquetasIDs:[3,4,5] - }); - - assert.strictEqual(response.status, 403); - }); - - // Test: Update Question (Expecting 404) - it('patch - pregunta404', async () => { - const response = await makeRequest('patch', '/api/pregunta', { - ID: 2, - cuerpo: 'probando', - titulo: '¿que dia se rinde analisis?', - etiquetasIDs:[3,4,5] - }); - - assert.strictEqual(response.status, 404); - }); - - - // Test: Update Question (Expecting 400) - it('patch - pregunta400', async () => { - const response = await makeRequest('patch', '/api/pregunta', { - ID: '9', - cuerpo: 'pelados puttos', - titulo: '¿que dia se rinde analisis?', - etiquetasIDs:[3,4,5] - }); - - assert.strictEqual(response.status, 400); - }); - - // Test: Create Answer (Expecting 404) - it('post - respuesta404', async () => { - const response = await makeRequest('post', '/api/respuesta', { - IDPregunta: 2, - cuerpo: 'hola', - }); - - assert.strictEqual(response.status, 404); - }); - - // Test: Create Answer (Expecting 404) - it('post - respuesta404', async () => { - const response = await makeRequest('post', '/api/respuesta', { - IDPregunta: 2, - cuerpo: 'hola', - }); - - assert.strictEqual(response.status, 404); - }); - - // Test: Create Answer (Expecting 400) - it('post - respuesta400', async () => { - const response = await makeRequest('post', '/api/respuesta', { - IDPregunta: 3, - cuerpo: 'no te anotes con x es un hijo de puta', - }); - - assert.strictEqual(response.status, 400); - }); - - // Test: Create Answer (Expecting 201) - it('post - respuesta201', async () => { - const response = await makeRequest('post', '/api/respuesta', { - IDPregunta: 3, - cuerpo: 'Los lunes a las 15 horas', - }); - - assert.strictEqual(response.status, 201); - }); - - // Test: Update Answer (Expecting 400) - it('patch - respuesta400', async () => { - const response = await makeRequest('patch', '/api/respuesta', { - ID: 23, - cuerpo: 'quiero drogas', - }); - - assert.strictEqual(response.status, 400); - }); - - // Test: Update Answer (Expecting 404) - it('patch - respuesta404', async () => { - const response = await makeRequest('patch', '/api/respuesta', { - ID: 1, - cuerpo: 'holaaaaaaaaaa', - }); - - assert.strictEqual(response.status, 404); - }); - - // Test: Update Answer (Expecting 403) - it('patch - respuesta403', async () => { - const response = await makeRequest('patch', '/api/respuesta', { - ID: 2, - cuerpo: 'holaaaaaaaaaa', - }); - - assert.strictEqual(response.status, 403); - }); - - // Test: Update Answer (Expecting 200) - it('patch - respuesta200', async () => { - const response = await makeRequest('patch', '/api/respuesta', { - ID: 23, - cuerpo: 'holaaaaaaaaaa', - }); - - assert.strictEqual(response.status, 200); - }); - - it('post - Suscripcion Etiqueta 201', async () => { - const response = await makeRequest('post', '/api/etiqueta/2/suscripcion'); - - assert.strictEqual(response.status, 201); - }); - - it('post - Suscripcion Pregunta 201', async () => { - const response = await makeRequest('post', '/api/pregunta/9/suscripcion'); - - assert.strictEqual(response.status, 201); - }); - - it('post - Suscripcion Pregunta 404', async () => { - const response = await makeRequest('post', '/api/pregunta/999999999999/suscripcion'); - - assert.strictEqual(response.status, 404); - }); - - it('delete - Suscripcion Pregunta 201', async () => { - const response = await makeRequest('delete', '/api/pregunta/9/suscripcion'); - - assert.strictEqual(response.status, 201); - }); - - it('post - Suscripcion Etiqueta 404', async () => { - const response = await makeRequest('post', '/api/etiqueta/1/suscripcion'); - - assert.strictEqual(response.status, 404); - }); - - - it('delete - Suscripcion Etiqueta 201', async () => { - const response = await makeRequest('delete', '/api/etiqueta/2/suscripcion'); - - assert.strictEqual(response.status, 201); - }); - - it('post - Login 404', async () => { - const response = await makeRequest('post', '/api/sesion', { - DNI: '1', - contrasenia: '12345679', - }); - - assert.strictEqual(response.status, 404); - }); - - it('post - Login 401', async () => { - const response = await makeRequest('post', '/api/sesion', { - DNI: '41097334', - contrasenia: '12345679', - }); - - assert.strictEqual(response.status, 401); - }); - - it('post - Login 200', async () => { - const response = await makeRequest('post', '/api/sesion', { - DNI: '41097334', - contrasenia: '12345678', - }); - - assert.strictEqual(response.status, 200); - }); - - it('post - Crear Usuario 400', async () => { - const response = await makeRequest('post', '/api/usuario', { - nombre: 'Matias Matias', - DNI: '41097335', - correo: 'matiasbais1998@gmail.com', - contrasenia: '12345678', - }); - - assert.strictEqual(response.status, 400); - }); - - it('post - Resetear Contrasenia 200', async () => { - const response = await makeRequest('post', '/api/usuario/41097335/contrasenia'); - - assert.strictEqual(response.status, 200); - }); - - it('patch - Cambiar Contrasenia 200', async () => { - const response = await makeRequest('patch', '/api/usuario', { - contrasenia: '12345678', - }); - - assert.strictEqual(response.status, 200); - }); - - it('get - Buscar Usuario 200', async () => { - const response = await makeRequest('get', '/api/usuario', { - nombre: 'Matias', - pagina: 0, - }); - - assert.strictEqual(response.status, 200); - }); - - it('get - Buscar Usuario 404', async () => { - const response = await makeRequest('get', '/api/usuario', { - nombre: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - pagina: 0, - }); - - assert.strictEqual(response.status, 404); - }); - - it('delete - Log Out 200', async () => { - const response = await makeRequest('delete', '/api/sesion'); - - assert.strictEqual(response.status, 200); - }); - -}); diff --git a/testApi.js b/testApi.js new file mode 100644 index 0000000..1f32ed1 --- /dev/null +++ b/testApi.js @@ -0,0 +1,73 @@ +import axios from 'axios'; +import assert from 'assert'; + +const baseURL = 'http://localhost:8080'; // Update the port or base URL according to your API + +let sessionCookie = null; + +const makeRequest = async (method, url, data = {}, headers = {}) => { + try { + const response = await axios({ + method, + url: baseURL + url, + data, + headers: { + ...headers, + Cookie: sessionCookie, + }, + }); + + if (response.headers['set-cookie']) { + sessionCookie = response.headers['set-cookie'][0].split(';')[0]; + } + + return response; + } catch (error) { + return error.response || { status: 500 }; // Default status code if response is undefined + } +}; + +const testData = [ + { method: 'post', url: '/api/sesion', body: { DNI: '4385139', contrasenia: '4385139' }, expectedStatus: 200 }, + { method: 'get', url: '/api/usuario/', expectedStatus: 403 }, + { method: 'post', url: '/api/usuario/123/bloqueo', expectedStatus: 401 }, + { method: 'delete', url: '/api/usuario/123/bloqueo', expectedStatus: 401 }, + { method: 'patch', url: '/api/usuario/123', expectedStatus: 401 }, + { method: 'delete', url: '/api/sesion', expectedStatus: 200 }, + { method: 'post', url: '/api/sesion', body: { DNI: '78249503218', contrasenia: '78249503218' }, expectedStatus: 200 }, + { method: 'patch', url: '/api/usuario/123', expectedStatus: 401 }, + { method: 'post', url: '/api/sesion', body: { DNI: '4385139', contrasenia: '4385139' }, expectedStatus: 200 }, + { method: 'patch', url: '/api/notificacion', body: { ID: '2' }, expectedStatus: 403 }, + { method: 'get', url: '/api/parametro', expectedStatus: 401 }, + { method: 'patch', url: '/api/parametro/1', expectedStatus: 401 }, + { method: 'post', url: '/api/perfil/', expectedStatus: 401 }, + { method: 'patch', url: '/api/perfil/123', expectedStatus: 401 }, + { method: 'patch', url: '/api/perfil/123/activado', expectedStatus: 401 }, + { method: 'get', url: '/api/perfil/', expectedStatus: 401 }, + { method: 'post', url: '/api/post/272/valoracion', expectedStatus: 400 }, + { method: 'get', url: '/api/post/reporte', expectedStatus: 403 }, + { method: 'get', url: '/api/post/borrados', expectedStatus: 403 }, + { method: 'get', url: '/api/post/masNegativos', expectedStatus: 403 }, + { method: 'get', url: '/api/post/estadisticas', expectedStatus: 403 }, + { method: 'patch', url: '/api/pregunta', body: { ID: '290' }, expectedStatus: 403 }, + { method: 'put', url: '/api/pregunta/290', expectedStatus: 403 }, + { method: 'get', url: '/api/pregunta/masVotadas', expectedStatus: 403 }, + { method: 'post', url: '/api/categoria/', expectedStatus: 401 }, + { method: 'patch', url: '/api/categoria/1/activado', expectedStatus: 401 }, + { method: 'patch', url: '/api/categoria/1', expectedStatus: 401 }, + { method: 'post', url: '/api/etiqueta/', expectedStatus: 401 }, + { method: 'patch', url: '/api/etiqueta/1/activado', expectedStatus: 401 }, + { method: 'patch', url: '/api/etiqueta/1', expectedStatus: 401 }, + { method: 'get', url: '/api/etiqueta/masUsadas', expectedStatus: 401 } + +]; + +describe('Express API Tests', () => { + testData.forEach(data => { + const bodyString = data.body ? JSON.stringify(data.body) : ''; + it(`${data.method.toUpperCase()} - ${data.url} ${bodyString ? 'with body ' + bodyString : ''}`, async () => { + const response = await makeRequest(data.method, data.url, data.body); + assert.strictEqual(response.status, data.expectedStatus); + }); + }); +}); \ No newline at end of file From 93053fefdd928905777fa3558ba70de7ed45133d Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Mon, 8 Apr 2024 15:29:25 -0300 Subject: [PATCH 03/14] =?UTF-8?q?fix=20cambiar=20contrase=C3=B1a=20y=20cor?= =?UTF-8?q?reo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/model.js | 27 +++++++++++++-------------- api/v1/usuario.js | 37 +++++++++++++++++++++---------------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/api/v1/model.js b/api/v1/model.js index f55fac3..896a851 100644 --- a/api/v1/model.js +++ b/api/v1/model.js @@ -689,10 +689,10 @@ Pregunta.pagina = ({ pagina = 0, duenioID: duenioDNI, filtrar, formatoCorto, usu `match(titulo) against (:where_titulo IN BOOLEAN MODE)` ) ) - let valorAgainstMatch=`${filtrar.texto}*`; - opciones.replacements={ - where_cuerpo:valorAgainstMatch - ,where_titulo:valorAgainstMatch + let valorAgainstMatch = `${filtrar.texto}*`; + opciones.replacements = { + where_cuerpo: valorAgainstMatch + , where_titulo: valorAgainstMatch }; filtrarTexto = true; } @@ -721,12 +721,12 @@ Pregunta.pagina = ({ pagina = 0, duenioID: duenioDNI, filtrar, formatoCorto, usu } } ); - if(!opciones.replacements) - opciones.replacements={}; - let variablesEnConsulta=filtrar.etiquetas.map(eti=>{ - let nombreVariable='eti_'+eti - opciones.replacements[nombreVariable]=eti; - return ':'+nombreVariable; + if (!opciones.replacements) + opciones.replacements = {}; + let variablesEnConsulta = filtrar.etiquetas.map(eti => { + let nombreVariable = 'eti_' + eti + opciones.replacements[nombreVariable] = eti; + return ':' + nombreVariable; }); opciones.attributes.include.push( [ @@ -762,8 +762,8 @@ Pregunta.pagina = ({ pagina = 0, duenioID: duenioDNI, filtrar, formatoCorto, usu if (filtrarTexto) { ranking.push(`(match(post.cuerpo) against (:order_cuerpo IN BOOLEAN MODE) + match(titulo) against (:order_titulo IN BOOLEAN MODE)*2)`); // * En la definición del where se establece replacements con un par de el mismo valor. - opciones.replacements['order_cuerpo']= - opciones.replacements['order_titulo']= + opciones.replacements['order_cuerpo'] = + opciones.replacements['order_titulo'] = opciones.replacements['where_cuerpo'] } if (filtrarEtiquetas) { @@ -1004,7 +1004,7 @@ Respuesta.pagina = ({ pagina = 0, DNI } = {}) => { fecha_baja: null, // * Vigentes } , required: false - ,separate: true + , separate: true } ], attributes: { @@ -1252,7 +1252,6 @@ Parametro.findAll().then((parametros) => { }); }); - export { Parametro, Carrera, diff --git a/api/v1/usuario.js b/api/v1/usuario.js index 0ee7cc7..3147ed5 100644 --- a/api/v1/usuario.js +++ b/api/v1/usuario.js @@ -190,7 +190,7 @@ router.get("/:DNI/respuestas", function (req, res) { } Respuesta.pagina({ pagina, DNI: req.params.DNI }) - .then((posts) =>res.send(posts)); + .then((posts) => res.send(posts)); }); router.post("/", (req, res) => { @@ -455,16 +455,19 @@ router.patch("/imagen", upload.single("image"), function (req, res) { res.status(200).send("Imagen Actualizada"); }); -router.patch("/contrasenia", function (req, res) { +router.patch("/contrasenia", async function (req, res) { Usuario.findByPk(req.session.usuario.DNI) .then((usuario) => { - if (bcrypt.compare(req.body.contraseniaAnterior, usuario.contrasenia)) { - usuario.contrasenia = req.body.contraseniaNueva; - req.session.usuario.contrasenia = req.body.contraseniaNueva; - usuario.save(); - res.status(200).send("Datos actualizados exitosamente"); - return; - } + bcrypt.compare(req.body.contraseniaAnterior, usuario.contrasenia).then(coinciden => { + if (coinciden) { + usuario.contrasenia = req.body.contraseniaNueva; + req.session.usuario.contrasenia = req.body.contraseniaNueva; + usuario.save(); + res.status(200).send("Datos actualizados exitosamente"); + return; + } + }); + res.status(402).send("Contraseña anterior no válida") }) .catch((err) => { @@ -475,13 +478,15 @@ router.patch("/contrasenia", function (req, res) { router.patch("/mail", function (req, res) { Usuario.findByPk(req.session.usuario.DNI) .then((usuario) => { - if (bcrypt.compare(req.body.contrasenia, usuario.contrasenia)) { - usuario.correo = req.body.correo; - req.session.usuario.correo = req.body.correo; - usuario.save(); - res.status(200).send("Datos actualizados exitosamente"); - return; - } + bcrypt.compare(req.body.contrasenia, usuario.contrasenia).then(coinciden => { + if (coinciden) { + usuario.correo = req.body.correo; + req.session.usuario.correo = req.body.correo; + usuario.save(); + res.status(200).send("Datos actualizados exitosamente"); + return; + } + }); res.status(402).send("Contraseña anterior no válida") }) .catch((err) => { From 04faefc2a0a52823b624917892b9880d08dad5f9 Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Mon, 8 Apr 2024 17:15:04 -0300 Subject: [PATCH 04/14] prohibido acceso usuarios bloqueados --- api/v1/sesion.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/api/v1/sesion.js b/api/v1/sesion.js index 2f729e7..5b44a2f 100644 --- a/api/v1/sesion.js +++ b/api/v1/sesion.js @@ -1,5 +1,6 @@ import * as express from "express"; -import { Usuario, Perfil, Permiso, Carrera } from "./model.js" +import { Sequelize } from "sequelize"; +import { Usuario, Perfil, Permiso, Carrera, Bloqueo } from "./model.js" import * as bcrypt from "bcrypt"; @@ -12,6 +13,13 @@ router.post("/", function (req, res) { include: Permiso, }, { model: Carrera + }, { + model: Bloqueo, + as: "bloqueosRecibidos", + where: { + fecha_desbloqueo: { [Sequelize.Op.is]: null } + }, + required: false }] }) .then((usu) => { @@ -25,6 +33,10 @@ router.post("/", function (req, res) { }) .then((coinciden) => { if (coinciden) { + if (usuario.bloqueosRecibidos) { + res.status(402).send("Usuario bloqueado") + return; + } req.session.usuario = usuario; res.status(200).send(); return; From a997a7264af4fae78039989c7233e50823f184a0 Mon Sep 17 00:00:00 2001 From: c3r38r170 Date: Mon, 8 Apr 2024 17:15:45 -0300 Subject: [PATCH 05/14] Evitados reportes de preguntas eliminadas. Pasado de suscripciones al unificar. --- api/v1/post.js | 4 ++++ api/v1/pregunta.js | 14 ++++++++++---- frontend/static/scripts/index.js | 2 -- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/api/v1/post.js b/api/v1/post.js index 8dc3703..474ee77 100644 --- a/api/v1/post.js +++ b/api/v1/post.js @@ -248,6 +248,10 @@ router.get('/reporte', function (req, res) { attributes: ['cuerpo', 'fecha'], required: true, as: 'reportado', + // TODO Refactor: DRY sobre las cuestiones de eliminar cosas + where:{ + eliminadorDNI:null + }, include: [ { model: Usuario diff --git a/api/v1/pregunta.js b/api/v1/pregunta.js index fc0e3e9..b678b23 100644 --- a/api/v1/pregunta.js +++ b/api/v1/pregunta.js @@ -262,8 +262,9 @@ router.put('/:ID', function (req, res) { include: [ { model: Post, include:[ {model: Usuario, as: 'eliminador' } - ,{model:ReportePost,include:{model:TipoReporte, as:'tipo',where:{ID:2}, attributes:[]}} // ! 2 es pregunta repetida + // ,{model:ReportePost,include:{model:TipoReporte, as:'tipo',attributes:[]}} ] }, + {model:SuscripcionesPregunta,as:'suscripciones'}, { model: Respuesta, as: 'respuestas', include: Post }, // TODO Refactor: Algún ENUM de tipos de reportes ] @@ -276,16 +277,21 @@ router.put('/:ID', function (req, res) { } // TODO Refactor: Ver si es posible simplificar - let esperarA = [], preguntaReemplazoID = req.body.duplicadaID; + let esperarA = [] + , preguntaReemplazoID = req.body.duplicadaID; if (pre.respuestas.length) { esperarA.push(...pre.respuestas.map(resp => resp.setPregunta(preguntaReemplazoID).then(r => r.save()))); } esperarA.push(pre.post.setEliminador(usuarioActual.DNI).then(p => p.save())); - - esperarA.push(pre.post.getReportePosts().then(reportes=>Promise.all(reportes.map(reporte => reporte.destroy())))); + // TODO Feature: Test this. + esperarA.push(pre.getSuscripciones().then(suscripciones=>Promise.all(suscripciones.map(suscripcion => suscripcion.setPregunta(preguntaReemplazoID).then(s => s.save()))))); + + // TODO Feature: ¿Pasar reportes de otras índoles? + // esperarA.push(pre.post.getReportePosts().then(reportes=>Promise.all(reportes.map(reporte => reporte.tipoID==2?/* ! 2 es pregunta repetida */reporte.destroy())))); + Promise.all(esperarA).then(() => { res.send(); }) diff --git a/frontend/static/scripts/index.js b/frontend/static/scripts/index.js index 616611c..9f54651 100644 --- a/frontend/static/scripts/index.js +++ b/frontend/static/scripts/index.js @@ -8,13 +8,11 @@ inicializarListas(); //Al clickear etiqueta la agrega a la busqueda - if (window.location.href.includes("searchInput") || window.location.href.includes("etiquetas")) { document.addEventListener('click', function (event) { // Evitar el comportamiento predeterminado del clic - if (event.target.className == "tag") { event.preventDefault(); From da367b530882384a503f13ba793769acb287d302 Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Mon, 8 Apr 2024 17:23:25 -0300 Subject: [PATCH 06/14] fix usuarios bloqueados --- api/v1/sesion.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/sesion.js b/api/v1/sesion.js index 5b44a2f..0a18af3 100644 --- a/api/v1/sesion.js +++ b/api/v1/sesion.js @@ -33,7 +33,7 @@ router.post("/", function (req, res) { }) .then((coinciden) => { if (coinciden) { - if (usuario.bloqueosRecibidos) { + if (usuario.bloqueosRecibidos.length > 0) { res.status(402).send("Usuario bloqueado") return; } From a04de31a5358610d1cc41c3275e910d1e84e66a1 Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Mon, 8 Apr 2024 17:27:02 -0300 Subject: [PATCH 07/14] =?UTF-8?q?descripcion=20en=20olvide=20mi=20contrase?= =?UTF-8?q?=C3=B1a?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/static/componentes/pagina.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/static/componentes/pagina.js b/frontend/static/componentes/pagina.js index 7542ab7..98c63c8 100644 --- a/frontend/static/componentes/pagina.js +++ b/frontend/static/componentes/pagina.js @@ -1,4 +1,4 @@ -import { ChipUsuario, DesplazamientoInfinito, MensajeInterfaz, Titulo, Formulario, Notificacion, Navegacion, Breadcrumb, Boton, Modal } from './todos.js' +import { ChipUsuario, DesplazamientoInfinito, MensajeInterfaz, Titulo, Formulario, Notificacion, Navegacion, Breadcrumb, Boton, Modal, ComponenteLiteral } from './todos.js' // TODO Feature: Tirar errores en los constructores con parámetros necesarios // TODO Refactor: Cambiar a Pantalla. Colisiona con el concepto de página de los modelos. @@ -271,6 +271,8 @@ class Encabezado { ); this.#modalLogin.contenido.push(formLogin); this.#modalLogin.contenido.push(new Boton({ titulo: 'Olvidé mi Contraseña', classes: 'mt-3 is-rounded js-modal-trigger olvide-contrasenia', dataTarget: 'modal-resetear-contrasenia' })) + this.#modalResetearContrasenia.contenido.push(new ComponenteLiteral(() => + "

Ingrese su DNI y mail y una nueva contraseña le será enviada al mismo


")); this.#modalRegistro.contenido.push(formRegistro); this.#modalResetearContrasenia.contenido.push(formResetearContrasenia) } From 2f7d6c66e1ab56e676e8ee532bef6a94a542f479 Mon Sep 17 00:00:00 2001 From: c3r38r170 Date: Mon, 8 Apr 2024 17:27:56 -0300 Subject: [PATCH 08/14] =?UTF-8?q?Suscripciones=20en=20la=20p=C3=A1gina=20d?= =?UTF-8?q?e=20la=20pregunta.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/router.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/frontend/router.js b/frontend/router.js index c51cfe6..6a774c7 100644 --- a/frontend/router.js +++ b/frontend/router.js @@ -136,8 +136,9 @@ router.get("/pregunta/:id?", async (req, res) => { model: EtiquetaDAO, include: { model: Categoria, as: "categoria" }, } - }, + } // TODO Refactor: Agregar la condición de suscripciones solo si req.session.usuario.DNI está definido. No hace falta traer todas, sino solo la que nos interesa. Ver voto como ejemplo. + /* , { model: UsuarioDAO , as: 'usuariosSuscriptos', @@ -147,9 +148,25 @@ router.get("/pregunta/:id?", async (req, res) => { fecha_baja: null // Condición para que la fecha de baja sea nula } } - } + } */ ]; + // TODO Refactor: Evitar chequear antes y después. + if(req.session.usuario){ + include.push( + // TODO Refactor: DRY, esto se repite en Pregunta.pagina + { + model:SuscripcionesPreguntaDAO + ,as:'suscripciones' + , include: { model: UsuarioDAO, as: 'suscripto', where: { DNI: req.session.usuario.DNI }, attributes: [] } + , where: { + fecha_baja: null // * Vigentes + } + ,required:false + } + ) + } + const p = await PreguntaDAO.findByPk(req.params.id, { include }); if (!p) { @@ -162,6 +179,7 @@ router.get("/pregunta/:id?", async (req, res) => { res.redirect('/'); return; } + NotificacionDAO.findAll({ include: [ { @@ -189,7 +207,7 @@ router.get("/pregunta/:id?", async (req, res) => { } else if (p.post.eliminadorDNI) { - // No está logueado y la pregunta esta eliminada + // * No está logueado y la pregunta esta eliminada res.redirect('/'); return; } From 81069ec870dab04c3adcae4143cb84b13aaa9d20 Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Mon, 8 Apr 2024 17:29:13 -0300 Subject: [PATCH 09/14] no mas alerts --- .../scripts/moderacion-posts-borrados.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/static/scripts/moderacion-posts-borrados.js b/frontend/static/scripts/moderacion-posts-borrados.js index 38d9808..5013d1f 100644 --- a/frontend/static/scripts/moderacion-posts-borrados.js +++ b/frontend/static/scripts/moderacion-posts-borrados.js @@ -13,7 +13,7 @@ tabla.iniciar(); let modalElemento = gEt("modal-general"); modalElemento.addEventListener("submit", () => { - modalElemento.classList.remove("is-active"); + modalElemento.classList.remove("is-active"); }); @@ -22,20 +22,20 @@ gEt('posts-borrados').onclick = (e) => { console.log(e.target); if (t.type != "button") { return; - } + } e.preventDefault(); let postID = t.getAttribute('data-id'); modal.titulo = "Restaurar Post"; - modal.contenido = [ - new ComponenteLiteral( + modal.contenido = [ + new ComponenteLiteral( () => `

Vas a restaurar el post #${postID}


` - ), - new Formulario('restaurarPost' + postID, '/api/post/' + postID + '/restaurar', [], (res) => { alert(res), location.reload() }, { textoEnviar: 'Restaurar', verbo: 'PATCH', clasesBoton: 'mx-auto is-link w-100' }) + ), + new Formulario('restaurarPost' + postID, '/api/post/' + postID + '/restaurar', [], (res) => { Swal.exito(res), location.reload() }, { textoEnviar: 'Restaurar', verbo: 'PATCH', clasesBoton: 'mx-auto is-link w-100' }) + + ]; + modal.redibujar(); + modalElemento.classList.add("is-active"); - ]; - modal.redibujar(); - modalElemento.classList.add("is-active"); - } \ No newline at end of file From aa37dad8acee9cc20aa16cd2be2d0ceb0096476a Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Mon, 8 Apr 2024 17:32:44 -0300 Subject: [PATCH 10/14] no mas posts borrados en perfiles --- api/v1/model.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/v1/model.js b/api/v1/model.js index 896a851..c095bd6 100644 --- a/api/v1/model.js +++ b/api/v1/model.js @@ -851,6 +851,7 @@ Post.pagina = ({ pagina = 0, DNI } = {}) => { include: [ { model: Post, + where: { eliminadorDNI: { [Sequelize.Op.is]: null } }, include: [ { model: Usuario, @@ -881,6 +882,7 @@ Post.pagina = ({ pagina = 0, DNI } = {}) => { required: false, include: { model: Post, + where: { eliminadorDNI: { [Sequelize.Op.is]: null } }, include: [ { model: Usuario, @@ -944,6 +946,7 @@ Respuesta.pagina = ({ pagina = 0, DNI } = {}) => { include: [ { model: Post, + where: { eliminadorDNI: { [Sequelize.Op.is]: null } }, include: [ { model: Voto @@ -967,6 +970,7 @@ Respuesta.pagina = ({ pagina = 0, DNI } = {}) => { required: true, include: { model: Post, + where: { eliminadorDNI: { [Sequelize.Op.is]: null } }, include: [ { model: Usuario, From d4e37973cc0a26440ae64592a0edc1365cf15576 Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Mon, 8 Apr 2024 17:40:52 -0300 Subject: [PATCH 11/14] perfil/tudni te muestra como te ven los demas --- frontend/router.js | 6 ------ frontend/static/pantallas/perfil.js | 18 +++++++++--------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/frontend/router.js b/frontend/router.js index c51cfe6..1e2c96c 100644 --- a/frontend/router.js +++ b/frontend/router.js @@ -483,12 +483,6 @@ router.get("/perfil/:DNI?", async (req, res) => { let paginaError = SinPermisos(req.session, 'Algo ha malido sal. Volver al inicio') let usuarioActual; if (req.params.DNI) { - if (req.session.usuario && req.session.usuario.DNI == req.params.DNI) { - // * perfil propio - let pagina = PaginaPerfilPropioInfo('/perfil' /* ! Sacamos el DNI para que cargue el script correcto. */, req.session); - mandarPagina(pagina); - return; - } BloqueoDAO.findAll({ where: { diff --git a/frontend/static/pantallas/perfil.js b/frontend/static/pantallas/perfil.js index e51058d..d031944 100644 --- a/frontend/static/pantallas/perfil.js +++ b/frontend/static/pantallas/perfil.js @@ -8,19 +8,19 @@ function crearPagina(ruta, usuario, usu, perfilBloqueado = false) { let modal = new Modal('General', 'modal-general'); let posibleBotonModerar; let posibleMensajeUsuarioBloqueado; - if(usuario.usuario?.perfil.permiso.ID > 1){ + if (usuario.usuario?.perfil.permiso.ID > 1 && usuario.usuario?.DNI != usu.DNI) { let boton; - if(perfilBloqueado){ + if (perfilBloqueado) { boton = `` - posibleMensajeUsuarioBloqueado = new MensajeInterfaz(MensajeInterfaz.GRIS,'Este usuario se encuentra bloqueado') - }else{ + posibleMensajeUsuarioBloqueado = new MensajeInterfaz(MensajeInterfaz.GRIS, 'Este usuario se encuentra bloqueado') + } else { boton = `` - posibleMensajeUsuarioBloqueado = new ComponenteLiteral(()=> ``) + posibleMensajeUsuarioBloqueado = new ComponenteLiteral(() => ``) } - posibleBotonModerar = new ComponenteLiteral(()=> `
${boton}
`) - }else{ - posibleMensajeUsuarioBloqueado = new ComponenteLiteral(()=> ``) - posibleBotonModerar = new ComponenteLiteral(()=> ``) + posibleBotonModerar = new ComponenteLiteral(() => `
${boton}
`) + } else { + posibleMensajeUsuarioBloqueado = new ComponenteLiteral(() => ``) + posibleBotonModerar = new ComponenteLiteral(() => ``) }; return new Pagina({ From b323f4b2cc74549551bb5368d89bd814ac24effe Mon Sep 17 00:00:00 2001 From: c3r38r170 Date: Mon, 8 Apr 2024 17:56:07 -0300 Subject: [PATCH 12/14] =?UTF-8?q?Ahora=20el=20sistema=20avisa=20de=20repor?= =?UTF-8?q?tes=20autom=C3=A1ticos=20en=20preguntas=20y=20respuestas.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/pregunta.js | 104 +++++++----------- api/v1/respuesta.js | 13 ++- frontend/router.js | 14 +-- frontend/static/pantallas/editar-pregunta.js | 25 ++--- frontend/static/pantallas/editar-respuesta.js | 14 ++- frontend/static/pantallas/nueva-pregunta.js | 2 +- frontend/static/pantallas/pregunta.js | 2 +- 7 files changed, 68 insertions(+), 106 deletions(-) diff --git a/api/v1/pregunta.js b/api/v1/pregunta.js index b678b23..ffe0df5 100644 --- a/api/v1/pregunta.js +++ b/api/v1/pregunta.js @@ -40,6 +40,9 @@ router.get("/", (req, res) => { }); }); +function editarPregunta(req, res, respuestaIA=null){ +} + router.patch("/", function (req, res) { Pregunta.findByPk(req.body.ID, { include: [ @@ -61,60 +64,22 @@ router.patch("/", function (req, res) { } else { // TODO Refactor: DRY en este if let modera = getModera(); - if (modera == 1) { - moderarWithRetry(req.body.titulo + " " + req.body.cuerpo, 50).then( - (respuesta) => { - let esperarA = [] - let rechazaPost = getRechazaPost(); - let reportaPost = getReportaPost(); - if (respuesta.apropiado < rechazaPost) { - res - .status(400) - .send("Texto rechazo por moderación automática. Razón: " + respuesta.motivo); - return; - } else if (respuesta.apropiado < reportaPost) { - //Crear reporte - esperarA.push(ReportePost.create({ - tipoID: 1, - reportadoID: pregunta.ID, - })) - - } - //si pasa el filtro - pregunta.post.cuerpo = req.body.cuerpo; - pregunta.titulo = req.body.titulo; - const etiquetasIDs = Array.isArray(req.body.etiquetas) ? req.body.etiquetas : [req.body.etiquetas]; - // !no se porque pero asi anda pregunta.save() no - esperarA.push( - pregunta.post.save() - .then(() => - pregunta.setEtiquetas([]) - ) - .then(pre => pre.save()) - .then(() => - Promise.all(etiquetasIDs.map( - (ID) => EtiquetasPregunta.create({ etiquetumID: ID, preguntumID: pregunta.post.ID }) - )) - ) - // .then(ep => pregunta.setEtiquetas(req.body.etiquetas.map( - // (ID) =>({ preguntumID : pregunta.post.ID , etiquetumID: ID }) - // ))) - ) - Promise.all(esperarA) - .then(() => - res.status(200).send(req.body.ID + "") - ) - - } - ); - } else { - let esperarA = [] + let esperarA = [] + const editarPregunta=(motivo=null)=>{ pregunta.post.cuerpo = req.body.cuerpo; pregunta.titulo = req.body.titulo; - const etiquetas = Array.isArray(req.body.etiquetas) ? req.body.etiquetas : [req.body.etiquetas]; // !no se porque pero asi anda pregunta.save() no + //TODO Refactor: Usar setEtiquetas. etiquetas vienen los id en array + // pregunta.setEtiquetas( + // req.body.etiquetasIDs.map( + // (ID) => new EtiquetasPregunta({ etiquetumID: ID }) + // ) + // ); + // .then(ep => pregunta.setEtiquetas(req.body.etiquetas.map( + // (ID) =>({ preguntumID : pregunta.post.ID , etiquetumID: ID }) + // ))) esperarA.push( pregunta.post.save() .then(() => @@ -126,24 +91,39 @@ router.patch("/", function (req, res) { (ID) => EtiquetasPregunta.create({ etiquetumID: ID, preguntumID: pregunta.post.ID }) )) ) - // .then(ep => pregunta.setEtiquetas(req.body.etiquetas.map( - // (ID) =>({ preguntumID : pregunta.post.ID , etiquetumID: ID }) - // ))) ) Promise.all(esperarA) .then(() => - res.status(200).send(req.body.ID + "") + res.status(200).send(motivo) ) - //etiquetas vienen los id en array - // pregunta.setEtiquetas( - // req.body.etiquetasIDs.map( - // (ID) => new EtiquetasPregunta({ etiquetumID: ID }) - // ) - // ); - //no se porque pero asi anda pregunta.save() no - // pregunta.post.save(); - // res.status(200).send("Pregunta actualizada exitosamente"); } + + if (modera == 1) { + moderarWithRetry(req.body.titulo + " " + req.body.cuerpo, 50).then( + (respuesta) => { + let rechazaPost = getRechazaPost(); + if (respuesta.apropiado < rechazaPost) { + res + .status(400) + .send("Texto rechazo por moderación automática. Razón: " + respuesta.motivo); + return; + } + + if (respuesta.apropiado < getReportaPost()) { + // * Crear reporte + esperarA.push(ReportePost.create({ + tipoID: 1, + reportadoID: req.body.ID + })) + + editarPregunta(respuesta.motivo); + return; + } + } + ); + } + + editarPregunta(); } } }) diff --git a/api/v1/respuesta.js b/api/v1/respuesta.js index b1f4ef5..8d30b7b 100644 --- a/api/v1/respuesta.js +++ b/api/v1/respuesta.js @@ -114,10 +114,10 @@ router.patch("/", function (req, res) { res.status(403).send(mensajeError403); return; } else { - const editarRespuesta = () => { + const editarRespuesta = (motivo=null) => { respuesta.post.cuerpo = req.body.cuerpo; respuesta.post.save(); - res.status(200).send(req.body.IDPregunta + ""); + res.status(200).send(motivo); } let modera = getModera(); @@ -130,17 +130,18 @@ router.patch("/", function (req, res) { return; } if (resp.apropiado < reportaPost) { - //Crear reporte + // * Crear reporte ReportePost.create({ tipoID: 1, reportadoID: respuesta.ID, }); + + editarRespuesta(resp.motivo); } - editarRespuesta(); }); - } else { - editarRespuesta(); } + + editarRespuesta(); } } }) diff --git a/frontend/router.js b/frontend/router.js index 6a774c7..da2e6b5 100644 --- a/frontend/router.js +++ b/frontend/router.js @@ -137,18 +137,6 @@ router.get("/pregunta/:id?", async (req, res) => { include: { model: Categoria, as: "categoria" }, } } - // TODO Refactor: Agregar la condición de suscripciones solo si req.session.usuario.DNI está definido. No hace falta traer todas, sino solo la que nos interesa. Ver voto como ejemplo. - /* , - { - model: UsuarioDAO - , as: 'usuariosSuscriptos', - through: { - model: SuscripcionesPreguntaDAO, - where: { - fecha_baja: null // Condición para que la fecha de baja sea nula - } - } - } */ ]; // TODO Refactor: Evitar chequear antes y después. @@ -214,7 +202,7 @@ router.get("/pregunta/:id?", async (req, res) => { // ! No se puede traer votos Y un resumen, por eso lo calculamos acá. Los votos los traemos solo para ver si el usuario actual votó. - //Ordenar respuestas por valoracion + // * Ordenar respuestas por valoracion function calculateSumValoracion(respuesta) { return respuesta.post.votos.reduce( (total, voto) => total + voto.valoracion, diff --git a/frontend/static/pantallas/editar-pregunta.js b/frontend/static/pantallas/editar-pregunta.js index 88a28b2..5b88e84 100644 --- a/frontend/static/pantallas/editar-pregunta.js +++ b/frontend/static/pantallas/editar-pregunta.js @@ -10,6 +10,7 @@ function crearPagina(ruta,sesion, pregunta, categorias){ 'editando-pregunta' ,'/api/pregunta' ,[ + // TODO Refactor: Mandar patch a /pregunta/:ID, no ?ID= {name:'ID',textoEtiqueta:'ID',value:pregunta.ID, type:'hidden'} ,{name:'titulo',textoEtiqueta:'Título',value:pregunta.titulo} ,{name:'cuerpo',textoEtiqueta:'Detalles',type:'textarea',value:pregunta.cuerpo} @@ -17,11 +18,12 @@ function crearPagina(ruta,sesion, pregunta, categorias){ ,{name:'etiquetas',textoEtiqueta:'Etiquetas',type:'lista-etiquetas',value:pregunta.etiquetas , extra:categorias.map(cat => cat.etiquetas.map(eti => ``)).flat().join('')} ] ,(res)=>{ - console.log(res) - setTimeout(function() { - window.location.replace('/pregunta/'+res); - }, 1000); - + const recargar=()=>window.location.replace('/pregunta/'+pregunta.ID); + // TODO Refactor: trim?? + if(res){ + Swal.redirigirEn(10,`La edición se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${res}`) + .then(recargar); + }else recargar(); } ,{ textoEnviar:'Editar Pregunta', verbo: 'PATCH', clasesBoton:'is-link is-rounded mt-3' @@ -32,15 +34,4 @@ function crearPagina(ruta,sesion, pregunta, categorias){ return pagina; } -export {crearPagina as PantallaEditarPregunta}; -// for(let eti of cat.etiquetas){ -// optionsEtiquetas.push(['OPTION',{ -// value:eti.ID -// ,dataset:{ -// categoriaID:cat.ID -// } -// ,innerText:`${cat.descripcion} - ${eti.descripcion}` -// }]); - -// htmlStyle+=`, .tag.is-rounded[data-value="${eti.ID}"]`; -// } \ No newline at end of file +export {crearPagina as PantallaEditarPregunta}; \ No newline at end of file diff --git a/frontend/static/pantallas/editar-respuesta.js b/frontend/static/pantallas/editar-respuesta.js index 8fe5592..3534477 100644 --- a/frontend/static/pantallas/editar-respuesta.js +++ b/frontend/static/pantallas/editar-respuesta.js @@ -12,16 +12,18 @@ function crearPagina(ruta, sesion, respuesta) { , '/api/respuesta/' , [ { name: 'ID', textoEtiqueta: 'ID', value: respuesta.ID, type: 'hidden' }, + // TODO Refactor: ¿Por qué respuesta.pregunta puede no tener ID?? No tiene sentido según el dominio. + // TODO Refactor: Also, en algún punto de la vida, quizá meter los endpoints de respuestas en los de preguntas. Ejemplo: POST /api/pregunta/:ID/respuesta { name: 'IDPregunta', textoEtiqueta: 'ID', value: respuesta.pregunta?.ID, type: 'hidden' } , { name: 'cuerpo', textoEtiqueta: 'Respuesta', type: 'textarea', value: respuesta.cuerpo } ] , (res) => { - console.log(res) - setTimeout(function () { - // TODO refactor: redirigir a pregunta asociada a esa respuesta - window.location.replace('/pregunta/' + res); - }, 1000); - + const recargar=()=>window.location.replace('/pregunta/'+respuesta.pregunta.ID); + // TODO Refactor: trim?? + if(res){ + Swal.redirigirEn(10,`La edición se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${res}`) + .then(recargar); + }else recargar(); } , { textoEnviar: 'Editar Respuesta', verbo: 'PATCH', clasesBoton: 'is-link is-rounded mt-3' diff --git a/frontend/static/pantallas/nueva-pregunta.js b/frontend/static/pantallas/nueva-pregunta.js index 33d529c..74885f0 100644 --- a/frontend/static/pantallas/nueva-pregunta.js +++ b/frontend/static/pantallas/nueva-pregunta.js @@ -23,7 +23,7 @@ function crearPagina(ruta,sesion,categorias){ const preguntaID=+respuesta.ID const irAPregunta=()=>window.location.replace('/pregunta/'+preguntaID); if(respuesta.motivo){ - Swal.redirigirEn(10,`La respuesta se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${respuesta.motivo}`) + Swal.redirigirEn(10,`La pregunta se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${respuesta.motivo}`) .then(irAPregunta); }else irAPregunta(); }else Swal.error(`Error ${info.codigo}: ${respuesta}`); diff --git a/frontend/static/pantallas/pregunta.js b/frontend/static/pantallas/pregunta.js index 9062ebe..9cf412e 100644 --- a/frontend/static/pantallas/pregunta.js +++ b/frontend/static/pantallas/pregunta.js @@ -48,7 +48,7 @@ function PaginaPregunta(ruta, sesion, pregunta){ if(ok){ const reload=()=>window.location.reload(); if(respuesta.motivo){ - Swal.redirigirEn(10,`La pregunta se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${respuesta.motivo}`) + Swal.redirigirEn(10,`La respuesta se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${respuesta.motivo}`) .then(reload); }else reload(); }else{ From d9abd4f4de8bf42ee12b708a3d97b8975e962e97 Mon Sep 17 00:00:00 2001 From: Matias Bais Date: Mon, 8 Apr 2024 18:01:44 -0300 Subject: [PATCH 13/14] poder reportar usuarios --- api/v1/usuario.js | 13 ++++----- frontend/static/pantallas/perfil.js | 8 +++++- frontend/static/scripts/perfil-viendo.js | 36 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/api/v1/usuario.js b/api/v1/usuario.js index 3147ed5..b801254 100644 --- a/api/v1/usuario.js +++ b/api/v1/usuario.js @@ -328,19 +328,18 @@ router.post("/:DNI/reporte", function (req, res) { } else { // TODO Refactor: Usar Sequelize, usuario.addReporteUsuario(new ReporteUsuario({reportante: ... o como sea })) ReportesUsuario - .findOne({ where: { usuarioReportadoDNI: req.params.DNI } }) + .findOne({ where: { reportadoDNI: req.params.DNI } }) .then(re => { if (re) { - re.usuarioReportanteDNI = req.session.usuario.DNI; + re.reportanteDNI = req.session.usuario.DNI; re.createdAt = new Date().toISOString().slice(0, 19).replace('T', ' '); return re.save(); } else { // ?? ReportesUsuario.ReportesUsuario. - return ReportesUsuario. - ReportesUsuario.create({ - usuarioReportanteDNI: req.session.usuario.DNI, - usuarioReportadoDNI: req.params.DNI, - }); + return ReportesUsuario.create({ + reportanteDNI: req.session.usuario.DNI, + reportadoDNI: req.params.DNI, + }); } }) .then(() => { diff --git a/frontend/static/pantallas/perfil.js b/frontend/static/pantallas/perfil.js index d031944..6dfd39e 100644 --- a/frontend/static/pantallas/perfil.js +++ b/frontend/static/pantallas/perfil.js @@ -18,7 +18,13 @@ function crearPagina(ruta, usuario, usu, perfilBloqueado = false) { posibleMensajeUsuarioBloqueado = new ComponenteLiteral(() => ``) } posibleBotonModerar = new ComponenteLiteral(() => `
${boton}
`) - } else { + } else if (usuario.usuario?.DNI != usu.DNI && usuario.usuario) { + let boton; + boton = `` + posibleMensajeUsuarioBloqueado = new ComponenteLiteral(() => ``) + posibleBotonModerar = new ComponenteLiteral(() => `
${boton}
`) + } + else { posibleMensajeUsuarioBloqueado = new ComponenteLiteral(() => ``) posibleBotonModerar = new ComponenteLiteral(() => ``) }; diff --git a/frontend/static/scripts/perfil-viendo.js b/frontend/static/scripts/perfil-viendo.js index bb8a04c..8464b54 100644 --- a/frontend/static/scripts/perfil-viendo.js +++ b/frontend/static/scripts/perfil-viendo.js @@ -162,3 +162,39 @@ if (desbloqueado) { } } + +let reportado = document.getElementById("botonReportar"); +if (reportado) { + + gEt("botonReportar").onclick = (e) => { + let boton = e.target; + if (boton.type != "button") { + return; + } + + var usuarioDNI = boton.getAttribute("data-DNI"); + modal.titulo = "Está seguro que desea reportar al usuario?"; + + modal.contenido = [ + new Formulario( + "moderacion-usuario-bloquear", + "/api/usuario/" + usuarioDNI + "/reporte", + [ + ], + (res) => { Swal.exito(`${res}`) }, + { + verbo: "POST", + textoEnviar: "Reportar Usuario", + clasesBoton: "is-link is-rounded mt-3", + // alEnviar: () => (checkbox.disabled = true), + } + ), + ]; + + modal.redibujar(); + + + modalElemento.classList.add("is-active"); + } +} + From 8915daf720eee7e9e13f553ffd89554bc9bda29d Mon Sep 17 00:00:00 2001 From: c3r38r170 Date: Mon, 8 Apr 2024 18:20:39 -0300 Subject: [PATCH 14/14] Ahora se avisan los reportes al editar y crear preguntas y respuestas. --- api/v1/ia.js | 3 ++- api/v1/pregunta.js | 9 ++++---- api/v1/respuesta.js | 8 +++++-- frontend/static/pantallas/editar-pregunta.js | 21 ++++++++++++------ frontend/static/pantallas/editar-respuesta.js | 22 +++++++++++++------ 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/api/v1/ia.js b/api/v1/ia.js index c769298..27bbe1c 100644 --- a/api/v1/ia.js +++ b/api/v1/ia.js @@ -31,7 +31,8 @@ async function moderar(post) { try { const response = await fetch(`${base_url}/chat/completions`, requestOptions); const responseData = await response.json(); - return JSON.parse(responseData.choices[0].message.content); + const contenido=responseData.choices[0].message.content; + return JSON.parse(contenido); } catch (error) { throw error; } diff --git a/api/v1/pregunta.js b/api/v1/pregunta.js index ffe0df5..7c6bba9 100644 --- a/api/v1/pregunta.js +++ b/api/v1/pregunta.js @@ -94,7 +94,7 @@ router.patch("/", function (req, res) { ) Promise.all(esperarA) .then(() => - res.status(200).send(motivo) + res.status(200).json({ID:req.body.ID ,motivo}) ) } @@ -119,11 +119,12 @@ router.patch("/", function (req, res) { editarPregunta(respuesta.motivo); return; } + + // TODO Refactor: DRY. No se si es posible igual, dejar comentario en todo caso. + editarPregunta(); } ); - } - - editarPregunta(); + }else editarPregunta(); } } }) diff --git a/api/v1/respuesta.js b/api/v1/respuesta.js index 8d30b7b..d90f167 100644 --- a/api/v1/respuesta.js +++ b/api/v1/respuesta.js @@ -117,7 +117,7 @@ router.patch("/", function (req, res) { const editarRespuesta = (motivo=null) => { respuesta.post.cuerpo = req.body.cuerpo; respuesta.post.save(); - res.status(200).send(motivo); + res.status(200).json({ID:req.body.IDPregunta,motivo}); } let modera = getModera(); @@ -129,6 +129,7 @@ router.patch("/", function (req, res) { res.status(400).send("Texto rechazo por moderación automática. Razón: " + respuesta.motivo); return; } + if (resp.apropiado < reportaPost) { // * Crear reporte ReportePost.create({ @@ -138,10 +139,13 @@ router.patch("/", function (req, res) { editarRespuesta(resp.motivo); } + + editarRespuesta(); }); + }else{ + editarRespuesta(); } - editarRespuesta(); } } }) diff --git a/frontend/static/pantallas/editar-pregunta.js b/frontend/static/pantallas/editar-pregunta.js index 5b88e84..a626359 100644 --- a/frontend/static/pantallas/editar-pregunta.js +++ b/frontend/static/pantallas/editar-pregunta.js @@ -17,13 +17,20 @@ function crearPagina(ruta,sesion, pregunta, categorias){ // TODO refactor: llevar el map a Formulario y mandar extra: categorias ,{name:'etiquetas',textoEtiqueta:'Etiquetas',type:'lista-etiquetas',value:pregunta.etiquetas , extra:categorias.map(cat => cat.etiquetas.map(eti => ``)).flat().join('')} ] - ,(res)=>{ - const recargar=()=>window.location.replace('/pregunta/'+pregunta.ID); - // TODO Refactor: trim?? - if(res){ - Swal.redirigirEn(10,`La edición se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${res}`) - .then(recargar); - }else recargar(); + ,(res,{ok,codigo})=>{ + if(ok){ + // ! No se puede acceder a las variables de alrededor. + respuesta=JSON.parse(res); + const preguntaID=+respuesta.ID + const recargar=()=>window.location.replace('/pregunta/'+preguntaID); + // TODO Refactor: trim?? + if(respuesta.motivo){ + Swal.redirigirEn(10,`La edición se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${respuesta.motivo}`) + .then(recargar); + }else recargar(); + }else{ + Swal.error(`Error ${codigo}: ${res}`); + } } ,{ textoEnviar:'Editar Pregunta', verbo: 'PATCH', clasesBoton:'is-link is-rounded mt-3' diff --git a/frontend/static/pantallas/editar-respuesta.js b/frontend/static/pantallas/editar-respuesta.js index 3534477..1dd9459 100644 --- a/frontend/static/pantallas/editar-respuesta.js +++ b/frontend/static/pantallas/editar-respuesta.js @@ -17,13 +17,21 @@ function crearPagina(ruta, sesion, respuesta) { { name: 'IDPregunta', textoEtiqueta: 'ID', value: respuesta.pregunta?.ID, type: 'hidden' } , { name: 'cuerpo', textoEtiqueta: 'Respuesta', type: 'textarea', value: respuesta.cuerpo } ] - , (res) => { - const recargar=()=>window.location.replace('/pregunta/'+respuesta.pregunta.ID); - // TODO Refactor: trim?? - if(res){ - Swal.redirigirEn(10,`La edición se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${res}`) - .then(recargar); - }else recargar(); + , (res,{ok,codigo}) => { + // TODO Refactor: DRY en esto al editar o crear pregunta o respuesta. + if(ok){ + // ! No se puede acceder a las variables de alrededor. + respuesta=JSON.parse(res); + const preguntaID=+respuesta.ID + const recargar=()=>window.location.replace('/pregunta/'+preguntaID); + // TODO Refactor: trim?? + if(respuesta.motivo){ + Swal.redirigirEn(10,`La edición se va a publicar, pero fue automáticamente reportada por el siguiente motivo:

${respuesta.motivo}`) + .then(recargar); + }else recargar(); + }else{ + Swal.error(`Error ${codigo}: ${res}`); + } } , { textoEnviar: 'Editar Respuesta', verbo: 'PATCH', clasesBoton: 'is-link is-rounded mt-3'