├── helpers
├── cache.js
├── index.js
├── db-validator.js
├── obtener-usuario.js
├── calcular-distancia.js
├── google-verify-token.js
├── jwt.js
├── generar-aleatorio.js
├── subir-archivo.js
└── enviar-notificacion.js
├── ejemplo.env
├── assets
└── no-image.jpg
├── prueba
├── img
│ ├── logo.png
│ └── descarga.png
└── public
│ ├── descarga.png
│ ├── index.html
│ └── pdfTemplate.js
├── index.js
├── routes
├── buscar.js
├── comentarios.js
├── documents.js
├── mensajes.js
├── denuncias.js
├── notificaciones.js
├── ubicaciones.js
├── auth.js
├── publicaciones.js
├── usuarios.js
├── uploads.js
├── reportes.js
└── salas.js
├── controllers
├── documents.js
├── denuncias.js
├── buscar.js
├── mensajes.js
├── ubicaciones.js
├── notificaciones.js
├── socket.js
├── auth.js
├── uploads.js
├── comentarios.js
├── usuarios.js
├── publicaciones.js
├── salas.js
└── reportes.js
├── .gitignore
├── database
└── config.js
├── middlewares
├── validar-campos.js
├── validar-archivo.js
├── validar-jwt.js
└── express-validator.js
├── models
├── index.js
├── mensaje.js
├── denuncia.js
├── comentario.js
├── ubicacion.js
├── sala.js
├── notificacion.js
├── publicacion.js
└── usuario.js
├── tests
├── usuarios.spec.js
├── notificaciones.spec.js
├── auth.spec.js
├── comentarios.spec.js
├── mensajes.spec.js
├── publicaciones.spec.js
├── denuncias.spec.js
├── salas.spec.js
└── ubicaciones.spec.js
├── package.json
├── app.js
├── sockets
└── socket.js
└── README.md
/helpers/cache.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/helpers/index.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ejemplo.env:
--------------------------------------------------------------------------------
1 | PORT=
2 | DB_CNN=
3 | JWT_KEY=
4 | TOKEN_NOTIFICAIONES=
--------------------------------------------------------------------------------
/assets/no-image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vinici0/rest-server-movil-web/HEAD/assets/no-image.jpg
--------------------------------------------------------------------------------
/prueba/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vinici0/rest-server-movil-web/HEAD/prueba/img/logo.png
--------------------------------------------------------------------------------
/prueba/img/descarga.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vinici0/rest-server-movil-web/HEAD/prueba/img/descarga.png
--------------------------------------------------------------------------------
/prueba/public/descarga.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Vinici0/rest-server-movil-web/HEAD/prueba/public/descarga.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 |
2 | const { app,server } = require("./app");
3 |
4 | server.listen(process.env.PORT, (err) => {
5 | if (err) throw new Error(err);
6 | console.log("Servidor corriendo en puerto", process.env.PORT);
7 | });
8 |
9 |
--------------------------------------------------------------------------------
/routes/buscar.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const { buscar } = require("../controllers/buscar");
3 |
4 | const router = Router();
5 |
6 | router.get("/:coleccion/:termino", buscar);
7 |
8 | module.exports = router;
9 |
--------------------------------------------------------------------------------
/controllers/documents.js:
--------------------------------------------------------------------------------
1 | const pdf = require('html-pdf');
2 | const pdfTemplate = require('../prueba/public/pdfTemplate');
3 | const path = require("path");
4 |
5 | const createDocument = async (req, res) => {
6 | res.send('PDF');
7 | };
8 |
9 | const getDocument = async (req, res) => {
10 | res.sendFile(path.join(__dirname, 'datos.pdf'));
11 | };
12 |
13 | module.exports = { createDocument, getDocument };
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 | *.pid.lock
10 |
11 | # Dependencies
12 | node_modules/
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 |
17 | # Output of 'npm run build'
18 | build/
19 |
20 | # Environment variables
21 | .env
22 |
23 | # IDE files
24 | .vscode/
25 | .idea/
26 |
27 | # OS generated files
28 | .DS_Store
29 | Thumbs.db
30 |
31 | uploads/
--------------------------------------------------------------------------------
/helpers/db-validator.js:
--------------------------------------------------------------------------------
1 | const { Usuario} = require('../models');
2 |
3 | const coleccionesPermitidas = ( coleccion = '', colecciones = []) => {
4 |
5 | const incluida = colecciones.includes( coleccion );
6 | if ( !incluida ) {
7 | throw new Error(`La colección ${ coleccion } no es permitida, ${ colecciones }`);
8 | }
9 | return true;
10 | }
11 |
12 |
13 | module.exports = {
14 | coleccionesPermitidas
15 | }
--------------------------------------------------------------------------------
/database/config.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const dbConnection = async () => {
4 | try {
5 | await mongoose.connect(process.env.DB_CNN);
6 |
7 | console.log("DB Online");
8 | } catch (error) {
9 | console.log(error);
10 | throw new Error("Error en la base de datos - Hable con el admin");
11 | }
12 | };
13 |
14 | module.exports = {
15 | dbConnection,
16 | };
17 |
18 |
19 |
--------------------------------------------------------------------------------
/middlewares/validar-campos.js:
--------------------------------------------------------------------------------
1 | const { validationResult } = require('express-validator');
2 |
3 |
4 | const validarCampos = (req, res, next ) => {
5 |
6 | const errores = validationResult( req );
7 |
8 | if( !errores.isEmpty() ) {
9 | return res.status(400).json({
10 | ok: false,
11 | errors: errores.mapped()
12 | });
13 | }
14 |
15 | next();
16 | }
17 |
18 |
19 | module.exports = {
20 | validarCampos
21 | }
--------------------------------------------------------------------------------
/routes/comentarios.js:
--------------------------------------------------------------------------------
1 | const { Router } = require('express');
2 | const { validarJWT } = require('../middlewares/validar-jwt');
3 | const { getComentariosByPublicacion, createComentario, toggleLikeComentario } = require('../controllers/comentarios');
4 |
5 | const router = Router();
6 |
7 | router.get("/:publicacionId", validarJWT, getComentariosByPublicacion);
8 |
9 | router.post("/", validarJWT, createComentario);
10 |
11 | router.put("/like/:id", validarJWT, toggleLikeComentario);
12 |
13 | module.exports = router;
--------------------------------------------------------------------------------
/helpers/obtener-usuario.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | const Sala = require("../models/");
4 |
5 | const obtenerUsuariosSalaHelper = async (salaId) => {
6 | try {
7 | const usuariosEnSala = await Sala.findById(salaId).populate({
8 | path: "usuarios",
9 | match: { online: false },
10 | });
11 | return usuariosEnSala.usuarios;
12 | } catch (error) {
13 | console.log(error);
14 | return [];
15 | }
16 | };
17 |
18 | module.exports = {
19 | obtenerUsuariosSalaHelper
20 | }
--------------------------------------------------------------------------------
/routes/documents.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const { check } = require("express-validator");
3 | const { validarJWT } = require("../middlewares/validar-jwt");
4 | const { validarArchivoSubir } = require("../middlewares/validar-archivo");
5 | const pdfTemplate = require('../prueba/public/pdfTemplate');
6 | const router = Router();
7 |
8 | const {createDocument,getDocument} = require('../controllers/documents');
9 |
10 | router.post( "/", createDocument );
11 |
12 | router.get( "/", getDocument );
13 |
14 | module.exports = router;
--------------------------------------------------------------------------------
/models/index.js:
--------------------------------------------------------------------------------
1 | const Comentario = require("./comentario");
2 | const Publicacion = require("./publicacion");
3 | const Usuario = require("./usuario");
4 | const Ubicacion = require("./ubicacion");
5 | const Mensaje = require("./mensaje");
6 | const Sala = require("./sala");
7 | const Notificacion = require("./notificacion");
8 | const Denuncia = require("./denuncia");
9 |
10 | module.exports = {
11 | Comentario,
12 | Publicacion,
13 | Usuario,
14 | Ubicacion,
15 | Mensaje,
16 | Sala,
17 | Notificacion,
18 | Denuncia
19 | }
--------------------------------------------------------------------------------
/middlewares/validar-archivo.js:
--------------------------------------------------------------------------------
1 | const { response } = require("express")
2 |
3 |
4 | const validarArchivoSubir = (req, res = response, next ) => {
5 |
6 | //obtenr nomber del body
7 |
8 | console.log(req.body);
9 |
10 | if (!req.files || Object.keys(req.files).length === 0 || !req.files.archivo ) {
11 | return res.status(400).json({
12 | msg: 'No hay archivos que subir - validarArchivoSubir'
13 | });
14 | }
15 |
16 | next();
17 |
18 | }
19 |
20 |
21 | module.exports = {
22 | validarArchivoSubir
23 | }
--------------------------------------------------------------------------------
/models/mensaje.js:
--------------------------------------------------------------------------------
1 | const { Schema, model } = require("mongoose");
2 |
3 | const MensajeSchema = Schema(
4 | {
5 | mensaje: {
6 | type: String,
7 | required: true,
8 | },
9 | usuario: {
10 | type: Schema.Types.ObjectId,
11 | ref: "Usuario",
12 | required: true,
13 | },
14 | },
15 | {
16 | timestamps: true,
17 | }
18 | );
19 |
20 | MensajeSchema.method("toJSON", function () {
21 | const { __v, _id, ...object } = this.toObject();
22 | return object;
23 | });
24 |
25 | module.exports = model("Mensaje", MensajeSchema);
--------------------------------------------------------------------------------
/routes/mensajes.js:
--------------------------------------------------------------------------------
1 | /*
2 | Path: /api/mensajes
3 | */
4 | const { Router } = require("express");
5 | const { validarJWT } = require("../middlewares/validar-jwt");
6 |
7 | const {
8 | getAllMessages,
9 | getMensajeByUser,
10 | getMensajeByRoom,
11 | } = require("../controllers/mensajes");
12 |
13 | const router = Router();
14 |
15 | router.get("/", validarJWT, getAllMessages);
16 |
17 | router.get("/get-mensaje-by-user", validarJWT, getMensajeByUser);
18 |
19 | router.get("/get-mensaje-by-room/:salaId", validarJWT, getMensajeByRoom);
20 |
21 | module.exports = router;
22 |
--------------------------------------------------------------------------------
/routes/denuncias.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const { check } = require("express-validator");
3 | const { validarJWT } = require("../middlewares/validar-jwt");
4 |
5 | const router = Router();
6 |
7 | const { validarCampos } = require("../middlewares/validar-campos");
8 | const { guardarDenuncia } = require("../controllers/denuncias");
9 |
10 | router.post( "/", [
11 | check("publicacionId", "El id de la publicación es obligatorio").not().isEmpty(),
12 | check("motivo", "El motivo es obligatorio").not().isEmpty(),
13 | validarCampos,
14 | validarJWT,
15 | ], guardarDenuncia );
16 |
17 | module.exports = router;
--------------------------------------------------------------------------------
/routes/notificaciones.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const { check } = require("express-validator");
3 | const { validarJWT } = require("../middlewares/validar-jwt");
4 | const { obtenerNotificacionesUsuario, marcarNotificacionComoLeida, deleteAllNotifications, deleteNotificationById } = require("../controllers/notificaciones");
5 |
6 | const router = Router();
7 |
8 | router.get("/", validarJWT, obtenerNotificacionesUsuario);
9 |
10 | router.put("/:id", validarJWT, marcarNotificacionComoLeida);
11 |
12 | router.delete("/", validarJWT, deleteAllNotifications);
13 |
14 | router.delete("/:id", validarJWT, deleteNotificationById);
15 |
16 | module.exports = router;
--------------------------------------------------------------------------------
/middlewares/validar-jwt.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 |
3 | const validarJWT = (req, res, next) => {
4 | // Leer token
5 | const token = req.header("x-token");
6 |
7 | if (!token) {
8 | return res.status(401).json({
9 | ok: false,
10 | msg: "No hay token en la petición",
11 | });
12 | }
13 |
14 | try {
15 | const { uid } = jwt.verify(token, process.env.JWT_KEY);
16 | console.log(uid);
17 | req.uid = uid;
18 |
19 | next();
20 | } catch (error) {
21 | return res.status(401).json({
22 | ok: false,
23 | msg: "Token no válido",
24 | });
25 | }
26 | };
27 |
28 | module.exports = {
29 | validarJWT,
30 | };
31 |
--------------------------------------------------------------------------------
/helpers/calcular-distancia.js:
--------------------------------------------------------------------------------
1 | // calcular la distancia entre dos puntos de latitud y longitud
2 | const calcularDistancia = (lat1, lon1, lat2, lon2) => {
3 | const R = 6371; // Radio de la Tierra en kilómetros
4 |
5 | const dLat = degToRad(lat2 - lat1);
6 | const dLon = degToRad(lon2 - lon1);
7 |
8 | const a =
9 | Math.sin(dLat / 2) * Math.sin(dLat / 2) +
10 | Math.cos(degToRad(lat1)) *
11 | Math.cos(degToRad(lat2)) *
12 | Math.sin(dLon / 2) *
13 | Math.sin(dLon / 2);
14 |
15 | const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
16 |
17 | const distancia = R * c;
18 |
19 | return distancia;
20 | };
21 |
22 | // Función para convertir grados a radianes
23 | function degToRad(deg) {
24 | return deg * (Math.PI / 180);
25 | }
26 |
27 | module.exports = {
28 | calcularDistancia,
29 | };
30 |
--------------------------------------------------------------------------------
/models/denuncia.js:
--------------------------------------------------------------------------------
1 | const { Schema, model } = require("mongoose");
2 |
3 | const DenunciaSchema = Schema(
4 | {
5 | publicacion: {
6 | type: Schema.Types.ObjectId,
7 | ref: 'Publicacion',
8 | required: true,
9 | },
10 | motivo: {
11 | type: String,
12 | required: true,
13 | },
14 | detalles: {
15 | type: String,
16 | },
17 | denunciante: {
18 | type: Schema.Types.ObjectId,
19 | ref: 'Usuario',
20 | required: true,
21 | },
22 | fecha: {
23 | type: Date,
24 | default: Date.now,
25 | },
26 | },
27 | );
28 |
29 | DenunciaSchema.method('toJSON', function () {
30 | const { __v, _id, ...object } = this.toObject();
31 | object.uid = _id;
32 | return object;
33 | });
34 |
35 | module.exports = model('Denuncia', DenunciaSchema);
--------------------------------------------------------------------------------
/helpers/google-verify-token.js:
--------------------------------------------------------------------------------
1 | const { OAuth2Client } = require("google-auth-library");
2 |
3 | const CLIENT_ID =
4 | "538224676274-66q03vper7rorc34ndtnb3g7sllclt8n.apps.googleusercontent.com";
5 |
6 | const client = new OAuth2Client(CLIENT_ID);
7 |
8 | const validarGoogleIdToken = async (token) => {
9 | try {
10 | const ticket = await client.verifyIdToken({
11 | idToken: token,
12 | audience: [
13 | CLIENT_ID,
14 | "538224676274-6dm96dvsaknf5gf1uh7sp672demu4at1.apps.googleusercontent.com",
15 | ],
16 | });
17 |
18 | const payload = ticket.getPayload();
19 |
20 | return {
21 | name: payload["name"],
22 | picture: payload["picture"],
23 | email: payload["email"],
24 | };
25 | } catch (error) {
26 | return null;
27 | }
28 | };
29 |
30 | module.exports = {
31 | validarGoogleIdToken,
32 | };
33 |
--------------------------------------------------------------------------------
/prueba/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | SocketServer
7 |
8 |
9 | Acceso denegado
10 |
11 |
12 |
13 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/helpers/jwt.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 |
3 | const generarJWT = (uid) => {
4 | return new Promise((resolve, reject) => {
5 | const payload = { uid };
6 |
7 | jwt.sign(
8 | payload,
9 | process.env.JWT_KEY,
10 | {
11 | expiresIn: "1y",
12 | },
13 | (err, token) => {
14 | if (err) {
15 | // no se pudo crear el token
16 | reject("No se pudo generar el JWT");
17 | } else {
18 | // TOKEN!
19 | resolve(token);
20 | }
21 | }
22 | );
23 | });
24 | };
25 |
26 | const comprobarJWT = (token = "") => {
27 | try {
28 | const { uid } = jwt.verify(token, process.env.JWT_KEY);
29 |
30 | return [true, uid];
31 | } catch (error) {
32 | return [false, null];
33 | }
34 | };
35 |
36 | module.exports = {
37 | generarJWT,
38 | comprobarJWT,
39 | };
40 |
--------------------------------------------------------------------------------
/tests/usuarios.spec.js:
--------------------------------------------------------------------------------
1 | const { app } = require("../app");
2 | const request = require("supertest");
3 |
4 | describe("Usuarios Router", () => {
5 | const token = process.env.TOKEN_TEST_AUTH; // Adjust this to retrieve the token properly
6 |
7 | test("Should delete a phone number", async () => {
8 | const response = await request(app)
9 | .delete("/api/usuarios/delete-telefono")
10 | .set("x-token", token)
11 | .expect(400);
12 |
13 | // Verify the response, e.g., response.body
14 | });
15 |
16 | test("Should get users", async () => {
17 | const response = await request(app)
18 | .get("/api/usuarios")
19 | .set("x-token", token)
20 | .expect(200);
21 |
22 | // Verify the response, e.g., response.body
23 | });
24 |
25 | // Add more tests for other endpoints as needed
26 | });
27 |
--------------------------------------------------------------------------------
/routes/ubicaciones.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const { check } = require("express-validator");
3 | const { validarJWT } = require("../middlewares/validar-jwt");
4 | const { validarCampos } = require("../middlewares/validar-campos");
5 | const {
6 | obtenerUbicaciones,
7 | crearUbicacion,
8 | obtenerUbicacionesPorUsuario,
9 | agregarUbicacion,
10 | eliminarUbicacion,
11 | } = require("../controllers/ubicaciones");
12 | const { validacionesUbicacion } = require("../middlewares/express-validator");
13 |
14 | const router = Router();
15 |
16 | router.get("/", obtenerUbicaciones);
17 |
18 | router.post("/", [validacionesUbicacion, validarCampos], crearUbicacion);
19 |
20 | router.get("/", validarJWT, obtenerUbicacionesPorUsuario);
21 |
22 | router.put("/:id", validarJWT, agregarUbicacion);
23 |
24 | router.delete("/:id", validarJWT, eliminarUbicacion);
25 | module.exports = router;
26 |
--------------------------------------------------------------------------------
/tests/notificaciones.spec.js:
--------------------------------------------------------------------------------
1 | const { app } = require("../app");
2 | const request = require("supertest");
3 |
4 | describe("Notificaciones Router", () => {
5 | const token = process.env.TOKEN_TEST_AUTH; // Adjust this to retrieve the token properly
6 |
7 | test("Should get user's notifications", async () => {
8 | const response = await request(app)
9 | .get("/api/notificacion")
10 | .set("x-token", token)
11 | .expect(200);
12 |
13 | // Verify the response, e.g., response.body
14 | });
15 |
16 | test("Should mark notification as read", async () => {
17 | const notificationId = "64bfef6c2f35690cfee892ff"; // Replace with an actual notification ID
18 | const response = await request(app)
19 | .put(`/api/notificacion/${notificationId}`)
20 | .set("x-token", token)
21 | .expect(404);
22 |
23 | // Verify the response, e.g., response.body
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/tests/auth.spec.js:
--------------------------------------------------------------------------------
1 | const { app } = require("../app");
2 | const request = require("supertest");
3 |
4 | describe("GET api/auth", () => {
5 | const user = {
6 | nombre: "vinicio",
7 | email: "testadadaawdwdawdadw1@gmail.com",
8 | password: "123456",
9 | };
10 |
11 | test("should return 200 for user login", async () => {
12 | await request(app)
13 | .post("/api/login")
14 | .send({
15 | email: user.email,
16 | password: user.password
17 | })
18 | .expect(200);
19 | });
20 |
21 | test("should return 400", async () => {
22 | await request(app)
23 | .post("/api/login/new")
24 | .send(user)
25 | .expect(400);
26 | });
27 |
28 | test("should return 200 for token renewal", async () => {
29 | const token = process.env.TOKEN_TEST_AUTH;
30 | await request(app)
31 | .get("/api/login/renew")
32 | .set("x-token", token)
33 | .expect(200);
34 | });
35 |
36 | });
37 |
--------------------------------------------------------------------------------
/models/comentario.js:
--------------------------------------------------------------------------------
1 | const { Schema, model } = require("mongoose");
2 |
3 | const ComentarioSchema = Schema(
4 | {
5 | contenido: {
6 | type: String,
7 | required: true,
8 | },
9 | usuario: {
10 | type: Schema.Types.ObjectId,
11 | ref: "Usuario",
12 | required: true,
13 | },
14 | publicacion: {
15 | type: Schema.Types.ObjectId,
16 | ref: "Publicacion",
17 | required: true,
18 | },
19 | likes: [
20 | {
21 | type: Schema.Types.ObjectId,
22 | ref: "Usuario",
23 | },
24 | ],
25 | estado: {
26 | type: String,
27 | enum: ["publicado", "borrador"],
28 | required: true,
29 | },
30 | },
31 | {
32 | timestamps: true,
33 | }
34 | );
35 |
36 | ComentarioSchema.method("toJSON", function () {
37 | const { __v, _id, ...object } = this.toObject();
38 | object.uid = _id;
39 | return object;
40 | });
41 |
42 | module.exports = model("Comentario", ComentarioSchema);
43 |
--------------------------------------------------------------------------------
/models/ubicacion.js:
--------------------------------------------------------------------------------
1 | const { Schema, model } = require("mongoose");
2 |
3 | const UbicacionSchema = Schema(
4 | {
5 | latitud: {
6 | type: Number,
7 | required: true,
8 | },
9 | longitud: {
10 | type: Number,
11 | required: true,
12 | },
13 | barrio: {
14 | type: String,
15 | required: true,
16 | },
17 | parroquia: {
18 | type: String,
19 | },
20 | ciudad: {
21 | type: String,
22 | required: true,
23 | },
24 | pais: {
25 | type: String,
26 | required: true,
27 | },
28 | referencia : {
29 | type: String,
30 | },
31 | estado: {
32 | type: Boolean,
33 | default: true,
34 | },
35 | },
36 | {
37 | timestamps: true,
38 | }
39 | );
40 |
41 | UbicacionSchema.method("toJSON", function () {
42 | const { __v, _id, ...object } = this.toObject();
43 | object.uid = _id;
44 | return object;
45 | });
46 |
47 | module.exports = model("Ubicacion", UbicacionSchema);
48 |
--------------------------------------------------------------------------------
/models/sala.js:
--------------------------------------------------------------------------------
1 | const { Schema, model } = require("mongoose");
2 |
3 | const SalaSchema = Schema(
4 | {
5 | nombre: {
6 | type: String,
7 | required: true,
8 | },
9 | codigo: {
10 | type: String,
11 | required: true,
12 | unique: true,
13 | },
14 | color: {
15 | type: String,
16 | required: true,
17 | },
18 | isLike : {
19 | type: Boolean,
20 | default: false
21 | },
22 | propietario: {
23 | type: Schema.Types.ObjectId,
24 | ref: "Usuario",
25 | },
26 | isActivo: {
27 | type: Boolean,
28 | default: true,
29 | },
30 | usuarios: [{ type: Schema.Types.ObjectId, ref: "Usuario" }],
31 | mensajes: [{ type: Schema.Types.ObjectId, ref: "Mensaje" }],
32 | },
33 |
34 | {
35 | timestamps: true,
36 | }
37 | );
38 |
39 | SalaSchema.method("toJSON", function () {
40 | const { __v, _id,...object } = this.toObject();
41 | object.uid = _id;
42 | return object;
43 | });
44 |
45 | module.exports = model("Sala", SalaSchema);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "01-band_names_server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "nodemon index.js",
9 | "start:dev": "nodemon index.js"
10 | },
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "axios": "^1.4.0",
15 | "bcryptjs": "^2.4.3",
16 | "cors": "^2.8.5",
17 | "dotenv": "^16.0.3",
18 | "exceljs": "^4.3.0",
19 | "express": "^4.18.2",
20 | "express-fileupload": "^1.4.0",
21 | "express-validator": "^6.6.1",
22 | "google-auth-library": "^8.8.0",
23 | "html-pdf": "^3.0.1",
24 | "jsonwebtoken": "^8.5.1",
25 | "lodash": "^4.17.21",
26 | "moment": "^2.29.4",
27 | "mongoose": "^6.6.5",
28 | "pdfkit": "^0.13.0",
29 | "pdfmake": "^0.2.7",
30 | "pdfmake-unicode": "^0.0.1",
31 | "socket.io": "^4.7.1",
32 | "uuid": "^9.0.0"
33 | },
34 | "devDependencies": {
35 | "jest": "^29.6.2",
36 | "supertest": "^6.3.3"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/helpers/generar-aleatorio.js:
--------------------------------------------------------------------------------
1 | const generarCodigoUnico = () => {
2 | const codigoNumerico = Math.floor(Math.random() * 999999); // Genera un número aleatorio entre 0 y 999999
3 | const codigo = codigoNumerico.toString().padStart(6, "0"); // Convierte el número en una cadena de 6 caracteres rellenada con ceros a la izquierda si es necesario
4 | const codigoConGuion = `${codigo.substr(0, 3)}-${codigo.substr(3)}`; // Agrega el guión al medio del código
5 | return codigoConGuion;
6 | };
7 |
8 | const generarColorAleatorio = () => {
9 | const colorBase = "6165FA"; // El color principal de la aplicación en formato hexadecimal (sin el prefijo 0xFF)
10 |
11 | let color = "#";
12 |
13 | // Generar dos valores hexadecimales aleatorios para cada uno de los tres componentes de color (rojo, verde y azul)
14 | for (let i = 0; i < 3; i++) {
15 | const componente = Math.floor(Math.random() * 256)
16 | .toString(16)
17 | .padStart(2, "0");
18 | color += componente;
19 | }
20 |
21 | return color;
22 | };
23 |
24 | module.exports = {
25 | generarCodigoUnico,
26 | generarColorAleatorio,
27 | };
28 |
--------------------------------------------------------------------------------
/tests/comentarios.spec.js:
--------------------------------------------------------------------------------
1 | const { app } = require("../app");
2 | const request = require("supertest");
3 |
4 | describe("Comments API Testing api/comentarios", () => {
5 | const token = process.env.TOKEN_TEST_AUTH;
6 |
7 | const commentData = {
8 | contenido:"sala1",
9 | publicacionId:"64c2dc5184c4d0f0c9062ef0"
10 | };
11 |
12 | test("Should retrieve comments by publication ID", async () => {
13 | await request(app)
14 | .get("/api/comentarios/64d17088e27ea53f578d106c")
15 | .set("x-token", token)
16 | .expect(200);
17 | });
18 |
19 | test("Should successfully create a new comment", async () => {
20 | const response = await request(app)
21 | .post("/api/comentarios")
22 | .set("x-token", token)
23 | .send(commentData)
24 | .expect(201);
25 | });
26 |
27 | test("Should successfully like a comment", async () => {
28 | await request(app)
29 | .put("/api/comentarios/like/64d17088e27ea53f578d106c")
30 | .set("x-token", token)
31 | .expect(200);
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/tests/mensajes.spec.js:
--------------------------------------------------------------------------------
1 | const { app } = require("../app");
2 | const request = require("supertest");
3 |
4 | describe("Mensajes Router", () => {
5 | const token = process.env.TOKEN_TEST_AUTH;
6 | const salaId = "64c1ca50a9e34350e4b40c27";
7 | test("Should get all messages", async () => {
8 | const response = await request(app)
9 | .get(`/api/mensajes/get-mensajes/${salaId}`)
10 | .set("x-token", token)
11 | .expect(404);
12 |
13 | // Verify the response, e.g., response.body
14 | });
15 |
16 | test("Should get messages by user", async () => {
17 | const response = await request(app)
18 | .get("/api/mensajes/get-mensaje-by-user")
19 | .set("x-token", token)
20 | .expect(200);
21 |
22 | // Verify the response, e.g., response.body
23 | });
24 |
25 | test("Should get messages by room", async () => {
26 | const response = await request(app)
27 | .get(`/api/mensajes/get-mensaje-by-room/${salaId}`)
28 | .set("x-token", token)
29 | .expect(200);
30 |
31 | // Verify the response, e.g., response.body
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/tests/publicaciones.spec.js:
--------------------------------------------------------------------------------
1 | const { app } = require("../app");
2 | const request = require("supertest");
3 |
4 | describe("Publicaciones Router", () => {
5 | const token = process.env.TOKEN_TEST_AUTH;
6 |
7 | test("Should get user's publications", async () => {
8 | const response = await request(app)
9 | .get("/api/publicacion")
10 | .set("x-token", token)
11 | .expect(200);
12 |
13 | // Verify the response, e.g., response.body
14 | });
15 |
16 | test("Should get nearby publications", async () => {
17 | const response = await request(app)
18 | .get("/api/publicacion/cercanas")
19 | .set("x-token", token)
20 | .expect(200);
21 |
22 | // Verify the response, e.g., response.body
23 | });
24 |
25 |
26 | test("Should get nearby publications", async () => {
27 | const response = await request(app)
28 | .get("/api/publicacion/cercanas")
29 | .set("x-token", token)
30 | .expect(200);
31 |
32 | // Verify the response, e.g., response.body
33 | });
34 |
35 | // Add more tests for other endpoints as needed
36 | });
37 |
--------------------------------------------------------------------------------
/tests/denuncias.spec.js:
--------------------------------------------------------------------------------
1 | const { app } = require("../app");
2 | const request = require("supertest");
3 |
4 | describe("Denuncias Router", () => {
5 | const token = process.env.TOKEN_TEST_AUTH;
6 |
7 | const denunciaData = {
8 | publicacionId: "64c2d5ec84c4d0f0c9062d14",
9 | motivo: "Inappropriate content",
10 | };
11 |
12 | test("Should successfully submit a denuncia", async () => {
13 | const denunciaExistente = true;
14 |
15 | const response = await request(app)
16 | .post("/api/denuncias")
17 | .set("x-token", token)
18 | .send(denunciaData);
19 |
20 | expect(response.body.ok).toBe(false);
21 | expect(response.body.msg).toBe(
22 | "Ya has denunciado esta publicación anteriormente"
23 | );
24 | });
25 |
26 | test("Should return 'not found' error for non-existing publication", async () => {
27 | const publicacionId = "non_existing_id";
28 | const denunciaData = {
29 | publicacionId,
30 | motivo: "Inappropriate content",
31 | };
32 |
33 | const response = await request(app)
34 | .post("/api/denuncias")
35 | .set("x-token", token)
36 | .send(denunciaData)
37 | .expect(500);
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/middlewares/express-validator.js:
--------------------------------------------------------------------------------
1 | const { check } = require("express-validator");
2 | const validacionesCrearPublicacion = [
3 | check("barrio", "El barrio es obligatorio").not().isEmpty(),
4 | check("ciudad", "La ciudad es obligatoria").not().isEmpty(),
5 | check("color", "El color es obligatorio").not().isEmpty(),
6 | check("contenido", "El contenido es obligatorio").not().isEmpty(),
7 | check("isPublic", "El estado de publicación es obligatorio").not().isEmpty(),
8 | check("latitud", "La latitud es obligatoria").not().isEmpty(),
9 | check("longitud", "La longitud es obligatoria").not().isEmpty(),
10 | check("titulo", "El título es obligatorio").not().isEmpty(),
11 | check("nombreUsuario", "El nombre de usuario es obligatorio").not().isEmpty(),
12 | ];
13 |
14 | const validacionesUbicacion = [
15 | check("barrio", "El barrio es obligatorio").not().isEmpty(),
16 | check("ciudad", "La ciudad es obligatoria").not().isEmpty(),
17 | check("latitud", "La latitud es obligatoria").not().isEmpty(),
18 | check("longitud", "La longitud es obligatoria").not().isEmpty(),
19 | check("pais", "El país es obligatorio").not().isEmpty(),
20 | ];
21 |
22 |
23 | module.exports = {
24 | validacionesCrearPublicacion,
25 | validacionesUbicacion,
26 | };
27 |
--------------------------------------------------------------------------------
/models/notificacion.js:
--------------------------------------------------------------------------------
1 | const { Schema, model } = require("mongoose");
2 |
3 | const NotificacionSchema = Schema(
4 | {
5 | tipo: {
6 | type: String,
7 | enum: ['publicacion', 'sos', 'mensaje'],
8 | required: true,
9 | },
10 | usuario: {
11 | type: Schema.Types.ObjectId,
12 | ref: 'Usuario',
13 | required: true,
14 | },
15 | //usuario que envia la notificacion
16 | usuarioRemitente: {
17 | type: Schema.Types.ObjectId,
18 | ref: 'Usuario',
19 | },
20 |
21 | publicacion: {
22 | type: Schema.Types.ObjectId,
23 | ref: 'Publicacion',
24 | },
25 | telefonoUsuario: {
26 | type: String,
27 | },
28 | mensaje: {
29 | type: String,
30 | required: true,
31 | },
32 | latitud: {
33 | type: Number,
34 | required: true,
35 | },
36 | longitud: {
37 | type: Number,
38 | required: true,
39 | },
40 | isLeida: {
41 | type: Boolean,
42 | default: false,
43 | },
44 | },
45 | {
46 | timestamps: true,
47 | }
48 | );
49 |
50 |
51 | NotificacionSchema.method('toJSON', function () {
52 | const { __v, _id,...object } = this.toObject();
53 | object.uid = _id;
54 | return object;
55 | });
56 |
57 |
58 | module.exports = model('Notificacion', NotificacionSchema);
59 |
--------------------------------------------------------------------------------
/routes/auth.js:
--------------------------------------------------------------------------------
1 | /*
2 | path: api/login
3 | TOUTER
4 | */
5 | const { Router } = require("express");
6 | const { check } = require("express-validator");
7 |
8 | const {
9 | crearUsuario,
10 | login,
11 | renewToken,
12 | googleAuth,
13 | } = require("../controllers/auth");
14 | const { validarCampos } = require("../middlewares/validar-campos");
15 | const { validarJWT } = require("../middlewares/validar-jwt");
16 |
17 | const router = Router();
18 |
19 | router.post(
20 | "/new",
21 | [
22 | check("nombre", "El nombre es obligatorio").not().isEmpty(),
23 | check("password", "La contraseña es obligatoria").not().isEmpty(),
24 | check("email", "El correo es obligatorio").isEmail(),
25 | validarCampos,
26 | ],
27 | crearUsuario
28 | );
29 |
30 | router.post(
31 | "/",
32 | [
33 | check("password", "La contraseña es obligatoria").not().isEmpty(),
34 | check("email", "El correo es obligatorio").isEmail(),
35 | validarCampos,
36 | ],
37 | login
38 | );
39 |
40 | router.post(
41 | "/",
42 | [
43 | check("password", "La contraseña es obligatoria").not().isEmpty(),
44 | check("email", "El correo es obligatorio").isEmail(),
45 | validarCampos,
46 | ],
47 | login
48 | );
49 |
50 | router.get("/renew", validarJWT, renewToken);
51 |
52 | router.post("/google", googleAuth);
53 |
54 | module.exports = router;
55 |
--------------------------------------------------------------------------------
/routes/publicaciones.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const { check } = require("express-validator");
3 | const { validarJWT } = require("../middlewares/validar-jwt");
4 | const {
5 | obtenerPublicacionesUsuario,
6 | guardarPublicacion,
7 | getPublicacionesEnRadio,
8 | updatePublicacion,
9 | likePublicacion,
10 | guardarListArchivo,
11 | isPublicacionFinalizada,
12 | deletePublicacion,
13 | actualizarDescripcion,
14 | } = require("../controllers/publicaciones");
15 | const { validarCampos } = require("../middlewares/validar-campos");
16 | const { validacionesCrearPublicacion } = require("../middlewares/express-validator");
17 |
18 | const router = Router();
19 |
20 | router.get("/", validarJWT, obtenerPublicacionesUsuario);
21 |
22 | router.get("/cercanas", validarJWT, getPublicacionesEnRadio);
23 |
24 | router.put("/like2/:id", validarJWT, likePublicacion);
25 |
26 | router.post("/", [...validacionesCrearPublicacion, validarCampos, validarJWT], guardarPublicacion);
27 |
28 | router.put("/:id", validarJWT, updatePublicacion);
29 |
30 | router.post("/listaArchivos/:uid/:titulo",validarCampos, guardarListArchivo);
31 |
32 | router.put("/like", validarJWT, updatePublicacion);
33 |
34 | router.put("/marcar-publicacion-pendiente-false/:publicacionId", validarJWT, isPublicacionFinalizada);
35 |
36 | router.delete("/:id", validarJWT, deletePublicacion);
37 |
38 | router.put("/actualizarDescripcion/:id", validarJWT, actualizarDescripcion);
39 |
40 | module.exports = router;
41 |
42 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const path = require("path");
3 | const cors = require("cors");
4 | const fileUpload = require('express-fileupload');
5 | require("dotenv").config();
6 |
7 | require("./database/config").dbConnection();
8 |
9 | const app = express();
10 | app.use(cors());
11 |
12 | app.use(express.json());
13 |
14 | const server = require("http").createServer(app);
15 | module.exports.io = require("socket.io")(server);
16 | require("./sockets/socket");
17 | const publicPath = path.resolve(__dirname, "./prueba/public");
18 | app.use(express.static(publicPath));
19 |
20 | app.use(
21 | fileUpload({
22 | useTempFiles: true,
23 | tempFileDir: "/tmp/",
24 | createParentPath: true
25 | })
26 | );
27 |
28 | app.use("/api/buscar", require("./routes/buscar"));
29 | app.use("/api/comentarios", require("./routes/comentarios"));
30 | app.use("/api/login", require("./routes/auth"));
31 | app.use("/api/mensajes", require("./routes/mensajes"));
32 | app.use("/api/publicacion", require("./routes/publicaciones"));
33 | app.use("/api/salas", require("./routes/salas"));
34 | app.use("/api/ubicaciones", require("./routes/ubicaciones"));
35 | app.use("/api/uploads", require("./routes/uploads"));
36 | app.use("/api/usuarios", require("./routes/usuarios"));
37 | app.use("/api/reportes", require("./routes/reportes"));
38 | app.use("/api/notificacion", require("./routes/notificaciones"));
39 | app.use("/api/denuncias", require("./routes/denuncias"));
40 | app.use("/api/documents", require("./routes/documents"));
41 |
42 | module.exports = {
43 | app,
44 | server,
45 | }
--------------------------------------------------------------------------------
/routes/usuarios.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const { validarJWT } = require("../middlewares/validar-jwt");
3 |
4 | const {
5 | actualizarUsuario,
6 | ageregarTelefonos,
7 | agregarDireccion,
8 | agregarTelefono,
9 | eliminarTelefono,
10 | enviarNotificacionesArrayTelefonos,
11 | getUsuarios,
12 | actualizarTelefonoOrNombre,
13 | actualizarIsOpenRoom,
14 | marcarPublicacionPendienteFalse,
15 | marcarSalaPendienteFalse,
16 | marcarNotificacionesPendienteFalse,
17 | eliminarTokenApp,
18 | } = require("../controllers/usuarios");
19 |
20 | const router = Router();
21 | router.delete("/delete-telefono", validarJWT, eliminarTelefono );
22 | router.get("/", validarJWT, getUsuarios);
23 | router.post("/notificacion", validarJWT, enviarNotificacionesArrayTelefonos);
24 | router.put("/", validarJWT, actualizarUsuario);
25 | router.put("/actualizar-is-open-room", validarJWT, actualizarIsOpenRoom);
26 | router.put("/add-direccion", validarJWT, agregarDireccion);
27 | router.put("/add-telefono", validarJWT, agregarTelefono );
28 | router.put("/add-telefonos", validarJWT, ageregarTelefonos );
29 | router.put("/add-telefono-nombre", validarJWT, actualizarTelefonoOrNombre );
30 | router.put("/marcar-publicacion-pendiente-false", validarJWT, marcarPublicacionPendienteFalse );
31 | router.put("/marcar-sala-pendiente-false", validarJWT, marcarSalaPendienteFalse );
32 | router.put("/marcar-notificaciones-pendiente-false", validarJWT, marcarNotificacionesPendienteFalse );
33 | router.delete("/delete-token-app", validarJWT, eliminarTokenApp );
34 |
35 | module.exports = router;
36 |
--------------------------------------------------------------------------------
/routes/uploads.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const { check } = require("express-validator");
3 | const { validarJWT } = require("../middlewares/validar-jwt");
4 | const { validarArchivoSubir } = require("../middlewares/validar-archivo");
5 | const {
6 | cargarArchivo,
7 | mostrarImagen,
8 | mostrarAllImagenes,
9 | actualizarImagen,
10 | mostrarImagenUsuario,
11 | } = require("../controllers/uploads");
12 | const { validarCampos } = require("../middlewares/validar-campos");
13 | const { coleccionesPermitidas } = require("../helpers/db-validator");
14 |
15 | const router = Router();
16 |
17 | router.post("/", validarArchivoSubir, cargarArchivo);
18 |
19 | router.get(
20 | "/:coleccion/:id",
21 | [
22 | check("id", "El id debe de ser de mongo").isMongoId(),
23 | // check('coleccion').custom( c => coleccionesPermitidas( c, ['usuarios','publicaciones'] ) ),
24 | validarCampos,
25 | ],
26 | mostrarImagen
27 | );
28 |
29 | router.get(
30 | "/usuario/:coleccion/:id",
31 | [
32 | check("id", "El id debe de ser de mongo").isMongoId(),
33 | // check('coleccion').custom( c => coleccionesPermitidas( c, ['usuarios','publicaciones'] ) ),
34 | validarCampos,
35 | ],
36 | mostrarImagenUsuario
37 | );
38 |
39 |
40 | router.get("/imagenes/:coleccion/:id", mostrarImagen);
41 |
42 | router.put('/:coleccion/:id', [
43 | validarArchivoSubir,
44 | check('id','El id debe de ser de mongo').isMongoId(),
45 | check('coleccion').custom( c => coleccionesPermitidas( c, ['usuarios','publicaciones'] ) ),
46 | validarCampos
47 | ], actualizarImagen )
48 |
49 | module.exports = router;
50 |
--------------------------------------------------------------------------------
/routes/reportes.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const {
3 | obtenerCiudades,obtenerBarrios,obtenerEmergencias,obtenerReporteBarras,obtenerReportePastel,obtenerAnios,obtenerMapaCalor,obtenerDatosCards
4 | ,obtenerCoordenadas
5 | ,descargarXLSX,descargarPDF,descargarCSV
6 | } = require("../controllers/reportes");
7 |
8 | const { validarJWT } = require("../middlewares/validar-jwt");
9 |
10 | const router = Router();
11 | router.get(
12 | "/obtenerCiudades",
13 | /* validarJWT, */
14 | obtenerCiudades
15 | );
16 | router.post(
17 | "/obtenerBarrios",
18 | /* validarJWT, */
19 | obtenerBarrios
20 | );
21 | router.post(
22 | "/obtenerEmergencias",
23 | /* validarJWT, */
24 | obtenerEmergencias
25 | );
26 | router.post(
27 | "/obtenerReporteBarras",
28 | /* validarJWT, */
29 | obtenerReporteBarras
30 | );
31 | router.post(
32 | "/obtenerReportePastel",
33 | /* validarJWT, */
34 | obtenerReportePastel
35 | );
36 | router.post(
37 | "/obtenerAnios",
38 | /* validarJWT, */
39 | obtenerAnios
40 | );
41 | router.post(
42 | "/obtenerMapaCalor",
43 | /* validarJWT, */
44 | obtenerMapaCalor
45 | );
46 | router.get(
47 | "/obtenerDatosCards",
48 | /* validarJWT, */
49 | obtenerDatosCards
50 | );
51 |
52 | router.post(
53 | "/obtenerCoordenadas",
54 | /* validarJWT, */
55 | obtenerCoordenadas
56 | );
57 |
58 | router.post(
59 | "/descargarXLSX",
60 | /* validarJWT, */
61 | descargarXLSX
62 | );
63 |
64 | router.post(
65 | "/descargarPDF",
66 | /* validarJWT, */
67 | descargarPDF
68 | );
69 |
70 | router.post(
71 | "/descargarCSV",
72 | /* validarJWT, */
73 | descargarCSV
74 | );
75 |
76 | module.exports = router;
77 |
--------------------------------------------------------------------------------
/routes/salas.js:
--------------------------------------------------------------------------------
1 | const { Router } = require("express");
2 | const {
3 | crearSala,
4 | getSalas,
5 | unirseSala,
6 | obtenerSalasMensajesUsuario,
7 | getMensajesBySala,
8 | getMensajesSala,
9 | updateSala,
10 | obtenerUsuariosSala,
11 | deleteSala,
12 | deleteUserById,
13 | abandonarSala,
14 | getSalasByUser,
15 | obtenerSalasConMensajesNoLeidos,
16 | cambiarEstadoSala,
17 | } = require("../controllers/salas");
18 |
19 | const { validarJWT } = require("../middlewares/validar-jwt");
20 |
21 | const router = Router();
22 |
23 | router.post("/", validarJWT, crearSala);
24 |
25 | router.get("/", getSalas);
26 |
27 | router.put("/:salaId", updateSala);
28 |
29 | router.delete("/:salaId", validarJWT, deleteSala);
30 |
31 | router.post("/unir-sala", validarJWT, unirseSala);
32 |
33 | router.get(
34 | "/obtener-salas-mensajes-usuario",
35 | validarJWT,
36 | obtenerSalasConMensajesNoLeidos
37 | );
38 |
39 | router.put("/cambiar-estado-sala/:salaId", validarJWT, cambiarEstadoSala);
40 |
41 | router.get(
42 | "/obtener-salas-mensajes-usuario",
43 | validarJWT,
44 | obtenerSalasMensajesUsuario
45 | );
46 |
47 | router.get("/obtener-salas-usuario", validarJWT, getSalasByUser);
48 |
49 | router.get("/get-mensajes-by-sala/:salaId", validarJWT, getMensajesBySala);
50 |
51 | router.get("/get-mensajes-sala/:salaId", validarJWT, getMensajesSala);
52 |
53 | router.get("/obtener-usuarios-sala/:salaId", validarJWT, obtenerUsuariosSala);
54 |
55 | router.delete("/delete-user/:salaId/:usuarioId", validarJWT, deleteUserById);
56 |
57 | router.delete("/abandonar-sala/:salaId", validarJWT, abandonarSala);
58 |
59 | // router.get("/obtener-mensajes-no-leidos/:salaId", validarJWT, obtenerMensajesNoLeidosPorUsuario);
60 |
61 | module.exports = router;
62 |
--------------------------------------------------------------------------------
/sockets/socket.js:
--------------------------------------------------------------------------------
1 | const { comprobarJWT } = require("../helpers/jwt");
2 | const { io } = require("../app");
3 | const {
4 | usuarioConectado,
5 | usuarioDesconectado,
6 | grabarMensajeSala,
7 | grabarComentarioPublicacion,
8 | } = require("../controllers/socket");
9 |
10 | // Mensajes de Sockets
11 | io.on("connection", (client) => {
12 | console.log("Cliente conectado");
13 |
14 | // console.log(client.handshake.headers);
15 | console.log(client.handshake.headers["x-token"], "token");
16 |
17 | const [valido, uid] = comprobarJWT(client.handshake.headers["x-token"]);
18 |
19 | // Verificar autenticación
20 |
21 | if (!valido) {
22 | console.log("Cliente no autenticado");
23 | return client.disconnect();
24 | }
25 |
26 | // Cliente autenticado
27 | usuarioConectado(uid);
28 | console.log("Cliente autenticado");
29 | client.on("join-room", async (payload) => {
30 | const { codigo } = payload;
31 | console.log(codigo, "codigo");
32 |
33 | const [valido, uid] = comprobarJWT(client.handshake.headers["x-token"]);
34 |
35 | if (!valido) {
36 | console.log("Token inválido");
37 | client.disconnect();
38 | } else {
39 | client.join(codigo);
40 | }
41 | });
42 |
43 | client.on("mensaje-grupal", async (payload) => {
44 | console.log(payload);
45 | grabarMensajeSala(payload);
46 | client.broadcast.to(payload.para).emit("mensaje-grupal", payload);
47 | });
48 |
49 | client.on("comentario-publicacion", async (payload) => {
50 | console.log(payload);
51 | client.broadcast.to(payload.para).emit("comentario-publicacion", payload);
52 | });
53 |
54 |
55 | client.on("disconnect", () => {
56 | usuarioDesconectado(uid);
57 | console.log("Cliente desconectado");
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/helpers/subir-archivo.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const { v4: uuidv4 } = require("uuid");
3 |
4 | const subirArchivoUsuario = (
5 | archivo,
6 | extensionesValidas = ["png", "jpg", "jpeg", "gif"],
7 | carpeta = ""
8 | ) => {
9 |
10 | return new Promise((resolve, reject) => {
11 | const nombreCortado = archivo.archivo.name.split(".");
12 | const extension = nombreCortado[nombreCortado.length - 1];
13 |
14 | // Validar la extension
15 | // if (!extensionesValidas.includes(extension)) {
16 | // return reject(
17 | // `La extensión ${extension} no es permitida - ${extensionesValidas}`
18 | // );
19 | // }
20 |
21 | const nombreTemp = uuidv4() + "." + extension;
22 | const uploadPath = path.join(__dirname, "../uploads/", carpeta, nombreTemp);
23 |
24 | archivo.archivo.mv(uploadPath, (err) => {
25 | if (err) {
26 | reject(err);
27 | }
28 |
29 | resolve(nombreTemp);
30 | });
31 | });
32 | };
33 |
34 | const subirArchivoPublicacion = (
35 | archivo,
36 | extensionesValidas = ["png", "jpg", "jpeg", "gif"],
37 | carpeta = ""
38 | ) => {
39 | return new Promise((resolve, reject) => {
40 | const nombreCortado = archivo.name.split(".");
41 | const extension = nombreCortado[nombreCortado.length - 1];
42 |
43 | // Validar la extensionssssss
44 | if (!extensionesValidas.includes(extension)) {
45 | return reject(
46 | `La extensión ${extension} no es permitida - ${extensionesValidas}`
47 | );
48 | }
49 |
50 | const nombreTemp = uuidv4() + "." + extension;
51 | const uploadPath = path.join(__dirname, "../uploads/", carpeta, nombreTemp);
52 |
53 | archivo.mv(uploadPath, (err) => {
54 | if (err) {
55 | reject(err);
56 | }
57 |
58 | resolve(nombreTemp);
59 | });
60 | });
61 | };
62 |
63 | module.exports = {
64 | subirArchivoUsuario,
65 | subirArchivoPublicacion
66 | };
67 |
--------------------------------------------------------------------------------
/models/publicacion.js:
--------------------------------------------------------------------------------
1 | const { Schema, model } = require("mongoose");
2 |
3 | const PublicacionSchema = Schema(
4 | {
5 | titulo: {
6 | type: String,
7 | required: true,
8 | },
9 | contenido: {
10 | type: String,
11 | required: true,
12 | },
13 |
14 | color: {
15 | type: String,
16 | required: true,
17 | },
18 | ciudad: {
19 | type: String,
20 | required: true,
21 | },
22 | barrio: {
23 | type: String,
24 | required: true,
25 | },
26 | isPublic: {
27 | type: Boolean,
28 | default: true,
29 | },
30 | usuario: {
31 | type: Schema.Types.ObjectId,
32 | ref: "Usuario",
33 | required: true,
34 | },
35 | nombreUsuario: {
36 | type: String,
37 | required: true,
38 | },
39 | likes: [
40 | {
41 | type: Schema.Types.ObjectId,
42 | ref: "Usuario",
43 | },
44 | ],
45 | //lista de imagenes
46 | imagenes: [
47 | {
48 | type: String,
49 | },
50 | ],
51 | latitud: {
52 | type: Number,
53 | },
54 | longitud: {
55 | type: Number,
56 | },
57 | comentarios: [
58 | {
59 | type: Schema.Types.ObjectId,
60 | ref: "Comentario",
61 | },
62 | ],
63 | imgAlerta: {
64 | type: String,
65 | required: true,
66 | },
67 |
68 | isLiked: {
69 | type: Boolean,
70 | default: false,
71 | },
72 | isActivo: {
73 | type: Boolean,
74 | default: true,
75 | },
76 | //publicacion pendiente
77 | isPublicacionPendiente: {
78 | type: Boolean,
79 | default: false,
80 | },
81 | },
82 | {
83 | timestamps: true,
84 | }
85 | );
86 |
87 | PublicacionSchema.method("toJSON", function () {
88 | const { __v, _id, ...object } = this.toObject();
89 | object.uid = _id;
90 | return object;
91 | });
92 |
93 | module.exports = model("Publicacion", PublicacionSchema);
94 |
--------------------------------------------------------------------------------
/tests/salas.spec.js:
--------------------------------------------------------------------------------
1 | const { app } = require("../app");
2 | const request = require("supertest");
3 |
4 | describe("Sala Router", () => {
5 | const token = process.env.TOKEN_TEST_AUTH;
6 | let salaId = "64bfef6c2f35690cfee892ff";
7 |
8 | // Prueba 1: Obtener todas las salas
9 | test("Should get salas", async () => {
10 | const response = await request(app)
11 | .get("/api/salas")
12 | .set("x-token", token)
13 | .expect(200);
14 |
15 | // Verificar la respuesta, por ejemplo:
16 | expect(response.body).toEqual(expect.arrayContaining([])); // Reemplaza [] con el formato esperado de las salas.
17 | });
18 |
19 | // Prueba 2: Crear una sala
20 | test("Should create a sala", async () => {
21 | const nuevaSala = { nombre: "Sala de Prueba" };
22 | const response = await request(app)
23 | .post("/api/salas")
24 | .set("x-token", token)
25 | .send(nuevaSala)
26 | .expect(200);
27 | });
28 |
29 | // Prueba 5: Eliminar una sala
30 | // Prueba 5: Eliminar una sala - Usuario no autorizado
31 | test("Should not delete a sala for unauthorized user", async () => {
32 | const response = await request(app)
33 | .delete(`/api/salas/${salaId}`)
34 | .set("x-token", token)
35 | .expect(401);
36 |
37 | // Verificar la respuesta HTTP 401 (Unauthorized)
38 | expect(response.status).toBe(401);
39 | });
40 |
41 |
42 | // Prueba 6: Unirse a una sala
43 | test("Should join a sala", async () => {
44 | const datosUnirseSala = { codigo: "299-427" };
45 | const response = await request(app)
46 | .post("/api/salas/unir-sala")
47 | .set("x-token", token)
48 | .send(datosUnirseSala)
49 | .expect(400);
50 |
51 |
52 | });
53 |
54 |
55 |
56 | // Prueba 8: Abandonar una sala
57 | test("Should leave a sala", async () => {
58 | const response = await request(app)
59 | .delete(`/api/salas/abandonar-sala/${salaId}`)
60 | .set("x-token", token)
61 | .expect(200);
62 |
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/models/usuario.js:
--------------------------------------------------------------------------------
1 | const { Schema, model } = require("mongoose");
2 |
3 | const UsuarioSchema = Schema(
4 | {
5 | nombre: {
6 | type: String,
7 | required: true,
8 | },
9 | email: {
10 | type: String,
11 | required: true,
12 | unique: true,
13 | },
14 | password: {
15 | type: String,
16 | required: true,
17 | },
18 | ubicaciones: [
19 | {
20 | type: Schema.Types.ObjectId,
21 | ref: "Ubicacion",
22 | },
23 | ],
24 | telefono: {
25 | type: String,
26 | },
27 | telefonos: [
28 | {
29 | type: String,
30 | },
31 | ],
32 | img: {
33 | type: String,
34 | },
35 | online: {
36 | type: Boolean,
37 | default: false,
38 | },
39 | tokenApp: {
40 | type: String,
41 | default: null,
42 | },
43 | google: {
44 | type: Boolean,
45 | default: false,
46 | },
47 | isOpenRoom: {
48 | type: Boolean,
49 | default: false,
50 | },
51 | isActivo: {
52 | type: Boolean,
53 | default: true,
54 | },
55 | isPublicacionPendiente: {
56 | type: Boolean,
57 | default: false,
58 | },
59 | isSalasPendiente: {
60 | type: Boolean,
61 | default: false,
62 | },
63 | isNotificacionesPendiente: {
64 | type: Boolean,
65 | default: false,
66 | },
67 | role: {
68 | type: String,
69 | required: true,
70 | default: "USER_ROLE",
71 | },
72 | salas: [
73 | {
74 | salaId: { type: Schema.Types.ObjectId, ref: "Sala" },
75 | mensajesNoLeidos: { type: Number, default: 0 },
76 | ultimaVezActivo: { type: Date, default: null },
77 | isRoomOpen: { type: Boolean, default: false },
78 | },
79 | ],
80 | },
81 | {
82 | timestamps: true,
83 | }
84 | );
85 |
86 | UsuarioSchema.method("toJSON", function () {
87 | const { __v, _id, password, ...object } = this.toObject();
88 | object.uid = _id;
89 | return object;
90 | });
91 |
92 | module.exports = model("Usuario", UsuarioSchema);
93 |
--------------------------------------------------------------------------------
/controllers/denuncias.js:
--------------------------------------------------------------------------------
1 | const { Usuario, Publicacion, Denuncia } = require("../models");
2 |
3 | const guardarDenuncia = async (req, res) => {
4 | const usuarioId = req.uid;
5 | const { publicacionId, motivo, detalles } = req.body;
6 |
7 | try {
8 | // Verificar si la publicación existe
9 | const publicacion = await Publicacion.findById(publicacionId);
10 | if (!publicacion) {
11 | return res.status(404).json({
12 | ok: false,
13 | msg: "La publicación no fue encontrada",
14 | });
15 | }
16 |
17 | // Verificar si el usuario ya ha denunciado esta publicación
18 | const denunciaExistente = await Denuncia.findOne({
19 | publicacion: publicacionId,
20 | denunciante: usuarioId,
21 | });
22 |
23 | if (denunciaExistente) {
24 | return res.status(400).json({
25 | ok: false,
26 | msg: "Ya has denunciado esta publicación anteriormente",
27 | });
28 | }
29 |
30 | // Crear la denuncia
31 | const denuncia = new Denuncia({
32 | publicacion: publicacionId,
33 | motivo,
34 | detalles,
35 | denunciante: usuarioId,
36 | });
37 |
38 | await denuncia.save();
39 |
40 | res.json({
41 | ok: true,
42 | denuncia,
43 | });
44 | } catch (error) {
45 | console.log(error);
46 | res.status(500).json({
47 | ok: false,
48 | msg: "Por favor hable con el administrador",
49 | });
50 | }
51 | };
52 |
53 |
54 | const obtenerDenuncias = async (req, res) => {
55 | try {
56 | const denuncias = await Denuncia.find()
57 | .populate("publicacion", "titulo")
58 | .populate("denunciante", "nombre")
59 | .sort({ fecha: -1 });
60 |
61 | res.json({
62 | ok: true,
63 | denuncias,
64 | });
65 | } catch (error) {
66 | console.log(error);
67 | res.status(500).json({
68 | ok: false,
69 | msg: "Por favor hable con el administrador",
70 | });
71 | }
72 | };
73 |
74 |
75 | module.exports = {
76 | guardarDenuncia,
77 | };
78 |
--------------------------------------------------------------------------------
/tests/ubicaciones.spec.js:
--------------------------------------------------------------------------------
1 | const { app } = require("../app");
2 | const request = require("supertest");
3 |
4 | describe("Ubicaciones Router", () => {
5 | const token = process.env.TOKEN_TEST_AUTH; // Adjust this to retrieve the token properly
6 |
7 | const dataUbicacion = {
8 | "latitud": -0.252175,
9 | "longitud": -79.1881,
10 | "barrio": "Calle Cuba",
11 | "parroquia": "Luz de América",
12 | "ciudad": "Santo Domingo de los Tsáchilas",
13 | "pais": "Ecuador",
14 | "referencia": "Parroquia Luz De América",
15 | }
16 |
17 | test("Should get all locations", async () => {
18 | const response = await request(app)
19 | .get("/api/ubicaciones")
20 | .expect(200);
21 |
22 | // Verify the response, e.g., response.body
23 | });
24 |
25 | test("Should create a new location", async () => {
26 |
27 |
28 | const response = await request(app)
29 | .post("/api/ubicaciones")
30 | .set("x-token", token)
31 | .send(dataUbicacion)
32 | .expect(200);
33 |
34 | // Verify the response, e.g., response.body
35 | });
36 |
37 | test("Should get user's locations", async () => {
38 | const response = await request(app)
39 | .get("/api/ubicaciones")
40 | .set("x-token", token)
41 | .expect(200);
42 | });
43 |
44 | test("Should add a location", async () => {
45 | const locationId = "64c3bb741d3d977b018a30ca"; // Replace with an actual location ID
46 | const response = await request(app)
47 | .put(`/api/ubicaciones/${locationId}`)
48 | .set("x-token", token)
49 | .send(dataUbicacion)
50 | .expect(200);
51 | });
52 |
53 | test("Should delete a location", async () => {
54 | const locationId = "64c3bb741d3d977b018a30ca"; // Replace with an actual location ID
55 | const response = await request(app)
56 | .delete(`/api/ubicaciones/${locationId}`)
57 | .set("x-token", token)
58 | .expect(200);
59 |
60 | // Verify the response, e.g., response.body
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/controllers/buscar.js:
--------------------------------------------------------------------------------
1 | const { response, request } = require("express");
2 | const { ObjectId } = require("mongoose").Types;
3 |
4 | const {
5 | Comentario,
6 | Mensaje,
7 | Publicacion,
8 | Sala,
9 | Ubicacion,
10 | Usuario,
11 | } = require("../models");
12 |
13 | const coleccionesPermitidas = [
14 | "usuarios",
15 | "publicaciones",
16 | "comentarios",
17 | "mensajes",
18 | "salas",
19 | "ubicaciones",
20 | ];
21 |
22 | const buscarUsuarios = async (termino = "", res = response) => {
23 | const esMongoID = ObjectId.isValid(termino);
24 |
25 | if (esMongoID) {
26 | const usuario = await Usuario.findById(termino);
27 | return res.json({
28 | results: usuario ? [usuario] : [],
29 | });
30 | }
31 |
32 | const regex = new RegExp(termino, "i");
33 |
34 | const usuarios = await Usuario.find({
35 | $or: [{ nombre: regex }, { apellido: regex }, { email: regex }],
36 | $and: [{ estado: true }],
37 | });
38 |
39 | res.json({
40 | results: usuarios,
41 | });
42 | };
43 |
44 | const buscarUbicaciones = async (
45 | termino = "",
46 | res = response,
47 | req = request
48 | ) => {
49 | const esMongoID = ObjectId.isValid(termino);
50 | if (esMongoID) {
51 | const ubicacion = await Ubicacion.findById(termino);
52 | return res.json({
53 | ubicaciones: ubicacion ? [ubicacion] : [],
54 | });
55 | }
56 |
57 | const { limite = 6, desde = 0 } = req.query;
58 | const regex = new RegExp(termino, "i");
59 |
60 | const ubicaciones = await Ubicacion.find({
61 | $or: [
62 | { barrio: regex },
63 | { ciudad: regex },
64 | { parroquia: regex },
65 | { pais: regex },
66 | { referencia: regex },
67 | ],
68 | $and: [{ estado: true }],
69 | })
70 | .skip(Number(desde))
71 | .limit(Number(limite));
72 |
73 | res.json({
74 | ok: true,
75 | ubicaciones: ubicaciones,
76 | });
77 | };
78 |
79 | const buscar = async (req = request, res = response) => {
80 | const { coleccion, termino } = req.params;
81 | if (!coleccionesPermitidas.includes(coleccion)) {
82 | return res.status(400).json({
83 | msg: `Las colecciones permitidas son: ${coleccionesPermitidas}`,
84 | });
85 | }
86 |
87 | switch (coleccion) {
88 | case "usuarios":
89 | buscarUsuarios(termino, res);
90 | break;
91 | case "ubicaciones":
92 | buscarUbicaciones(termino, res, req);
93 | break;
94 | default:
95 | res.status(500).json({
96 | msg: "Se le olvidó hacer esta búsqueda",
97 | });
98 | }
99 | };
100 |
101 | module.exports = { buscar };
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Backend de Seguridad ESPE
2 | El proyecto Backend de Seguridad ESPE es una parte fundamental del proyecto de vinculación con la sociedad denominado "Implementación de aplicaciones web y móvil para gestionar emergencias comunitarias en la provincia de Santo Domingo de los Tsáchilas". Su objetivo principal es fortalecer la seguridad de la comunidad a través de la comunicación, coordinación y respuesta ante situaciones de emergencia. Esta aplicación aprovecha el alto uso de dispositivos móviles e Internet para ofrecer una solución innovadora en el campo de la protección ciudadana.
3 |
4 | ## Pasos para ejecutar el proyecto
5 | A continuación, se detallan los pasos necesarios para ejecutar el proyecto Backend de Seguridad ESPE en su entorno local:
6 |
7 | ### Requisitos previos
8 | Asegúrese de tener instalado [Node.js](https://nodejs.org/en) en su sistema.
9 |
10 | ### Clonar el repositorio
11 | ```
12 | git clone https://github.com/Vinici0/rest-server-movil-web.git
13 | cd rest-server-movil-web
14 | ```
15 | ### Instalar dependencias
16 | Ejecute el siguiente comando para instalar todas las dependencias del proyecto:
17 | ```
18 | npm install
19 | ```
20 | ### Configurar variables de entorno
21 |
22 | El proyecto utiliza variables de entorno para configuraciones sensibles. Cree un archivo .env en el directorio raíz del proyecto y configure las siguientes variables:
23 | ```
24 | PORT=3000 # Puerto en el que se ejecutará el servidor
25 | DB_CNN= # URI de la base de datos MongoDB
26 | JWT_KEY= # Clave secreta para JWT
27 | TOKEN_NOTIFICAIONES= # notificaciones
28 | ```
29 | ### Ejecutar el servidor
30 | El servidor estará disponible en ```http://localhost:3000```.
31 |
32 | ### Dependencias del proyecto
33 | A continuación, se enumeran las principales dependencias utilizadas en este proyecto:
34 |
35 | - **axios:** Realizar solicitudes HTTP.
36 | - **bcryptjs:** Realizar el hash de contraseñas.
37 | - **cors:** Configuración de políticas de acceso de origen cruzado.
38 | - **dotenv:** Cargar variables de entorno desde un archivo.
39 | - **express:** Framework de aplicación web.
40 | - **express-fileupload:** Procesar cargas de archivos.
41 | - **express-validator:** Validación de datos en Express.
42 | - **google-auth-library:** Autenticación con Google.
43 | - **html-pdf:** Generación de archivos PDF a partir de HTML.
44 | - **jsonwebtoken:** Implementación de JSON Web Tokens.
45 | - **lodash:** Utilidades de manipulación de datos.
46 | - **moment:** Manipulación de fechas y horas.
47 | - **mongoose:** Modelado de datos para MongoDB.
48 | - **pdfkit y pdfmake:** Generación de documentos PDF.
49 | - **socket.io:** Comunicación en tiempo real mediante WebSocket.
50 | - **uuid:** Generación de identificadores únicos.
51 |
52 | ### Contacto
53 | Si tienes alguna pregunta o comentario sobre este proyecto, no dudes en contactarme a través de mi perfil de [LinkedIn](https://www.linkedin.com/in/vinicio-borja-tapia/).
54 | ¡Gracias por su interés en el proyecto Backend de Seguridad ESPE!
55 |
56 |
--------------------------------------------------------------------------------
/helpers/enviar-notificacion.js:
--------------------------------------------------------------------------------
1 | const axios = require("axios");
2 | const { guardarNotificacion } = require("../controllers/notificaciones");
3 |
4 | const enviarNotificacion = async (tokens, titulo, desc, data = {}) => {
5 | if (tokens.length === 0) {
6 | console.log("No hay tokens");
7 | return;
8 | }
9 |
10 | try {
11 | const response = await axios.post(
12 | "https://fcm.googleapis.com/fcm/send",
13 | {
14 | notification: {
15 | title: titulo,
16 | body: desc,
17 | },
18 | priority: "high",
19 | data: {
20 | data: JSON.stringify(data),
21 | },
22 | registration_ids: tokens,
23 | },
24 | {
25 | headers: {
26 | "Content-Type": "application/json",
27 | Authorization: "key=" + process.env.TOKEN_NOTIFICAIONES,
28 | },
29 | }
30 | );
31 |
32 | console.log(response.data);
33 |
34 | } catch (error) {
35 | console.log(error);
36 | throw new Error("Error al enviar la notificación.");
37 | }
38 | };
39 |
40 | // Controlador para guardar una notificación relacionada con una publicación
41 | const guardarNotificacionPublicacion = async (
42 | usuario,
43 | mensaje,
44 | publicacionId,
45 | latitud,
46 | longitud,
47 | usuarioRemitente
48 | ) => {
49 | try {
50 | const notificacion = await guardarNotificacion(
51 | "publicacion",
52 | usuario,
53 | mensaje,
54 | publicacionId,
55 | null,
56 | latitud,
57 | longitud,
58 | usuarioRemitente
59 | );
60 |
61 | return notificacion;
62 | } catch (error) {
63 | console.log(error);
64 | throw new Error("Error al guardar la notificación de publicación");
65 | }
66 | };
67 |
68 | const guardarNotificacionPublicacionMensaje = async (
69 | usuario,
70 | mensaje,
71 | publicacionId,
72 | latitud,
73 | longitud,
74 | usuarioRemitente
75 | ) => {
76 | try {
77 | const notificacion = await guardarNotificacion(
78 | "mensaje",
79 | usuario,
80 | mensaje,
81 | publicacionId,
82 | null,
83 | latitud,
84 | longitud,
85 | usuarioRemitente
86 | );
87 |
88 | return notificacion;
89 | } catch (error) {
90 | console.log(error);
91 | throw new Error("Error al guardar la notificación de publicación");
92 | }
93 | };
94 |
95 | // Controlador para guardar una notificación relacionada con una solicitud
96 | const guardarNotificacionSOS = async (
97 | usuario,
98 | mensaje,
99 | telefonoUsuario,
100 | latitud,
101 | longitud,
102 | usuarioRemitente
103 | ) => {
104 | try {
105 | const notificacion = await guardarNotificacion(
106 | "sos",
107 | usuario,
108 | mensaje,
109 | null,
110 | telefonoUsuario,
111 | latitud,
112 | longitud,
113 | usuarioRemitente
114 | );
115 |
116 | return notificacion;
117 | } catch (error) {
118 | console.log(error);
119 | throw new Error("Error al guardar la notificación de solicitud");
120 | }
121 | };
122 |
123 | module.exports = {
124 | enviarNotificacion,
125 | guardarNotificacionPublicacion,
126 | guardarNotificacionSOS,
127 | guardarNotificacionPublicacionMensaje
128 | };
129 |
--------------------------------------------------------------------------------
/controllers/mensajes.js:
--------------------------------------------------------------------------------
1 | const { Usuario, Sala, Mensaje } = require("../models");
2 |
3 | const getMensajeByUser = async (req, res) => {
4 | const miId = req.uid;
5 |
6 | const mensajes = await Mensaje.find({
7 | usuario: miId,
8 | });
9 |
10 | res.json({
11 | ok: true,
12 | mensajes,
13 | });
14 | };
15 |
16 | const getAllMessages = async (req, res) => {
17 | const messages = await Mensaje.find();
18 | res.json({
19 | ok: true,
20 | messages,
21 | });
22 | };
23 |
24 | const getMensajeByRoom = async (req, res) => {
25 | const { salaId } = req.params;
26 | const { limite = 50, desde = 0 } = req.query;
27 | const usuarioId = req.uid;
28 |
29 | try {
30 | const sala = await Sala.findById(salaId)
31 | .populate({
32 | path: "mensajes",
33 | options: {
34 | skip: Number(desde),
35 | limit: Number(limite),
36 | sort: { createdAt: -1 },
37 | },
38 | })
39 | .lean();
40 |
41 | const mensajesSala = await Promise.all(
42 | sala.mensajes.map(async (mensaje) => {
43 |
44 | const usuarioMensaje = await Usuario.findById(mensaje.usuario);
45 |
46 | mensaje = { ...mensaje, nombre: usuarioMensaje.nombre, img: usuarioMensaje.img, isGoogle: usuarioMensaje.google };
47 | return mensaje;
48 | })
49 | );
50 |
51 | const usuario = await Usuario.findById(usuarioId);
52 |
53 | // Encontrar la entrada correspondiente en la lista de salas del usuario para la sala específica
54 | const salaUsuario = usuario.salas.find((salaUsuario) => salaUsuario.salaId.toString() === salaId);
55 |
56 | // Reiniciar el contador de mensajes no leídos (mensajesNoLeidos) a cero para esa entrada
57 | if (salaUsuario) {
58 | salaUsuario.mensajesNoLeidos = 0;
59 | await usuario.save();
60 | }
61 |
62 | res.json({
63 | ok: true,
64 | mensajesSala,
65 | });
66 | } catch (error) {
67 | console.log(error);
68 | res.status(500).json({
69 | ok: false,
70 | msg: "Por favor hable con el administrador",
71 | });
72 | }
73 | };
74 |
75 |
76 |
77 | const getMensajeByRoom2 = async (req, res) => {
78 | const { salaId } = req.params;
79 | const { limite = 50, desde = 0 } = req.query;
80 | const miId = req.uid;
81 |
82 | try {
83 | const sala = await Sala.findById(salaId)
84 | .populate({
85 | path: "mensajes",
86 | options: {
87 | skip: Number(desde),
88 | limit: Number(limite),
89 | sort: { createdAt: -1 },
90 | },
91 | })
92 | .lean();
93 |
94 | const mensajesSala = await Promise.all(
95 | sala.mensajes.map(async (mensaje) => {
96 | const usuarioMensaje = await Usuario.findById(mensaje.usuario);
97 | mensaje = { ...mensaje, nombre: usuarioMensaje.nombre, img: usuarioMensaje.img, isGoogle: usuarioMensaje.google };
98 | return mensaje;
99 | })
100 | );
101 |
102 | // Marcar los mensajes de la sala como leídos por el usuario
103 | const mensajesIds = mensajesSala.map((mensaje) => mensaje._id);
104 | await Mensaje.updateMany(
105 | { _id: { $in: mensajesIds }, leidoPor: { $ne: miId } },
106 | { $addToSet: { leidoPor: miId } }
107 | );
108 |
109 | res.json({
110 | ok: true,
111 | mensajesSala,
112 | });
113 | } catch (error) {
114 | console.log(error);
115 | res.status(500).json({
116 | ok: false,
117 | msg: "Por favor hable con el administrador",
118 | });
119 | }
120 | };
121 |
122 |
123 |
124 | module.exports = {
125 | getAllMessages,
126 | getMensajeByUser,
127 | getMensajeByRoom,
128 | };
129 |
--------------------------------------------------------------------------------
/controllers/ubicaciones.js:
--------------------------------------------------------------------------------
1 | const { Ubicacion, Usuario } = require("../models");
2 |
3 | const crearUbicacion = async (req, res = response) => {
4 | try {
5 | const ubicacion = new Ubicacion(req.body);
6 | await ubicacion.save();
7 | res.json({
8 | ok: true,
9 | ubicacion,
10 | });
11 | } catch (error) {
12 | console.log(error);
13 | res.status(500).json({
14 | ok: false,
15 | msg: "Error inesperado",
16 | });
17 | }
18 | };
19 |
20 | const obtenerUbicaciones = async (req, res = response) => {
21 | try {
22 | const ubicaciones = await Ubicacion.find();
23 | res.json({
24 | ok: true,
25 | ubicaciones,
26 | });
27 | } catch (error) {
28 | console.log(error);
29 | res.status(500).json({
30 | ok: false,
31 | msg: "Error inesperado",
32 | });
33 | }
34 | };
35 |
36 | const obtenerUbicacionesPorUsuario = async (req, res = response) => {
37 | const usuarioId = req.uid;
38 | try {
39 | const ubicaciones = await Ubicacion.find({ usuario: usuarioId });
40 | res.json({
41 | ok: true,
42 | ubicaciones,
43 | });
44 | } catch (error) {
45 | console.log(error);
46 | res.status(500).json({
47 | ok: false,
48 | msg: "Error inesperado",
49 | });
50 | }
51 | };
52 |
53 | const agregarUbicacion = async (req, res = response) => {
54 | const usuarioId = req.uid;
55 | const ubicacionId = req.params.id;
56 |
57 | try {
58 | const usuario = await Usuario.findById(usuarioId);
59 |
60 | if (!usuario) {
61 | return res.status(404).json({
62 | ok: false,
63 | msg: "Usuario no encontrado",
64 | });
65 | }
66 |
67 | const ubicacion = await Ubicacion.findById(ubicacionId);
68 |
69 | if (!ubicacion) {
70 | return res.status(404).json({
71 | ok: false,
72 | msg: "Ubicación no encontrada",
73 | });
74 | }
75 |
76 | // Verificar si la ubicación ya está asociada al usuario
77 | if (usuario.ubicaciones.includes(ubicacionId)) {
78 | return res.status(400).json({
79 | ok: false,
80 | msg: "La ubicación ya está asociada al usuario",
81 | });
82 | }
83 |
84 | // Agregar la ubicación al usuario
85 | usuario.ubicaciones.push(ubicacionId);
86 | await usuario.save();
87 |
88 | res.json(
89 | ubicacion,
90 | );
91 | } catch (error) {
92 | console.log(error);
93 | res.status(500).json({
94 | ok: false,
95 | msg: "Error inesperado",
96 | });
97 | }
98 | };
99 |
100 | //delete ubicacion por id
101 | const eliminarUbicacion = async (req, res = response) => {
102 | const usuarioId = req.uid;
103 | const ubicacionId = req.params.id;
104 |
105 | try {
106 | const usuario = await Usuario.findById(usuarioId);
107 |
108 | if (!usuario) {
109 | return res.status(404).json({
110 | ok: false,
111 | msg: "Usuario no encontrado",
112 | });
113 | }
114 |
115 | // Verificar si la ubicación está asociada al usuario
116 | if (!usuario.ubicaciones.includes(ubicacionId)) {
117 | return res.status(400).json({
118 | ok: false,
119 | msg: "La ubicación no está asociada al usuario",
120 | });
121 | }
122 |
123 | // Eliminar la ubicación del usuario
124 | await Usuario.findByIdAndUpdate(usuarioId, {
125 | $pull: { ubicaciones: ubicacionId },
126 | });
127 |
128 | res.json({
129 | ok: true,
130 | msg: "Ubicación eliminada del usuario exitosamente",
131 | });
132 | } catch (error) {
133 | console.log(error);
134 | res.status(500).json({
135 | ok: false,
136 | msg: "Error inesperado",
137 | });
138 | }
139 | };
140 |
141 | module.exports = {
142 | crearUbicacion,
143 | obtenerUbicaciones,
144 | obtenerUbicacionesPorUsuario,
145 | agregarUbicacion,
146 | eliminarUbicacion,
147 | };
148 |
--------------------------------------------------------------------------------
/controllers/notificaciones.js:
--------------------------------------------------------------------------------
1 | const { Notificacion } = require("../models");
2 |
3 | const obtenerNotificacionesUsuario = async (req, res) => {
4 | const usuarioId = req.uid;
5 | const { limite = 10, desde = 0 } = req.query;
6 |
7 | try {
8 | const notificaciones = await Notificacion.find({
9 | usuario: usuarioId,
10 | })
11 | .populate(
12 | "publicacion",
13 | "titulo contenido color ciudad barrio isPublic usuario likes imagenes latitud longitud comentarios imgAlerta isLiked createdAt updatedAt nombreUsuario isPublicacionPendiente"
14 | )
15 | .populate("usuarioRemitente", "nombre img telefono email google")
16 | .sort({ createdAt: -1 })
17 | .skip(Number(desde))
18 | .limit(Number(limite));
19 |
20 | //que solo
21 |
22 | res.json({
23 | ok: true,
24 | notificaciones,
25 | });
26 | } catch (error) {
27 | console.log(error);
28 | res.status(500).json({
29 | ok: false,
30 | msg: "Por favor hable con el administrador",
31 | });
32 | }
33 | };
34 |
35 | const marcarNotificacionComoLeida = async (req, res) => {
36 | const usuarioId = req.uid;
37 | const notificacionId = req.params.id;
38 |
39 | try {
40 | const notificacion = await Notificacion.findById(notificacionId);
41 |
42 | if (!notificacion) {
43 | return res.status(404).json({ mensaje: "Notificación no encontrada" });
44 | }
45 |
46 | notificacion.isLeida = true;
47 |
48 | await notificacion.save();
49 |
50 | res.json({
51 | ok: true,
52 | notificacion,
53 | });
54 | } catch (error) {
55 | console.log(error);
56 | res.status(500).json({
57 | ok: false,
58 | msg: "Por favor hable con el administrador",
59 | });
60 | }
61 | };
62 |
63 | // Controlador para guardar una nueva notificación
64 | const guardarNotificacion = async (
65 | tipo,
66 | usuario,
67 | mensaje,
68 | relacionadoId = null,
69 | telefonoUsuario = null,
70 | latitud,
71 | longitud,
72 | usuarioRemitente
73 | ) => {
74 | console.log("usuarioRemitente", usuarioRemitente);
75 | try {
76 | console.log(telefonoUsuario);
77 | const notificacion = new Notificacion({
78 | tipo,
79 | usuario,
80 | publicacion: tipo === "publicacion" || tipo === "mensaje" ? relacionadoId : null,
81 | telefonoDestino: tipo === "sos" ? telefonoUsuario : null,
82 | mensaje,
83 | latitud,
84 | longitud,
85 | usuarioRemitente,
86 | });
87 |
88 | await notificacion.save();
89 |
90 | // Aquí puedes realizar acciones adicionales relacionadas con la notificación, si es necesario
91 |
92 | return notificacion;
93 | } catch (error) {
94 | console.log(error);
95 | throw new Error("Error al guardar la notificación");
96 | }
97 | };
98 |
99 | //deleteAllNotifications
100 | const deleteAllNotifications = async (req, res) => {
101 | const usuarioId = req.uid;
102 |
103 | try {
104 | const notificaciones = await Notificacion.deleteMany({
105 | usuario: usuarioId,
106 | });
107 |
108 | res.json({
109 | ok: true,
110 | notificaciones,
111 | });
112 | } catch (error) {
113 | console.log(error);
114 | res.status(500).json({
115 | ok: false,
116 | msg: "Por favor hable con el administrador",
117 | });
118 | }
119 | };
120 |
121 | //deleteNotificationById
122 | const deleteNotificationById = async (req, res) => {
123 | const usuarioId = req.uid;
124 | const notificacionId = req.params.id;
125 |
126 | try {
127 | const notificacion = await Notificacion.findById(notificacionId);
128 |
129 | if (!notificacion) {
130 | return res.status(404).json({ mensaje: "Notificación no encontrada" });
131 | }
132 |
133 | await notificacion.delete();
134 |
135 | res.json({
136 | ok: true,
137 | notificacion,
138 | });
139 | } catch (error) {
140 | console.log(error);
141 | res.status(500).json({
142 | ok: false,
143 | msg: "Por favor hable con el administrador",
144 |
145 | });
146 | }
147 | };
148 |
149 | module.exports = {
150 | obtenerNotificacionesUsuario,
151 | guardarNotificacion,
152 | marcarNotificacionComoLeida,
153 | deleteAllNotifications,
154 | deleteNotificationById,
155 | };
156 |
--------------------------------------------------------------------------------
/controllers/socket.js:
--------------------------------------------------------------------------------
1 | const { enviarNotificacion } = require("../helpers/enviar-notificacion");
2 | const {
3 | Publicacion,
4 | Sala,
5 | Mensaje,
6 | Usuario,
7 | Comentario,
8 | } = require("../models");
9 |
10 | const usuarioConectado = async (uid = "") => {
11 | if (!uid) return null;
12 |
13 | const usuario = await Usuario.findById(uid);
14 | if (!usuario) return null;
15 |
16 | usuario.online = true;
17 | await usuario.save();
18 | return usuario;
19 | };
20 |
21 | const usuarioDesconectado = async (uid = "") => {
22 | if (!uid) return null;
23 |
24 | const usuario = await Usuario.findById(uid);
25 | if (!usuario) return null;
26 | usuario.online = false;
27 | await usuario.save();
28 | return usuario;
29 | };
30 |
31 | const grabarMensaje = async (payload) => {
32 | // payload: {
33 | // de: '',
34 | // para: '',
35 | // texto: ''
36 | // }
37 |
38 | try {
39 | console.log(payload);
40 | const mensaje = new Mensaje(payload);
41 | await mensaje.save();
42 |
43 | return true;
44 | } catch (error) {
45 | return false;
46 | }
47 | };
48 |
49 | const grabarMensajeSala2 = async (payload) => {
50 | try {
51 | const { mensaje, de, para } = payload;
52 | const sala = await Sala.findById(para);
53 |
54 | const newMessage = new Mensaje({ mensaje, usuario: de });
55 | await newMessage.save();
56 |
57 | sala.mensajes.push(newMessage._id);
58 | await sala.save();
59 |
60 | return true;
61 | } catch (error) {
62 | console.log(error);
63 | return false;
64 | }
65 | };
66 |
67 | const grabarMensajeSala = async (payload) => {
68 | try {
69 | const { mensaje, de, para } = payload;
70 |
71 | // console.log(payload);
72 | const newMessage = new Mensaje({ mensaje, usuario: de });
73 | await newMessage.save();
74 |
75 | const sala = await Sala.findById(para);
76 | sala.mensajes.push(newMessage._id);
77 | await sala.save();
78 |
79 | const usuariosEnGrupoOffline = await obtenerUsuariosSalaHelper(para, de);
80 |
81 | for (const usuario of usuariosEnGrupoOffline) {
82 | if (usuario._id.toString() === de) {
83 | continue;
84 | }
85 |
86 | //actualizar isSalasPendiente a true
87 | usuario.isSalasPendiente = true;
88 | usuario.isNotificacionesPendiente = true;
89 |
90 | usuario.salas = usuario.salas.map((sala) => {
91 | if (sala.salaId.toString() === para) {
92 | sala.mensajesNoLeidos++;
93 | sala.ultimaVezActivo = new Date();
94 | }
95 |
96 | return sala;
97 | });
98 |
99 | await usuario.save();
100 | }
101 |
102 | const tokens = usuariosEnGrupoOffline.map((usuario) => usuario.tokenApp);
103 | const titulo = "Nuevo mensaje";
104 | const desc = `Tienes un nuevo mensaje en el grupo ${sala.nombre}`;
105 |
106 | const data = {
107 | salaId: sala._id,
108 | nombre: sala.nombre,
109 | mensajesNoLeidos: sala.mensajesNoLeidos,
110 | ultimaVezActivo: sala.ultimaVezActivo,
111 | type: "sala",
112 | };
113 |
114 | const allTokens = [].concat(...tokens);
115 | //TODO: enviar notificación
116 | await enviarNotificacion(allTokens, titulo, desc, data);
117 | return true;
118 | } catch (error) {
119 | console.log(error);
120 | return false;
121 | }
122 | };
123 |
124 | const obtenerUsuariosSalaHelper = async (salaId, usuarioId) => {
125 | try {
126 | // El usuario que envía el mensaje
127 | const usuariosEnSala = await Usuario.find({
128 | "salas.salaId": salaId,
129 | "salas.isRoomOpen": false,
130 | _id: { $ne: usuarioId },
131 | });
132 |
133 | return usuariosEnSala;
134 | } catch (error) {
135 | console.log(error);
136 | return [];
137 | }
138 | };
139 |
140 | const grabarComentarioPublicacion = async (payload) => {
141 | console.log(payload);
142 | const usuarioId = payload.de;
143 | try {
144 | const { mensaje, para } = payload;
145 |
146 | const publicacion = await Publicacion.findById(para);
147 | if (!publicacion) {
148 | return res.status(404).json({ error: "Publicación no encontrada" });
149 | }
150 |
151 | const comentario = new Comentario({
152 | contenido: mensaje,
153 | usuario: usuarioId,
154 | publicacion: para,
155 | estado: "publicado",
156 | });
157 |
158 | await comentario.save();
159 |
160 | publicacion.comentarios.push(comentario._id);
161 | await publicacion.save();
162 |
163 | return comentario._id.toString();
164 | } catch (error) {
165 | console.error(error);
166 | return false;
167 | }
168 | };
169 |
170 | module.exports = {
171 | usuarioConectado,
172 | usuarioDesconectado,
173 | grabarMensaje,
174 | grabarMensajeSala,
175 | grabarComentarioPublicacion,
176 | };
177 |
--------------------------------------------------------------------------------
/controllers/auth.js:
--------------------------------------------------------------------------------
1 | const { response } = require("express");
2 | const bcrypt = require("bcryptjs");
3 |
4 | const Usuario = require("../models/usuario");
5 | const { generarJWT } = require("../helpers/jwt");
6 | const { validarGoogleIdToken } = require("../helpers/google-verify-token");
7 |
8 | const crearUsuario = async (req, res = response) => {
9 | const { email, password, tokenApp } = req.body;
10 |
11 | try {
12 | const existeEmail = await Usuario.findOne({ email });
13 | if (existeEmail) {
14 | return res.status(400).json({
15 | ok: false,
16 | msg: "El correo ya está registrado",
17 | });
18 | }
19 |
20 | const usuario = new Usuario(req.body);
21 |
22 | // Encriptar contraseña
23 | const salt = bcrypt.genSaltSync();
24 | usuario.password = bcrypt.hashSync(password, salt);
25 | usuario.tokenApp = tokenApp;
26 | await usuario.save();
27 |
28 | // Generar mi JWT
29 | const token = await generarJWT(usuario.id);
30 |
31 | res.json({
32 | ok: true,
33 | usuario,
34 | token,
35 | });
36 | } catch (error) {
37 | console.log(error);
38 | res.status(500).json({
39 | ok: false,
40 | msg: "Hable con el administrador",
41 | });
42 | }
43 | };
44 | const login = async (req, res = response) => {
45 | const { email, password, tokenApp } = req.body;
46 | console.log(req.body);
47 | try {
48 | const usuarioDB = await Usuario.findOne({ email })
49 | .populate(
50 | "ubicaciones",
51 | "latitud longitud ciudad pais barrio updatedAt createdAt estado _id"
52 | )
53 | .exec();
54 | if (!usuarioDB) {
55 | return res.status(404).json({
56 | ok: false,
57 | msg: "Email no encontrado",
58 | });
59 | }
60 |
61 | // Validar el password
62 | const validPassword = bcrypt.compareSync(password, usuarioDB.password);
63 | if (!validPassword) {
64 | return res.status(400).json({
65 | ok: false,
66 | msg: "La contraseña no es valida",
67 | });
68 | }
69 |
70 | // Actualizar el token de dispositivo si se proporciona
71 | if (tokenApp) {
72 | await Usuario.findOneAndUpdate({ email }, { tokenApp });
73 | }
74 |
75 | // Generar el JWT
76 | const token = await generarJWT(usuarioDB.id);
77 |
78 | res.json({
79 | ok: true,
80 | usuario: usuarioDB,
81 | token,
82 | });
83 | } catch (error) {
84 | console.log(error);
85 | return res.status(500).json({
86 | ok: false,
87 | msg: "Hable con el administrador",
88 | });
89 | }
90 | };
91 |
92 | const googleAuth = async (req, res = response) => {
93 | const token = req.body.token;
94 | const { tokenApp } = req.body;
95 | if (!token) {
96 | return res.json({
97 | ok: false,
98 | msg: "No hay token en la petición",
99 | });
100 | }
101 |
102 | const googleUser = await validarGoogleIdToken(token);
103 | const { email } = googleUser;
104 | try {
105 | if (!googleUser) {
106 | return res.status(400).json({
107 | ok: false,
108 | });
109 | }
110 |
111 | let usuarioDB = await Usuario.findOne({ email }).populate(
112 | "ubicaciones",
113 | "latitud longitud ciudad pais barrio updatedAt createdAt estado _id"
114 | );
115 |
116 | if (!usuarioDB) {
117 | // Si el usuario no existe, lo creamos
118 | const data = {
119 | nombre: googleUser.name,
120 | tokenApp: tokenApp,
121 | email: googleUser.email,
122 | password: "@@@",
123 | img: googleUser.picture,
124 | google: true,
125 | };
126 |
127 | usuarioDB = new Usuario(data);
128 |
129 | await usuarioDB.save();
130 | }
131 |
132 | // Actualizar el token de dispositivo si se proporciona
133 | if (tokenApp) {
134 | usuarioDB.tokenApp = tokenApp;
135 | await usuarioDB.save();
136 | }
137 |
138 | // Generar el JWT
139 | const token = await generarJWT(usuarioDB.id);
140 |
141 | return res.json({
142 | ok: true,
143 | usuario: usuarioDB,
144 | token,
145 | });
146 | } catch (error) {
147 | console.log(error);
148 | return res.status(500).json({
149 | ok: false,
150 | msg: "Hable con el administrador",
151 | });
152 | }
153 | };
154 | const renewToken = async (req, res = response) => {
155 | try {
156 | const uid = req.uid;
157 |
158 | // Generar un nuevo JWT usando el UID del usuario
159 | const token = await generarJWT(uid);
160 |
161 | // Obtener el usuario por el UID desde la base de datos
162 | const usuarioDB = await Usuario.findById(uid).populate(
163 | "ubicaciones",
164 | "latitud longitud ciudad pais barrio updatedAt createdAt estado _id"
165 | );
166 |
167 | if (!usuarioDB) {
168 | return res.status(404).json({
169 | ok: false,
170 | msg: "Usuario no encontrado",
171 | });
172 | }
173 |
174 | // Obtener el token de dispositivo (tokenApp) desde la solicitud
175 | const { tokenApp } = req.body;
176 |
177 | // Actualizar el token de dispositivo si se proporciona en la solicitud
178 | if (tokenApp) {
179 | usuarioDB.tokenApp = tokenApp;
180 | await usuarioDB.save();
181 | }
182 |
183 | // Devolver la respuesta con el nuevo token JWT y los datos del usuario
184 | res.json({
185 | ok: true,
186 | usuario: usuarioDB,
187 | token,
188 | });
189 | } catch (error) {
190 | console.log(error);
191 | return res.status(500).json({
192 | ok: false,
193 | msg: "Hable con el administrador",
194 | });
195 | }
196 | };
197 |
198 | module.exports = {
199 | crearUsuario,
200 | login,
201 | renewToken,
202 | googleAuth,
203 | };
204 |
--------------------------------------------------------------------------------
/controllers/uploads.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const fs = require("fs");
3 |
4 | const { response } = require("express");
5 | const { subirArchivoUsuario } = require("../helpers/subir-archivo");
6 |
7 | const { Usuario, Publicacion } = require("../models");
8 |
9 | const cargarArchivo = async (req, res = response) => {
10 | try {
11 | const nombres = [];
12 | for (const archivo of req.files.archivo) {
13 | const nombre = await subirArchivoUsuario(archivo, undefined, "imgs");
14 | nombres.push(nombre);
15 | }
16 | res.json({ nombres });
17 | } catch (msg) {
18 | res.status(400).json({ msg });
19 | }
20 | };
21 |
22 | const mostrarImagen = async (req, res = response) => {
23 | const { id, coleccion } = req.params;
24 |
25 | let modelo;
26 |
27 | switch (coleccion) {
28 | case "usuarios":
29 | modelo = await Usuario.findById(id);
30 | if (!modelo) {
31 | return res.status(400).json({
32 | msg: `No existe un usuario con el id ${id}`,
33 | });
34 | }
35 |
36 | break;
37 |
38 | case "publicaciones":
39 | modelo = await Publicacion.findById(id);
40 | if (!modelo) {
41 | return res.status(400).json({
42 | msg: `No existe un producto con el id ${id}`,
43 | });
44 | }
45 |
46 | break;
47 |
48 | default:
49 | return res.status(500).json({ msg: "Se me olvidó validar esto" });
50 | }
51 |
52 | const idqury = req.query.imagenIndex;
53 |
54 | //si no se especifica el id de la imagen se muestra todas las imagenes
55 |
56 | // Limpiar imágenes previas
57 | if (modelo.imagenes) {
58 | //motrar imagen si concide con el id del arreglo de imagenes
59 | const pathImagen = path.join(
60 | __dirname,
61 | "../uploads",
62 | coleccion + "/" + modelo.titulo.replace(/\s/g, ""),
63 | modelo.imagenes.find((img) => img === idqury)
64 | );
65 |
66 | if (fs.existsSync(pathImagen)) {
67 | //Sirve para verificar si existe el archivo en el path especificado
68 | return res.sendFile(pathImagen);
69 | }
70 | }
71 |
72 | const pathImagen = path.join(__dirname, "../assets/no-image.jpg");
73 | res.sendFile(pathImagen);
74 | };
75 |
76 | const mostrarAllImagenes = async (req, res = response) => {
77 | const { id, coleccion } = req.params;
78 |
79 | let modelo;
80 |
81 | switch (coleccion) {
82 | case "usuarios":
83 | modelo = await Usuario.findById(id);
84 | if (!modelo) {
85 | return res.status(400).json({
86 | msg: `No existe un usuario con el id ${id}`,
87 | });
88 | }
89 | break;
90 |
91 | case "publicaciones":
92 | modelo = await Publicacion.findById(id);
93 | if (!modelo) {
94 | return res.status(400).json({
95 | msg: `No existe una publicación con el id ${id}`,
96 | });
97 | }
98 | break;
99 |
100 | default:
101 | return res.status(500).json({ msg: "Se me olvidó validar esto" });
102 | }
103 |
104 | // Limpiar imágenes previas
105 | if (modelo.imagenes && modelo.imagenes.length > 0) {
106 | const pathImagenes = modelo.imagenes.map((imagenId) => {
107 | const pathImagen = path.join(
108 | __dirname,
109 | "../uploads",
110 | coleccion,
111 | imagenId
112 | );
113 | return fs.existsSync(pathImagen) ? pathImagen : null;
114 | });
115 |
116 | // Filtrar las rutas de imagen válidas
117 | const rutasValidas = pathImagenes.filter((ruta) => ruta !== null);
118 |
119 | if (rutasValidas.length > 0) {
120 | return res.json({ imagenes: rutasValidas });
121 | }
122 | }
123 |
124 | const pathImagen = path.join(__dirname, "../assets/no-image.jpg");
125 |
126 | res.sendFile(pathImagen);
127 | };
128 |
129 | const mostrarImagenUsuario = async (req, res = response) => {
130 | const { id, coleccion } = req.params;
131 |
132 | let modelo;
133 |
134 | switch (coleccion) {
135 | case "usuarios":
136 | modelo = await Usuario.findById(id);
137 | if (!modelo) {
138 | return res.status(400).json({
139 | msg: `No existe un usuario con el id ${id}`,
140 | });
141 | }
142 |
143 | break;
144 |
145 | default:
146 | return res.status(500).json({ msg: "Se me olvidó validar esto" });
147 | }
148 |
149 | // Limpiar imágenes previas
150 | if (modelo.img) {
151 | // Hay que borrar la imagen del servidor
152 | const pathImagen = path.join(
153 | __dirname,
154 | "../uploads",
155 | coleccion,
156 | modelo.img
157 | );
158 |
159 | if (fs.existsSync(pathImagen)) {
160 | return res.sendFile(pathImagen);//S
161 | }
162 | }
163 |
164 | const pathImagen = path.join(__dirname, "../assets/no-image.jpg");
165 | res.sendFile(pathImagen);
166 | };
167 |
168 | const actualizarImagen = async (req, res = response) => {
169 | const { id, coleccion } = req.params;
170 |
171 | let modelo;
172 |
173 | switch (coleccion) {
174 | case "usuarios":
175 | modelo = await Usuario.findById(id);
176 | if (!modelo) {
177 | return res.status(400).json({
178 | msg: `No existe un usuario con el id ${id}`,
179 | });
180 | }
181 |
182 | break;
183 |
184 | case "publicaciones":
185 | modelo = await Publicacion.findById(id);
186 | if (!modelo) {
187 | return res.status(400).json({
188 | msg: `No existe una publicación con el id ${id}`,
189 | });
190 | }
191 |
192 | break;
193 |
194 | default:
195 | return res.status(500).json({ msg: "Se me olvidó validar esto" });
196 | }
197 |
198 | if (modelo.img) {
199 | // Hay que borrar la imagen del servidor
200 | const pathImagen = path.join(
201 | __dirname,
202 | "../uploads",
203 | coleccion,
204 | modelo.img
205 | );
206 | if (fs.existsSync(pathImagen)) {
207 | fs.unlinkSync(pathImagen);
208 | }
209 | }
210 |
211 | const nombre = await subirArchivoUsuario(req.files, undefined, coleccion);
212 | modelo.img = nombre;
213 |
214 | await modelo.save();
215 |
216 | res.json(modelo);
217 | };
218 |
219 | module.exports = {
220 | cargarArchivo,
221 | mostrarImagen,
222 | mostrarAllImagenes,
223 | actualizarImagen,
224 | mostrarImagenUsuario,
225 | };
226 |
--------------------------------------------------------------------------------
/controllers/comentarios.js:
--------------------------------------------------------------------------------
1 | const {
2 | guardarNotificacionPublicacion,
3 | enviarNotificacion,
4 | guardarNotificacionPublicacionMensaje,
5 | } = require("../helpers/enviar-notificacion");
6 | const { Publicacion, Comentario, Usuario } = require("../models");
7 |
8 | const createComentario2 = async (req, res) => {
9 | const usuarioId = req.uid;
10 | try {
11 | const { contenido, publicacionId } = req.body;
12 |
13 | // Verificar si la publicación existe
14 | const publicacion = await Publicacion.findById(publicacionId);
15 | if (!publicacion) {
16 | return res.status(404).json({ error: "Publicación no encontrada" });
17 | }
18 |
19 | // Crear el nuevo comentario
20 | const comentario = new Comentario({
21 | contenido,
22 | usuario: usuarioId,
23 | publicacion: publicacionId,
24 | estado: "publicado",
25 | });
26 |
27 | // Guardar el comentario en la base de datos
28 | await comentario.save();
29 |
30 | // Agregar el comentario a la lista de comentarios de la publicación
31 | publicacion.comentarios.push(comentario._id);
32 | await publicacion.save();
33 | res.status(201).json({ comentario });
34 |
35 | publicacion.toObject();
36 | publicacion.type = "publication";
37 | delete publicacion.__v;
38 | // Obtener los IDs de los usuarios que han comentado en la publicación
39 | const usuariosQueComentaron = await Usuario.find({
40 | _id: { $in: publicacion.comentarios },
41 | });
42 |
43 | console.log(usuariosQueComentaron);
44 |
45 | // Obtener los tokens de los usuarios para enviar notificaciones
46 | const tokens = usuariosQueComentaron.map((usuario) => usuario.tokenApp);
47 | console.log(tokens);
48 | const titulo =
49 | "Nuevo comentario en una publicación en la que has comentado";
50 |
51 | // Envío de notificaciones a los usuarios
52 | // await enviarNotificacion(tokens, titulo, contenido, publicacion);
53 |
54 | // Guardar notificaciones de comentarios en la publicación
55 | // for (const usuario of usuariosQueComentaron) {
56 | // await guardarNotificacionPublicacion(
57 | // usuario._id.toString(),
58 | // contenido,
59 | // publicacion._id.toString(),
60 | // publicacion.latitud,
61 | // publicacion.longitud,
62 | // publicacion.usuario.toString()
63 | // );
64 | // }
65 | } catch (error) {
66 | console.error(error);
67 | res.status(500).json({ error: "Error al crear el comentario" });
68 | }
69 | };
70 |
71 | const createComentario = async (req, res) => {
72 | const usuarioId = req.uid;
73 | try {
74 | const { contenido, publicacionId } = req.body;
75 |
76 | // Verificar si la publicación existe
77 | const publicacion = await Publicacion.findById(publicacionId);
78 | if (!publicacion) {
79 | return res.status(404).json({ error: "Publicación no encontrada" });
80 | }
81 |
82 | // Crear el nuevo comentario
83 | const comentario = new Comentario({
84 | contenido,
85 | usuario: usuarioId,
86 | publicacion: publicacionId,
87 | estado: "publicado",
88 | });
89 |
90 | // Guardar el comentario en la base de datos
91 | await comentario.save();
92 |
93 | // Agregar el comentario a la lista de comentarios de la publicación
94 | publicacion.comentarios.push(comentario._id);
95 | await publicacion.save();
96 | res.status(201).json({ comentario });
97 |
98 | const publicacion2 = publicacion.toObject(); // Asignar la nueva instancia
99 | publicacion2.type = "publication";
100 | delete publicacion2.__v;
101 | console.log(publicacion2);
102 |
103 | // Obtener los comentarios relacionados con la publicación
104 | const comentariosDeLaPublicacion = await Comentario.find({ publicacion: publicacionId });
105 |
106 | // Obtener los IDs de los usuarios que han comentado
107 | const usuariosQueComentaronIds = comentariosDeLaPublicacion.map((comentario) => comentario.usuario);
108 |
109 | // Obtener los usuarios que han comentado
110 | const usuariosQueComentaron = await Usuario.find({ _id: { $in: usuariosQueComentaronIds } });
111 |
112 | // Obtener los tokens de los usuarios para enviar notificaciones
113 | const tokens = usuariosQueComentaron.map((usuario) => usuario.tokenApp);
114 | const titulo = "Comentaron en un reporte";
115 | const subTitulo = "Comentario en un reporte en el que has comentado";
116 | // Envío de notificaciones a los usuarios
117 | await enviarNotificacion(tokens, titulo, contenido, publicacion2);
118 |
119 | // Guardar notificaciones de comentarios en la publicación
120 | for (const usuario of usuariosQueComentaron) {
121 | await guardarNotificacionPublicacionMensaje(
122 | usuario._id.toString(),
123 | contenido,
124 | publicacion2._id.toString(),
125 | publicacion2.latitud,
126 | publicacion2.longitud,
127 | publicacion2.usuario.toString()
128 | );
129 | }
130 | } catch (error) {
131 | console.error(error);
132 | res.status(500).json({ error: "Error al crear el comentario" });
133 | }
134 | };
135 |
136 |
137 | const getComentariosByPublicacion = async (req, res) => {
138 | try {
139 | const { publicacionId } = req.params;
140 | // Buscar los comentarios de la publicación en la base de datos
141 | const comentarios = await Comentario.find({
142 | publicacion: publicacionId,
143 | }).populate("usuario", "nombre google img");
144 |
145 | res.status(200).json({
146 | ok: true,
147 | comentarios,
148 | });
149 | } catch (error) {
150 | console.error(error);
151 | res.status(500).json({ error: "Error al obtener los comentarios" });
152 | }
153 | };
154 |
155 | const toggleLikeComentario = async (req, res) => {
156 | try {
157 | const comentarioId = req.params.id;
158 |
159 | const comentario = await Comentario.findById(comentarioId).populate(
160 | "usuario",
161 | "nombre img"
162 | );
163 | if (!comentario) {
164 | return res.status(404).json({ error: "Comentario no encontrado" });
165 | }
166 |
167 | // Verificar si el usuario ya ha dado like al comentario
168 | const usuarioId = req.uid;
169 | const usuarioIndex = comentario.likes.findIndex(
170 | (userId) => userId.toString() === usuarioId
171 | );
172 |
173 | if (usuarioIndex === -1) {
174 | // El usuario no ha dado like al comentario, agregar el like
175 | comentario.likes.push(usuarioId);
176 | } else {
177 | // El usuario ya ha dado like al comentario, quitar el like
178 | comentario.likes.splice(usuarioIndex, 1);
179 | }
180 |
181 | await comentario.save();
182 |
183 | res.status(200).json({ ok: true, comentario: comentario });
184 | } catch (error) {
185 | console.error(error);
186 | res.status(500).json({ error: "Error al modificar el contador de likes" });
187 | }
188 | };
189 |
190 | module.exports = {
191 | createComentario,
192 | getComentariosByPublicacion,
193 | toggleLikeComentario,
194 | };
195 |
--------------------------------------------------------------------------------
/prueba/public/pdfTemplate.js:
--------------------------------------------------------------------------------
1 | module.exports = (dataInfo) => {
2 | console.log(dataInfo);
3 | const data = dataInfo.publicaciones;
4 |
5 | const today = new Date();
6 | const groupedData = {};
7 |
8 | data.forEach((item) => {
9 | if (!groupedData[item.titulo]) {
10 | groupedData[item.titulo] = [];
11 | }
12 | groupedData[item.titulo].push(item);
13 | });
14 |
15 | return `
16 |
17 |
18 |
19 |
20 | PDF Result Template
21 |
177 |
178 |
179 |
180 |
181 |

184 |
185 |
186 |
UNIVERSIDAD DE LAS FUERZAS ARMADAS - ESPE
187 | REPORTE DE EMERGENCIAS COMUNITARIAS
188 |
189 |
190 |

193 |
194 |
195 |
196 |
197 |
198 |
Usuario registrado
199 |
${data.totalUsuarios}
200 |
201 |
202 |
Publicaciones registradas
203 |
${data.length}
204 |
205 |
206 |
Publicaciones por mes
207 |
${data.totalPublicacionesMes}
208 |
209 |
210 |
Publicaciones por día
211 |
${data.totalPublicacionesDia}
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 | Reporte de Emergencias
223 | ${today.toLocaleDateString()}
224 |
225 | |
226 |
227 |
228 | | Título |
229 | Ciudad |
230 | Fecha de creación |
231 | Fecha de actualización |
232 | Hora de creación |
233 | Hora de actualización |
234 | Cantidad |
235 | Porcentaje |
236 |
237 | ${Object.entries(groupedData)
238 | .map(
239 | ([titulo, items]) => `
240 |
241 | | ${titulo} |
242 | ${items[0].ciudad} |
243 | ${items[0].createdAt.toLocaleDateString()} |
244 |
245 | ${items[items.length - 1].updatedAt.toLocaleDateString()}
246 | |
247 | ${items[0].createdAt.toLocaleTimeString()} |
248 |
249 | ${items[items.length - 1].updatedAt.toLocaleTimeString()}
250 | |
251 | ${items.length} |
252 |
253 | ${((items.length / data.length) * 100).toFixed(2)}%
254 | |
255 |
256 | `
257 | )
258 | .join("")}
259 |
260 |
261 | | Total |
262 | |
263 | |
264 | |
265 | |
266 | |
267 | ${data.length} |
268 | 100% |
269 |
270 |
271 |
272 |
273 |
274 |
275 | `;
276 | };
277 |
--------------------------------------------------------------------------------
/controllers/usuarios.js:
--------------------------------------------------------------------------------
1 | const { response } = require("express");
2 | const { Usuario } = require("../models");
3 | const {
4 | enviarNotificacion,
5 | guardarNotificacionSOS,
6 | } = require("../helpers/enviar-notificacion");
7 |
8 | const getUsuarios = async (req, res = response) => {
9 | const desde = Number(req.query.desde) || 0;
10 |
11 | const usuarios = await Usuario.find({ _id: { $ne: req.uid } })
12 | .sort("-online")
13 | .skip(desde)
14 | .limit(20);
15 |
16 | res.json({
17 | ok: true,
18 | usuarios,
19 | });
20 | };
21 |
22 | const actualizarUsuario = async (req, res) => {
23 | const uid = req.uid;
24 | const { nombre, email, online, password, telefono, ...resto } = req.body;
25 |
26 | try {
27 | // Busca y actualiza el usuario por su ID
28 | const usuario = await Usuario.findByIdAndUpdate(uid, resto, { new: true });
29 |
30 | res.json({
31 | ok: true,
32 | usuario,
33 | });
34 | } catch (error) {
35 | console.log(error);
36 | res.status(500).json({
37 | ok: false,
38 | msg: "Por favor hable con el administrador",
39 | });
40 | }
41 | };
42 |
43 | const actualizarIsOpenRoom = async (req, res) => {
44 | const uid = req.uid;
45 | const { isOpenRoom } = req.body;
46 |
47 | try {
48 | // Busca y actualiza el usuario por su ID
49 | const usuario = await Usuario.findByIdAndUpdate(
50 | uid,
51 | { isOpenRoom },
52 | { new: true }
53 | );
54 |
55 | res.json({
56 | ok: true,
57 | usuario,
58 | });
59 | } catch (error) {
60 | console.log(error);
61 | res.status(500).json({
62 | ok: false,
63 | msg: "Por favor hable con el administrador",
64 | });
65 | }
66 | };
67 |
68 | const actualizarTelefonoOrNombre = async (req, res) => {
69 | const uid = req.uid;
70 | const { nombre, telefono } = req.body;
71 | try {
72 | // Busca y actualiza el usuario por su ID
73 | const usuario = await Usuario.findByIdAndUpdate(
74 | uid,
75 | { nombre, telefono },
76 | { new: true }
77 | );
78 |
79 | res.json({
80 | ok: true,
81 | usuario,
82 | });
83 | } catch (error) {
84 | console.log(error);
85 | res.status(500).json({
86 | ok: false,
87 | msg: "Por favor hable con el administrador",
88 | });
89 | }
90 | };
91 |
92 | // Controlador para agregar una nueva dirección a un usuario
93 | const agregarDireccion = async (req, res) => {
94 | const idUsuario = req.uid;
95 | const { latitud, longitud } = req.body;
96 |
97 | try {
98 | const usuario = await Usuario.findById(idUsuario);
99 |
100 | if (!usuario) {
101 | return res.status(404).json({ mensaje: "Usuario no encontrado" });
102 | }
103 |
104 | const nuevaDireccion = {
105 | latitud,
106 | longitud,
107 | };
108 |
109 | usuario.direcciones.push(nuevaDireccion);
110 |
111 | await usuario.save();
112 |
113 | res.status(201).json({ mensaje: "Dirección agregada", usuario });
114 | } catch (error) {
115 | console.error(error);
116 | res.status(500).json({ mensaje: "Error al agregar la dirección" });
117 | }
118 | };
119 |
120 | const ageregarTelefonos = async (req, res) => {
121 | const idUsuario = req.uid;
122 |
123 | const { telefono } = req.body;
124 |
125 | try {
126 | const usuario = await Usuario.findById(idUsuario);
127 |
128 | if (!usuario) {
129 | return res.status(404).json({ mensaje: "Usuario no encontrado" });
130 | }
131 |
132 | // Verificar si el teléfono ya está asociado al usuario
133 | if (usuario.telefonos.includes(telefono)) {
134 | return res.status(400).json({
135 | ok: false,
136 | msg: "El teléfono ya está asociado al usuario",
137 | });
138 | }
139 |
140 | usuario.telefonos.push(telefono);
141 | await usuario.save();
142 |
143 | res.status(201).json({ mensaje: "Teléfono agregado", usuario });
144 | } catch (error) {
145 | console.error(error);
146 | res.status(500).json({ mensaje: "Error al agregar el teléfono" });
147 | }
148 | };
149 |
150 | const eliminarTelefono = async (req, res) => {
151 | const idUsuario = req.uid;
152 | const { telefono } = req.body;
153 |
154 | try {
155 | const usuario = await Usuario.findById(idUsuario);
156 |
157 | if (!usuario) {
158 | return res.status(404).json({ mensaje: "Usuario no encontrado" });
159 | }
160 |
161 | // Verificar si el teléfono está asociado al usuario
162 | if (!usuario.telefonos.includes(telefono)) {
163 | return res.status(400).json({
164 | ok: false,
165 | msg: "El teléfono no está asociado al usuario",
166 | });
167 | }
168 |
169 | // Eliminar el teléfono del arreglo
170 | usuario.telefonos = usuario.telefonos.filter((tel) => tel !== telefono);
171 | await usuario.save();
172 |
173 | res.status(200).json({ mensaje: "Teléfono eliminado", usuario });
174 | } catch (error) {
175 | console.error(error);
176 | res.status(500).json({ mensaje: "Error al eliminar el teléfono" });
177 | }
178 | };
179 |
180 | const agregarTelefono = async (req, res) => {
181 | const idUsuario = req.uid;
182 | const { telefono } = req.body;
183 |
184 | try {
185 | const usuario = await Usuario.findById(idUsuario);
186 |
187 | if (!usuario) {
188 | return res.status(404).json({ mensaje: "Usuario no encontrado" });
189 | }
190 |
191 | usuario.telefono = telefono;
192 | await usuario.save();
193 |
194 | res.status(201).json({ mensaje: "Teléfono agregado", usuario });
195 | } catch (error) {
196 | console.error(error);
197 | res.status(500).json({ mensaje: "Error al agregar el teléfono" });
198 | }
199 | };
200 |
201 | const enviarNotificacionesArrayTelefonos = async (req, res) => {
202 | const idUsuario = req.uid;
203 | const { lat, lng } = req.body;
204 |
205 | try {
206 | const usuario = await Usuario.findById(idUsuario).populate(
207 | "ubicaciones",
208 | "latitud longitud"
209 | );
210 |
211 | if (!usuario) {
212 | return res.status(404).json({ mensaje: "Usuario no encontrado" });
213 | }
214 |
215 | const telefonos = usuario.telefonos; // Obtener el arreglo de teléfonos del usuario
216 |
217 | const usuariosConTelefono = await Usuario.find({
218 | telefono: { $in: telefonos },
219 | });
220 | const tokens = usuariosConTelefono.map((usuario) => usuario.tokenApp);
221 |
222 | const titulo = `${usuario.nombre} necesita ayuda`;
223 | const contenido = "Presiona para ver la ubicación";
224 |
225 | //TODO: Notificación SOS
226 | const data = {
227 | nombre: usuario.nombre,
228 | latitud: lat,
229 | longitud: lng,
230 | img: usuario.img,
231 | google: usuario.google,
232 | type: "sos",
233 | };
234 |
235 | await enviarNotificacion(tokens, titulo, contenido, data);
236 |
237 | for (const usuarioDestino of usuariosConTelefono) {
238 | await guardarNotificacionSOS(
239 | usuarioDestino._id,
240 | contenido,
241 | usuario.telefono,
242 | lat,
243 | lng,
244 | idUsuario
245 | );
246 | //TODO: Verificar si el usuario tiene la app abierta
247 | usuarioDestino.isNotificacionesPendiente = true;
248 | await usuarioDestino.save();
249 | }
250 | res
251 | .status(200)
252 | .json({ mensaje: "Notificación enviada", usuarios: usuariosConTelefono });
253 | } catch (error) {
254 | console.error(error);
255 | res.status(500).json({ mensaje: "Error al enviar la notificación" });
256 | }
257 | };
258 |
259 | const marcarPublicacionPendienteFalse = async (req, res) => {
260 | const idUsuario = req.uid;
261 |
262 | try {
263 | const usuario = await Usuario.findById(idUsuario);
264 |
265 | if (!usuario) {
266 | return res.status(404).json({ mensaje: "Usuario no encontrado" });
267 | }
268 | usuario.isPublicacionPendiente = false;
269 | await usuario.save();
270 |
271 | res.status(200).json({
272 | mensaje: "Campo isPublicacionPendiente actualizado a false",
273 | usuario,
274 | });
275 | } catch (error) {
276 | console.error(error);
277 | res
278 | .status(500)
279 | .json({ mensaje: "Error al actualizar el campo isPublicacionPendiente" });
280 | }
281 | };
282 |
283 | const marcarSalaPendienteFalse = async (req, res) => {
284 | const idUsuario = req.uid;
285 |
286 | try {
287 | const usuario = await Usuario.findById(idUsuario);
288 |
289 | if (!usuario) {
290 | return res.status(404).json({ mensaje: "Usuario no encontrado" });
291 | }
292 |
293 | usuario.isSalasPendiente = false;
294 | await usuario.save();
295 |
296 | res
297 | .status(200)
298 | .json({ mensaje: "Campo isSalaPendiente actualizado a false", usuario });
299 | } catch (error) {
300 | console.error(error);
301 | res
302 |
303 | .status(500)
304 | .json({ mensaje: "Error al actualizar el campo isSalaPendiente" });
305 | }
306 | };
307 |
308 | //isNotificacionesPendiente
309 | const marcarNotificacionesPendienteFalse = async (req, res) => {
310 | const idUsuario = req.uid;
311 |
312 | try {
313 | const usuario = await Usuario.findById(idUsuario);
314 |
315 | if (!usuario) {
316 | return res.status(404).json({ mensaje: "Usuario no encontrado" });
317 | }
318 |
319 | usuario.isNotificacionesPendiente = false;
320 | await usuario.save();
321 |
322 | res.status(200).json({
323 | mensaje: "Campo isNotificacionesPendiente actualizado a false",
324 | usuario,
325 | });
326 | } catch (error) {
327 | console.error(error);
328 | res
329 | .status(500)
330 | .json({
331 | mensaje: "Error al actualizar el campo isNotificacionesPendiente",
332 | });
333 | }
334 | };
335 |
336 | const eliminarTokenApp = async (req, res) => {
337 | const uid = req.uid;
338 |
339 | try {
340 | // Busca y actualiza el usuario por su ID para eliminar el tokenApp
341 | const usuario = await Usuario.findByIdAndUpdate(
342 | uid,
343 | { $unset: { tokenApp: "" } },
344 | { new: true }
345 | );
346 |
347 | res.json({
348 | ok: true,
349 | usuario,
350 | msg: "El tokenApp ha sido eliminado correctamente.",
351 | });
352 | } catch (error) {
353 | console.log(error);
354 | res.status(500).json({
355 | ok: false,
356 | msg: "Por favor hable con el administrador",
357 | });
358 | }
359 | };
360 |
361 | module.exports = {
362 | getUsuarios,
363 | actualizarUsuario,
364 | agregarDireccion,
365 | ageregarTelefonos,
366 | agregarTelefono,
367 | eliminarTelefono,
368 | enviarNotificacionesArrayTelefonos,
369 | actualizarTelefonoOrNombre,
370 | actualizarIsOpenRoom,
371 | marcarPublicacionPendienteFalse,
372 | marcarSalaPendienteFalse,
373 | marcarNotificacionesPendienteFalse,
374 | eliminarTokenApp,
375 | };
376 |
--------------------------------------------------------------------------------
/controllers/publicaciones.js:
--------------------------------------------------------------------------------
1 | const { calcularDistancia } = require("../helpers/calcular-distancia");
2 | const {
3 | enviarNotificacion,
4 | guardarNotificacionPublicacion,
5 | } = require("../helpers/enviar-notificacion");
6 | const { subirArchivoPublicacion } = require("../helpers/subir-archivo");
7 | const { Usuario, Publicacion } = require("../models");
8 |
9 | const obtenerPublicacionesUsuario = async (req, res) => {
10 | const usuarioId = req.uid;
11 | try {
12 | const publicaciones = await Publicacion.find({ usuario: usuarioId });
13 |
14 | res.json({
15 | ok: true,
16 | publicaciones,
17 | });
18 | } catch (error) {
19 | console.log(error);
20 | res.status(500).json({
21 | ok: false,
22 | msg: "Por favor hable con el administrador",
23 | });
24 | }
25 | };
26 | const guardarPublicacion = async (req, res) => {
27 | const radio = 2;
28 | const usuarioId = req.uid;
29 | const nombres = [];
30 | const {
31 | titulo,
32 | contenido,
33 | color,
34 | ciudad,
35 | barrio,
36 | isPublic,
37 | imagenes,
38 | imgAlerta,
39 | latitud,
40 | longitud,
41 | nombreUsuario,
42 | } = req.body;
43 |
44 | try {
45 | const publicacion = new Publicacion({
46 | titulo,
47 | contenido,
48 | color,
49 | ciudad,
50 | barrio,
51 | isPublic,
52 | usuario: usuarioId,
53 | imagenes,
54 | imgAlerta,
55 | latitud,
56 | longitud,
57 | nombreUsuario,
58 | });
59 | await publicacion.save();
60 |
61 | res.json({
62 | ok: true,
63 | publicacion,
64 | });
65 |
66 | const usuarios = await Usuario.find().populate(
67 | "ubicaciones",
68 | "latitud longitud tokenApp"
69 | );
70 |
71 | const usuariosEnRadio = usuarios.filter((usuario) => {
72 | return usuario.ubicaciones.some((ubicacion) => {
73 | const distancia = calcularDistancia(
74 | ubicacion.latitud,
75 | ubicacion.longitud,
76 | latitud,
77 | longitud
78 | );
79 | return distancia <= radio;
80 | });
81 | });
82 |
83 | const tokens = usuariosEnRadio
84 | .filter((usuario) => usuario._id.toString() !== usuarioId.toString())
85 | .map((usuario) => usuario.tokenApp);
86 |
87 | // Actualizar el campo isPublicacionPendiente a true para todos los usuarios en usuariosEnRadio
88 | for (const usuario of usuariosEnRadio) {
89 | usuario.isPublicacionPendiente = true;
90 | usuario.isNotificacionesPendiente = true;
91 | await usuario.save();
92 | }
93 |
94 | //TODO: Notificar a los usuarios en el radio
95 | const publicacion2 = publicacion.toObject();
96 | publicacion2.type = "publication";
97 | console.log(publicacion2);
98 | delete publicacion2.__v;
99 | await enviarNotificacion(tokens, titulo, contenido, publicacion2);
100 |
101 | const usuariosEnRadio2 = usuariosEnRadio.filter((usuario) => usuario._id.toString() !== usuarioId.toString());
102 |
103 | for (const usuario of usuariosEnRadio2) {
104 | await guardarNotificacionPublicacion(
105 | usuario._id,
106 | contenido,
107 | publicacion._id,
108 | latitud,
109 | longitud,
110 | usuarioId
111 | );
112 | }
113 | } catch (error) {
114 | console.log(error);
115 | res.status(500).json({
116 | ok: false,
117 | msg: "Por favor hable con el administrador",
118 | });
119 | }
120 | };
121 |
122 | const guardarListArchivo = async (req, res) => {
123 | const nombres = [];
124 | const { titulo, uid } = req.params;
125 |
126 | const archivo = req.files?.archivo;
127 |
128 | try {
129 | const publicacion = await Publicacion.findById(uid);
130 |
131 | if (!publicacion) {
132 | return res.status(404).json({ mensaje: "Publicación no encontrada" });
133 | }
134 | if (archivo !== undefined && archivo !== null) {
135 | if (Array.isArray(archivo)) {
136 | for (const file of archivo) {
137 | const nombre = await subirArchivoPublicacion(
138 | file,
139 | undefined,
140 | "publicaciones/" + titulo.replace(/\s/g, "")
141 | );
142 | if (!publicacion.imagenes) {
143 | publicacion.imagenes = []; // Inicializar como un array vacío si es nulo
144 | }
145 | publicacion.imagenes.push(nombre);
146 | nombres.push(nombre);
147 | }
148 | } else {
149 | const nombre = await subirArchivoPublicacion(
150 | archivo,
151 | undefined,
152 | "publicaciones/" + titulo.replace(/\s/g, "")
153 | );
154 | if (!publicacion.imagenes) {
155 | publicacion.imagenes = []; // Inicializar como un array vacío si es nulo
156 | }
157 | publicacion.imagenes.push(nombre);
158 | nombres.push(nombre);
159 | }
160 | }
161 |
162 | await publicacion.save();
163 |
164 | res.json({
165 | ok: true,
166 | publicacion,
167 | nombres,
168 | });
169 | } catch (error) {
170 | console.log(error);
171 | res.status(500).json({
172 | ok: false,
173 | msg: "Por favor hable con el administrador",
174 | });
175 | }
176 | };
177 |
178 | const getPublicacionesEnRadio = async (req, res) => {
179 | const radio = 2; // Radio en kilómetros
180 | const { limite = 15, desde = 0 } = req.query;
181 | try {
182 | const usuario = await Usuario.findById(req.uid).populate(
183 | "ubicaciones",
184 | "latitud longitud"
185 | );
186 |
187 | if (!usuario) {
188 | return res.status(404).json({ mensaje: "Usuario no encontrado." });
189 | }
190 |
191 | let publicacionesEnRadio;
192 |
193 | if (usuario.ubicaciones.length > 0) {
194 | publicacionesEnRadio = await Publicacion.find({
195 | latitud: { $exists: true },
196 | longitud: { $exists: true },
197 | isActivo: true,
198 | })
199 | .sort({ createdAt: -1 })
200 | .skip(Number(desde));
201 |
202 | publicacionesEnRadio = publicacionesEnRadio.filter((publicacion) => {
203 | return usuario.ubicaciones.some((direccion) => {
204 | const distancia = calcularDistancia(
205 | publicacion.latitud,
206 | publicacion.longitud,
207 | direccion.latitud,
208 | direccion.longitud
209 | );
210 |
211 | return distancia <= radio;
212 | });
213 | });
214 | } else {
215 | publicacionesEnRadio = await Publicacion.find({ isActivo: true })
216 | .sort({ createdAt: -1 })
217 | .skip(Number(desde));
218 | }
219 |
220 | publicacionesEnRadio = publicacionesEnRadio.slice(0, Number(limite));
221 |
222 | res.json({
223 | ok: true,
224 | publicaciones: publicacionesEnRadio,
225 | });
226 | } catch (error) {
227 | console.error(error);
228 | res.status(500).json({ mensaje: "Error al obtener las publicaciones." });
229 | }
230 | };
231 |
232 | const dislikePublicacion = async (req, res) => {
233 | try {
234 | const publicacionId = req.params.id;
235 |
236 | // Verificar si la publicación existe
237 | const publicacion = await Publicacion.findById(publicacionId);
238 | if (!publicacion) {
239 | return res.status(404).json({ error: "Publicación no encontrada" });
240 | }
241 |
242 | // Verificar si el contador de likes es mayor a cero antes de decrementar
243 | if (publicacion.likes > 0) {
244 | publicacion.likes -= 1;
245 | await publicacion.save();
246 | }
247 |
248 | res.status(200).json({ likes: publicacion.likes });
249 | } catch (error) {
250 | console.error(error);
251 | res
252 | .status(500)
253 | .json({ error: "Error al decrementar el contador de likes" });
254 | }
255 | };
256 |
257 | //update publicacion
258 | const updatePublicacion = async (req, res) => {
259 | const { id } = req.params;
260 | const { isLiked, likes } = req.body;
261 |
262 | try {
263 | const publicacion = await Publicacion.findById(id);
264 |
265 | if (!publicacion) {
266 | return res.status(404).json({ mensaje: "Publicacion no encontrada" });
267 | }
268 |
269 | const nuevaPublicacion = {
270 | isLiked,
271 | likes,
272 | usuario: req.uid,
273 | };
274 |
275 | const publicacionActualizada = await Publicacion.findByIdAndUpdate(
276 | id,
277 | nuevaPublicacion,
278 | { new: true }
279 | );
280 |
281 | res.json({
282 | ok: true,
283 | publicacion: publicacionActualizada,
284 | });
285 | } catch (error) {
286 | console.log(error);
287 | res.status(500).json({
288 | ok: false,
289 | mensaje: "Error inesperado",
290 | });
291 | }
292 | };
293 |
294 | const updatePublicacion2 = async (req, res) => {
295 | const { id } = req.params;
296 | const { likes } = req.body;
297 |
298 | try {
299 | const publicacion = await Publicacion.findById(id);
300 |
301 | if (!publicacion) {
302 | return res.status(404).json({ mensaje: "Publicacion no encontrada" });
303 | }
304 |
305 | const nuevaPublicacion = {
306 | likes,
307 | usuario: req.uid,
308 | };
309 |
310 | const publicacionActualizada = await Publicacion.findByIdAndUpdate(
311 | id,
312 | nuevaPublicacion,
313 | { new: true }
314 | );
315 |
316 | res.json({
317 | ok: true,
318 | publicacion: publicacionActualizada,
319 | });
320 | } catch (error) {
321 | console.log(error);
322 | res.status(500).json({
323 | ok: false,
324 | mensaje: "Error inesperado",
325 | });
326 | }
327 | };
328 |
329 | const obtenerPublicacionesUsuarioConLikes = async (req, res) => {
330 | const usuarioId = req.uid; // ID del usuario obtenido del token de autenticación
331 |
332 | try {
333 | const publicaciones = await Publicacion.find({ usuario: usuarioId });
334 |
335 | const publicacionesConLikes = publicaciones.filter(
336 | (publicacion) => publicacion.isLiked
337 | );
338 |
339 | res.json({
340 | ok: true,
341 | publicacionesConLikes,
342 | });
343 | } catch (error) {
344 | console.log(error);
345 | res.status(500).json({
346 | ok: false,
347 | msg: "Por favor hable con el administrador",
348 | });
349 | }
350 | };
351 |
352 | //update like publicacion
353 | const likePublicacion = async (req, res) => {
354 | try {
355 | const publicacionId = req.params.id;
356 | const usuarioId = req.uid;
357 |
358 | // Verificar si la publicación existe
359 | const publicacion = await Publicacion.findById(publicacionId);
360 | if (!publicacion) {
361 | return res.status(404).json({ error: "Publicación no encontrada" });
362 | }
363 |
364 | // Verificar si el usuario ya ha dado like a la publicación
365 | const usuarioYaDioLike = publicacion.likes.includes(usuarioId.toString());
366 |
367 | if (!usuarioYaDioLike) {
368 | // Agregar el ID del usuario a la lista de likes
369 | publicacion.likes.push(usuarioId);
370 | } else {
371 | // Eliminar el ID del usuario de la lista de likes
372 | publicacion.likes = publicacion.likes.filter(
373 | (id) => id.toString() !== usuarioId.toString()
374 | );
375 | }
376 |
377 | await publicacion.save();
378 |
379 | res.status(200).json({ publicacion });
380 | } catch (error) {
381 | console.error(error);
382 | res.status(500).json({ error: "Error al gestionar el like" });
383 | }
384 | };
385 |
386 | //isPublicacionPendiente a true
387 | const isPublicacionFinalizada = async (req, res) => {
388 | const usuarioId = req.uid;
389 |
390 | try {
391 | const { publicacionId } = req.params;
392 |
393 | // Verificar si la publicación existe
394 | const publicacion = await Publicacion.findById(publicacionId);
395 | if (!publicacion) {
396 | return res.status(404).json({ error: "Publicación no encontrada" });
397 | }
398 |
399 | // Verificar si el usuario es el dueño de la publicación
400 | if (publicacion.usuario.toString() !== usuarioId) {
401 | return res.status(401).json({ error: "No autorizado para modificar esta publicación" });
402 | }
403 |
404 | // Cambiar el estado de isPublicacionPendiente a true
405 | publicacion.isPublicacionPendiente = true;
406 | await publicacion.save();
407 |
408 | res.status(200).json({ message: "La publicación se ha finalizado" });
409 | } catch (error) {
410 | console.error(error);
411 | res.status(500).json({ error: "Error al marcar la publicación como pendiente" });
412 | }
413 | };
414 |
415 | //delete publicacion
416 | const deletePublicacion = async (req, res) => {
417 | const { id } = req.params;
418 | try {
419 | await Publicacion.findByIdAndDelete(id);
420 | // await Publicacion.findByIdAndUpdate(id, { isActivo: false });
421 | res.status(200).json({ message: "Publicación eliminada con éxito" });
422 | } catch (error) {
423 | res.status(500).json({ message: "Error al eliminar la publicación" });
424 | }
425 | };
426 |
427 | const actualizarDescripcion = async (req, res) => {
428 | const { id } = req.params;
429 | const { descripcion } = req.body;
430 |
431 | try {
432 | if (!descripcion) {
433 | return res.status(400).json({ mensaje: "La descripción es obligatoria" });
434 | }
435 |
436 | //actualizar
437 | await Publicacion.findByIdAndUpdate(id, { contenido: descripcion });
438 |
439 | res.json({
440 | ok: true,
441 | mensaje: "Descripción actualizada con éxito",
442 | });
443 | } catch (error) {
444 | console.log(error);
445 | res.status(500).json({
446 | ok: false,
447 | mensaje: "Error inesperado",
448 | });
449 | }
450 | };
451 |
452 |
453 | module.exports = {
454 | obtenerPublicacionesUsuario,
455 | guardarPublicacion,
456 | getPublicacionesEnRadio,
457 | likePublicacion,
458 | dislikePublicacion,
459 | updatePublicacion,
460 | updatePublicacion2,
461 | obtenerPublicacionesUsuarioConLikes,
462 | guardarListArchivo,
463 | isPublicacionFinalizada,
464 | deletePublicacion,
465 | actualizarDescripcion
466 | };
467 |
--------------------------------------------------------------------------------
/controllers/salas.js:
--------------------------------------------------------------------------------
1 | const { Mensaje, Sala, Usuario } = require("../models");
2 |
3 | const { generarCodigoUnico } = require("../helpers/generar-aleatorio");
4 | const _ = require("lodash");
5 | const { enviarNotificacion } = require("../helpers/enviar-notificacion");
6 | // const { obtenerUsuariosSalaHelper } = require("../helpers/obtener-usuario");
7 |
8 | const obtenerMensajesSala = async (req, res) => {
9 | const { codigo } = req.params;
10 |
11 | try {
12 | const sala = await Sala.findOne({ codigo }).populate("mensajes");
13 | if (!sala) {
14 | return res.status(404).json({
15 | ok: false,
16 | msg: "Sala no encontrada",
17 | });
18 | }
19 |
20 | res.json({
21 | ok: true,
22 | mensajes: sala.mensajes,
23 | });
24 | } catch (error) {
25 | console.log(error);
26 | res.status(500).json({
27 | ok: false,
28 | msg: "Por favor hable con el administrador",
29 | });
30 | }
31 | };
32 |
33 | // Paso 2: Modificar el controlador crearSala
34 |
35 | const crearSala = async (req, res) => {
36 | const { nombre } = req.body;
37 | let codigo;
38 | let salaExistente;
39 |
40 | do {
41 | codigo = generarCodigoUnico();
42 | salaExistente = await Sala.findOne({ codigo });
43 | } while (salaExistente);
44 |
45 | const colorRandom = Array.from({ length: 3 }, () =>
46 | Math.floor(Math.random() * 256)
47 | );
48 | const color = colorRandom.reduce(
49 | (acc, curr) => acc + curr.toString(16).padStart(2, "0")
50 | );
51 |
52 | try {
53 | const sala = new Sala({ nombre, codigo, color, propietario: req.uid });
54 |
55 | // Agregar el uid del creador a la lista de usuarios de la sala
56 | sala.usuarios.push(req.uid);
57 |
58 | await sala.save();
59 |
60 | // Agregar la sala creada a la lista de salas del usuario
61 | const usuario = await Usuario.findById(req.uid);
62 | usuario.salas.push({
63 | salaId: sala._id,
64 | mensajesNoLeidos: 0,
65 | ultimaVezActivo: null,
66 | isRoomOpen: false,
67 | });
68 | await usuario.save();
69 |
70 | const uid = req.uid;
71 | const salaResponse = _.pick(sala.toObject(), [
72 | "nombre",
73 | "codigo",
74 | "color",
75 | "mensajes",
76 | "usuarios",
77 | "propietario",
78 | "_id",
79 | ]);
80 | salaResponse.totalUsuarios = sala.usuarios.length;
81 | salaResponse.idUsuario = uid;
82 | res.json({
83 | ok: true,
84 | sala: salaResponse,
85 | });
86 | } catch (error) {
87 | console.log(error);
88 | res.status(500).json({
89 | ok: false,
90 | msg: "Por favor hable con el administrador",
91 | });
92 | }
93 | };
94 |
95 | const unirseSala = async (req, res) => {
96 | const { codigo } = req.body;
97 | const uid = req.uid;
98 |
99 | try {
100 | const sala = await Sala.findOne({ codigo });
101 |
102 | if (!sala) {
103 | return res.status(404).json({
104 | ok: false,
105 | msg: "Sala no encontrada",
106 | });
107 | }
108 |
109 | // Verificar si el usuario ya está en la sala
110 | if (sala.usuarios.includes(uid)) {
111 | return res.status(400).json({
112 | ok: false,
113 | msg: "El usuario ya está en la sala",
114 | });
115 | }
116 |
117 | // Agregar al usuario a la lista de usuarios de la sala
118 | sala.usuarios.push(uid);
119 | await sala.save();
120 |
121 | // Agregar la sala a la lista de salas del usuario
122 | const usuario = await Usuario.findById(uid);
123 | usuario.salas.push({
124 | salaId: sala._id,
125 | mensajesNoLeidos: 0, // Inicializar a cero mensajes no leídos al unirse a la sala
126 | ultimaVezActivo: null, // Inicializar como null ya que aún no ha enviado mensajes en esta sala
127 | });
128 | await usuario.save();
129 |
130 | const salaResponse = _.pick(sala.toObject(), [
131 | "nombre",
132 | "codigo",
133 | "color",
134 | "usuarios",
135 | "propietario",
136 | "_id",
137 | ]);
138 | salaResponse.idUsuario = uid;
139 | salaResponse.totalUsuarios = sala.usuarios.length;
140 | res.json({
141 | ok: true,
142 | sala: salaResponse,
143 | });
144 | } catch (error) {
145 | console.log(error);
146 | res.status(500).json({
147 | ok: false,
148 | msg: "Por favor hable con el administrador",
149 | });
150 | }
151 | };
152 |
153 | const grabarMensajeSala = async (req, res) => {
154 | try {
155 | const { mensaje, salaId } = req.body;
156 | const usuarioId = req.uid;
157 |
158 | const newMessage = new Mensaje({ mensaje, usuario: usuarioId });
159 | await newMessage.save();
160 |
161 | const sala = await Sala.findById(salaId);
162 | sala.mensajes.push(newMessage._id);
163 | await sala.save();
164 |
165 | const usuariosEnGrupoOffline = await obtenerUsuariosSalaHelper(salaId);
166 |
167 | // Actualizar la cantidad de mensajes no leídos solo para los usuarios offline en el grupo
168 | for (const usuario of usuariosEnGrupoOffline) {
169 | usuario.salas = usuario.salas.map((sala) => {
170 | if (sala.salaId.toString() === salaId) {
171 | sala.mensajesNoLeidos++;
172 | sala.ultimaVezActivo = new Date();
173 | }
174 |
175 | return sala;
176 | });
177 | }
178 |
179 | await Promise.all(usuariosEnGrupoOffline.map((usuario) => usuario.save()));
180 |
181 | res.json({
182 | ok: true,
183 | sala: sala,
184 | });
185 | } catch (error) {
186 | console.log(error);
187 | res.status(500).json({
188 | ok: false,
189 | msg: "Por favor hable con el administrador",
190 | });
191 | }
192 | };
193 |
194 | /*
195 | obtenerUsuariosSalaHelper
196 | Esta función obtiene los usuarios de una sala que están offline y que no han abierto la sala en la aplicación.
197 | */
198 | const obtenerUsuariosSalaHelper = async (salaId) => {
199 | try {
200 | const usuariosEnSala = await Usuario.find({
201 | "salas.salaId": salaId,
202 | "salas.isRoomOpen": false,
203 | });
204 | return usuariosEnSala;
205 | } catch (error) {
206 | console.log(error);
207 | return [];
208 | }
209 | };
210 |
211 | const cambiarEstadoSala = async (req, res) => {
212 | try {
213 | const { isRoomOpen } = req.body;
214 | const userId = req.uid;
215 |
216 | // Encuentra el usuario por su ID
217 | const usuario = await Usuario.findById(userId);
218 |
219 | if (!usuario) {
220 | return res.status(404).json({
221 | ok: false,
222 | msg: "Usuario no encontrado",
223 | });
224 | }
225 |
226 | // Find the sala with the given salaId in the salas array
227 | const salaToUpdate = usuario.salas.find(
228 | (sala) => sala.salaId.toString() === req.params.salaId
229 | );
230 |
231 | if (!salaToUpdate) {
232 | return res.status(404).json({
233 | ok: false,
234 | msg: "Sala no encontrada para el usuario",
235 | });
236 | }
237 |
238 | // Update the isRoomOpen property for the found sala
239 | salaToUpdate.isRoomOpen = isRoomOpen;
240 |
241 | await usuario.save();
242 |
243 | return res.json({
244 | ok: true,
245 | msg: "Estado de la sala actualizado exitosamente",
246 | usuario: usuario,
247 | });
248 | } catch (error) {
249 | console.log(error);
250 | res.status(500).json({
251 | ok: false,
252 | msg: "Por favor hable con el administradorrr",
253 | });
254 | }
255 | };
256 |
257 | const obtenerSalasConMensajesNoLeidos = async (req, res) => {
258 | const usuarioId = req.uid;
259 |
260 | try {
261 | const usuario = await Usuario.findById(usuarioId);
262 | const salas = usuario.salas;
263 | const salasConMensajesNoLeidos = [];
264 | for (const sala of salas) {
265 | // Obtener la información de la sala
266 | const salaInfo = await Sala.findById(sala.salaId);
267 | // Obtener el total de usuarios en la sala
268 | const totalUsuariosSala = salaInfo.usuarios.length;
269 | // Si la sala tiene mensajes no leídos, se agrega al array con la cantidad de mensajes no leídos y el total de usuarios
270 | if (sala.mensajesNoLeidos > 0) {
271 | salasConMensajesNoLeidos.push({
272 | uid: salaInfo._id,
273 | nombre: salaInfo.nombre,
274 | color: salaInfo.color,
275 | propietario: salaInfo.propietario,
276 | codigo: salaInfo.codigo,
277 | mensajesNoLeidos: sala.mensajesNoLeidos,
278 | totalUsuarios: totalUsuariosSala,
279 | });
280 | } else {
281 | // Si la sala no tiene mensajes no leídos, se agrega al array con 0 mensajes no leídos y el total de usuarios
282 | salasConMensajesNoLeidos.push({
283 | uid: salaInfo._id,
284 | nombre: salaInfo.nombre,
285 | color: salaInfo.color,
286 | codigo: salaInfo.codigo,
287 | propietario: salaInfo.propietario,
288 | mensajesNoLeidos: 0,
289 | totalUsuarios: totalUsuariosSala,
290 | });
291 | }
292 | }
293 |
294 | res.json({
295 | ok: true,
296 | salas: salasConMensajesNoLeidos,
297 | });
298 | } catch (error) {
299 | console.log(error);
300 | res.status(500).json({
301 | ok: false,
302 | msg: "Por favor hable con el administrador",
303 | });
304 | }
305 | };
306 |
307 | const getSalas = async (req, res) => {
308 | const uid = req.uid;
309 | const salas = await Sala.find(
310 | {},
311 | { nombre: 1, codigo: 1, _id: 1, usuarios: 1, color: 1, propietario: 1 }
312 | );
313 |
314 | res.json({
315 | ok: true,
316 | salas,
317 | });
318 | };
319 |
320 | const obtenerSalasMensajesUsuario = async (req, res) => {
321 | const uid = req.uid;
322 |
323 | try {
324 | const salas = await Sala.find({ usuarios: uid }).populate("mensajes");
325 | res.json({
326 | ok: true,
327 | salas,
328 | });
329 | } catch (error) {
330 | console.log(error);
331 | res.status(500).json({
332 | ok: false,
333 | msg: "Por favor hable con el administrador",
334 | });
335 | }
336 | };
337 |
338 | const getSalasByUser = async (req, res) => {
339 | const uid = req.uid;
340 | try {
341 | const salas = await Sala.find(
342 | { usuarios: uid, isActivo: true },
343 | { nombre: 1, _id: 1, color: 1, codigo: 1, propietario: 1 }
344 | );
345 |
346 | const totalUsuarios = await Sala.find({ usuarios: uid }).countDocuments();
347 | res.json({
348 | ok: true,
349 | salas,
350 | totalUsuarios,
351 | });
352 | } catch (error) {
353 | console.log(error);
354 | res.status(500).json({
355 | ok: false,
356 | msg: "Por favor hable con el administrador",
357 | });
358 | }
359 | };
360 |
361 | const getMensajesBySala = async (req, res) => {
362 | const { salaId } = req.params;
363 | try {
364 | const sala = await Sala.findById(salaId)
365 | .populate("mensajes")
366 | .populate("usuarios");
367 |
368 | res.json({
369 | ok: true,
370 | sala,
371 | });
372 | } catch (error) {
373 | console.log(error);
374 | res.status(500).json({
375 | ok: false,
376 | msg: "Por favor hable con el administrador",
377 | });
378 | }
379 | };
380 |
381 | const getMensajesSala = async (req, res) => {
382 | try {
383 | const { salaId } = req.params;
384 | const sala = await Sala.findById(salaId).populate("mensajes");
385 |
386 | res.json({
387 | ok: true,
388 | sala,
389 | });
390 | } catch (error) {
391 | console.log(error);
392 | res.status(500).json({
393 | ok: false,
394 | msg: "Por favor hable con el administrador",
395 | });
396 | }
397 | };
398 |
399 | const updateSala = async (req, res) => {
400 | try {
401 | const { salaId } = req.params;
402 | const { nombre, codigo, color } = req.body;
403 |
404 | const sala = await Sala.findByIdAndUpdate(
405 | salaId,
406 | { nombre, codigo, color },
407 | { new: true }
408 | );
409 |
410 | res.json({
411 | ok: true,
412 | sala,
413 | });
414 | } catch (error) {
415 | console.log(error);
416 | res.status(500).json({
417 | ok: false,
418 | msg: "Por favor hable con el administrador",
419 | });
420 | }
421 | };
422 |
423 | const deleteSala = async (req, res) => {
424 | try {
425 | const { salaId } = req.params;
426 |
427 | // Find the room by its ID
428 | const sala = await Sala.findById(salaId);
429 |
430 | if (!sala) {
431 | return res.status(404).json({
432 | ok: false,
433 | msg: "Sala no encontrada",
434 | });
435 | }
436 |
437 | // Check if the user is the owner of the room
438 | if (sala.propietario.toString() !== req.uid) {
439 | return res.status(401).json({
440 | ok: false,
441 | msg: "No estás autorizado para eliminar esta sala",
442 | });
443 | }
444 |
445 | // Delete the room from the Sala collection
446 | await Sala.findByIdAndDelete(salaId);
447 |
448 | // Delete the room from the list of rooms for all users
449 | await Usuario.updateMany(
450 | { "salas.salaId": salaId },
451 | {
452 | $pull: {
453 | salas: { salaId: salaId },
454 | mensajes: { _id: { $in: sala.mensajes } }, // Remove messages associated with the room
455 | },
456 | }
457 | );
458 |
459 | res.json({
460 | ok: true,
461 | msg: "Sala eliminada exitosamente",
462 | });
463 | } catch (error) {
464 | console.log(error);
465 | res.status(500).json({
466 | ok: false,
467 | msg: "Por favor hable con el administrador",
468 | });
469 | }
470 | };
471 |
472 | const obtenerUsuariosSala = async (req, res) => {
473 | const { salaId } = req.params;
474 |
475 | console.log(salaId);
476 | try {
477 | const sala = await Sala.findById(salaId).populate({
478 | path: "usuarios",
479 | populate: {
480 | path: "ubicaciones",
481 | model: "Ubicacion", // Reemplaza "Ubicacion" con el nombre de tu modelo de ubicaciones
482 | },
483 | });
484 |
485 | console.log(sala);
486 |
487 | if (!sala) {
488 | return res.status(404).json({
489 | ok: false,
490 | msg: "Sala no encontrada",
491 | });
492 | }
493 |
494 |
495 |
496 | res.json({
497 | ok: true,
498 | usuarios: sala.usuarios,
499 | });
500 | } catch (error) {
501 | console.log(error);
502 | res.status(500).json({
503 | ok: false,
504 | msg: "Por favor hable con el administrador",
505 | });
506 | }
507 | };
508 |
509 | const deleteUserById = async (req, res) => {
510 | const { salaId, usuarioId } = req.params;
511 | const uid = req.uid;
512 |
513 | try {
514 | // Buscar la sala por su ID
515 | const sala = await Sala.findById(salaId);
516 |
517 | //eliminar de la sala el usuario
518 |
519 | if (!sala) {
520 | return res.status(404).json({
521 | ok: false,
522 | msg: "Sala no encontrada",
523 | });
524 | }
525 |
526 | // Verificar si el usuario es el propietario de la sala
527 | if (sala.propietario.toString() !== uid) {
528 | return res.status(401).json({
529 | ok: false,
530 | msg: "No estás autorizado para realizar esta acción",
531 | });
532 | }
533 |
534 | // Verificar si el usuario a eliminar existe en la sala
535 | if (!sala.usuarios.includes(usuarioId)) {
536 | return res.status(404).json({
537 | ok: false,
538 | msg: "Usuario no encontrado en la sala",
539 | });
540 | }
541 |
542 | // Eliminar al usuario de la sala
543 | sala.usuarios.pull(usuarioId);
544 | await sala.save();
545 |
546 | //eliminar de la sala el usuario
547 | const usuario = await Usuario.findById(usuarioId);
548 | usuario.salas = usuario.salas.filter((sala) => !sala.salaId.equals(salaId));
549 | await usuario.save();
550 |
551 | res.json({
552 | ok: true,
553 | msg: "Usuario eliminado exitosamente de la sala",
554 | });
555 |
556 | //notificar al miemro eliminado que fue eliminado
557 | const usuarioEliminado = await Usuario.findById(usuarioId);
558 | const usuarioEliminador = await Usuario.findById(uid);
559 | const mensaje = {
560 | titulo: "Eliminado de sala",
561 | cuerpo: `El usuario ${usuarioEliminador.nombre} te ha eliminado de la sala ${sala.nombre}`,
562 | };
563 |
564 | // await enviarNotificacion( usuarioEliminado.tokenApp, mensaje.titulo, mensaje.cuerpo,sala);
565 | //tokens, titulo, desc, data = {}
566 |
567 | res.status(500).json({
568 | ok: false,
569 | msg: "Por favor hable con el administrador",
570 | });
571 |
572 | } catch (error) {
573 | console.log(error);
574 | res.status(500).json({
575 | ok: false,
576 | msg: "Por favor hable con el administradorrr",
577 | });
578 | }
579 | };
580 |
581 |
582 | const abandonarSala = async (req, res) => {
583 | const { salaId } = req.params;
584 | const uid = req.uid;
585 |
586 | try {
587 | // Buscar al usuario por su ID
588 | const usuario = await Usuario.findById(uid);
589 |
590 | // Filtrar las salas del usuario y guardar los cambios
591 | usuario.salas = usuario.salas.filter((sala) => !sala.salaId.equals(salaId));
592 | //eliminar de la sala
593 | const sala = await Sala.findById(salaId);
594 | sala.usuarios.pull(uid);
595 |
596 | await sala.save();
597 |
598 | await usuario.save();
599 |
600 | res.json({
601 | ok: true,
602 | msg: "Usuario abandonó la sala exitosamente",
603 | });
604 | } catch (error) {
605 | console.log(error);
606 | res.status(500).json({
607 | ok: false,
608 | msg: "Por favor hable con el administrador",
609 | });
610 | }
611 | };
612 |
613 | module.exports = {
614 | abandonarSala,
615 | deleteSala,
616 | deleteUserById,
617 | crearSala,
618 | getMensajesBySala,
619 | getMensajesSala,
620 | getSalas,
621 | getSalasByUser,
622 | grabarMensajeSala,
623 | obtenerMensajesSala,
624 | obtenerSalasMensajesUsuario,
625 | obtenerUsuariosSala,
626 | unirseSala,
627 | updateSala,
628 | obtenerSalasConMensajesNoLeidos,
629 | cambiarEstadoSala,
630 | };
631 |
--------------------------------------------------------------------------------
/controllers/reportes.js:
--------------------------------------------------------------------------------
1 | const { Publicacion, Usuario } = require("../models");
2 | const fs = require("fs");
3 | const PDFDocument = require("pdfkit");
4 | const pdfMakePrinter = require("pdfmake/src/printer");
5 | const pdfMakeUni = require("pdfmake-unicode");
6 | const ExcelJS = require("exceljs");
7 | const publicacion = require("../models/publicacion");
8 | process.env.OPENSSL_CONF = '/dev/null';
9 | //Importaciones
10 | const pdf = require("html-pdf");
11 | const pdfTemplate = require("../prueba/public/pdfTemplate");
12 | const path = require("path");
13 |
14 | const obtenerCiudades = async (req, res) => {
15 | let ciudades = [];
16 | try {
17 | let publicaciones = await Publicacion.find();
18 | ciudades = Array.from(
19 | new Set(publicaciones.map((publicacion) => publicacion["ciudad"]))
20 | );
21 |
22 | res.json({
23 | ok: true,
24 | msg: "Ciudades obtenidas correctamente",
25 | data: ciudades,
26 | });
27 | } catch (error) {
28 | console.log(error);
29 | res.status(500).json({
30 | ok: false,
31 | msg: "Por favor hable con el administrador",
32 | });
33 | }
34 | };
35 |
36 | const obtenerBarrios = async (req, res) => {
37 | let barrios = [];
38 | let consulta = {};
39 | try {
40 | const parametrosBusqueda = req.body;
41 | Object.keys(parametrosBusqueda).forEach((key) => {
42 | if (
43 | parametrosBusqueda[key] !== "" &&
44 | parametrosBusqueda[key] !== undefined
45 | ) {
46 | consulta[key] = parametrosBusqueda[key];
47 | }
48 | });
49 | let publicaciones = await Publicacion.find(consulta);
50 | if (
51 | parametrosBusqueda.horaFin != undefined &&
52 | parametrosBusqueda.horaFin.includes(":")
53 | ) {
54 | const FechahoraFin = convertToEcuadorTimeZone(
55 | new Date(parametrosBusqueda.horaFin)
56 | );
57 | const horaFin = FechahoraFin.getHours();
58 | const minutosFin = FechahoraFin.getMinutes();
59 | const documentosHoraFin = publicaciones.filter((publicacion) => {
60 | const hora = publicacion.createdAt.getHours();
61 | const minutos = publicacion.createdAt.getMinutes();
62 |
63 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
64 | });
65 | publicaciones = documentosHoraFin;
66 | }
67 |
68 | if (
69 | parametrosBusqueda.horaInicio != undefined &&
70 | parametrosBusqueda.horaInicio.includes(":")
71 | ) {
72 | const FechahoraInicio = convertToEcuadorTimeZone(
73 | new Date(parametrosBusqueda.horaInicio)
74 | );
75 | const horaInicio = FechahoraInicio.getHours();
76 | const minutosInicio = FechahoraInicio.getMinutes();
77 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
78 | const hora = publicacion.createdAt.getHours();
79 | const minutos = publicacion.createdAt.getMinutes();
80 | return (
81 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
82 | );
83 | });
84 | publicaciones = documentosHoraInicio;
85 | }
86 |
87 | barrios = Array.from(
88 | new Set(publicaciones.map((publicacion) => publicacion["barrio"]))
89 | );
90 | res.json({
91 | ok: true,
92 | msg: "Barrios obtenidos correctamente",
93 | data: barrios,
94 | });
95 | } catch (error) {
96 | console.log(error);
97 | res.status(500).json({
98 | ok: false,
99 | msg: "Por favor hable con el administrador",
100 | });
101 | }
102 | };
103 |
104 | const obtenerDatosCards = async (req, res) => {
105 | let publicacionesRegistradas = 0;
106 | let usuariosRegistros = 0;
107 | let publicacionesDelMes = 0;
108 | let publicacionesDelDia = 0;
109 | try {
110 | let publicaciones = await Publicacion.find();
111 | const usuarios = await Usuario.find();
112 | publicacionesRegistradas = publicaciones.length;
113 | usuariosRegistros = usuarios.length;
114 | const fechaActual = new Date();
115 |
116 | // Calcula el primer día del mes actual
117 | const primerDiaMesActual = new Date(
118 | fechaActual.getFullYear(),
119 | fechaActual.getMonth(),
120 | 1
121 | );
122 |
123 | // Calcula el último día del mes actual
124 | const ultimoDiaMesActual = new Date(
125 | fechaActual.getFullYear(),
126 | fechaActual.getMonth() + 1,
127 | 0
128 | );
129 |
130 | // Consulta las publicaciones que se encuentran dentro del rango del mes actual
131 | publicacionesDelMes = await Publicacion.countDocuments({
132 | createdAt: {
133 | $gte: primerDiaMesActual,
134 | $lte: ultimoDiaMesActual,
135 | },
136 | });
137 |
138 | const fechaInicioDiaActual = new Date();
139 | fechaInicioDiaActual.setHours(0, 0, 0, 0);
140 |
141 | // Obtenemos la fecha de fin del día actual
142 | const fechaFinDiaActual = new Date();
143 | fechaFinDiaActual.setHours(23, 59, 59, 999);
144 |
145 | // Realizamos la consulta a la base de datos para obtener el conteo
146 | publicacionesDelDia = await Publicacion.countDocuments({
147 | createdAt: {
148 | $gte: fechaInicioDiaActual,
149 | $lte: fechaFinDiaActual,
150 | },
151 | });
152 | res.json({
153 | ok: true,
154 | msg: "Barrios obtenidos correctamente",
155 | data: {
156 | publicacionesRegistradas,
157 | usuariosRegistros,
158 | publicacionesDelMes,
159 | publicacionesDelDia,
160 | },
161 | });
162 | } catch (error) {
163 | console.log(error);
164 | res.status(500).json({
165 | ok: false,
166 | msg: "Por favor hable con el administrador",
167 | });
168 | }
169 | };
170 |
171 | const obtenerAnios = async (req, res) => {
172 | let anios = [];
173 | let consulta = {};
174 | try {
175 | const parametrosBusqueda = req.body;
176 | Object.keys(parametrosBusqueda).forEach((key) => {
177 | if (parametrosBusqueda[key] != "") {
178 | consulta[key] = parametrosBusqueda[key];
179 | }
180 | });
181 | let publicaciones = await Publicacion.find(consulta);
182 | if (
183 | parametrosBusqueda.horaFin != undefined &&
184 | parametrosBusqueda.horaFin.includes(":")
185 | ) {
186 | const FechahoraFin = convertToEcuadorTimeZone(
187 | new Date(parametrosBusqueda.horaFin)
188 | );
189 | const horaFin = FechahoraFin.getHours();
190 | const minutosFin = FechahoraFin.getMinutes();
191 | const documentosHoraFin = publicaciones.filter((publicacion) => {
192 | const hora = publicacion.createdAt.getHours();
193 | const minutos = publicacion.createdAt.getMinutes();
194 |
195 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
196 | });
197 | publicaciones = documentosHoraFin;
198 | }
199 |
200 | if (
201 | parametrosBusqueda.horaInicio != undefined &&
202 | parametrosBusqueda.horaInicio.includes(":")
203 | ) {
204 | const FechahoraInicio = convertToEcuadorTimeZone(
205 | new Date(parametrosBusqueda.horaInicio)
206 | );
207 | const horaInicio = FechahoraInicio.getHours();
208 | const minutosInicio = FechahoraInicio.getMinutes();
209 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
210 | const hora = publicacion.createdAt.getHours();
211 | const minutos = publicacion.createdAt.getMinutes();
212 | return (
213 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
214 | );
215 | });
216 | publicaciones = documentosHoraInicio;
217 | }
218 |
219 | anios = Array.from(
220 | new Set(
221 | publicaciones.map((publicacion) =>
222 | new Date(publicacion.createdAt).getFullYear()
223 | )
224 | )
225 | );
226 | res.json({
227 | ok: true,
228 | msg: "Años obtenidos correctamente",
229 | data: anios,
230 | });
231 | } catch (error) {
232 | console.log(error);
233 | res.status(500).json({
234 | ok: false,
235 | msg: "Por favor hable con el administrador",
236 | });
237 | }
238 | };
239 |
240 | const obtenerEmergencias = async (req, res) => {
241 | let emergencias = [];
242 | let consulta = {};
243 | try {
244 | const parametrosBusqueda = req.body;
245 | Object.keys(parametrosBusqueda).forEach((key) => {
246 | if (
247 | parametrosBusqueda[key] !== "" &&
248 | parametrosBusqueda[key] !== undefined
249 | ) {
250 | consulta[key] = parametrosBusqueda[key];
251 | }
252 | });
253 | let publicaciones = await Publicacion.find(consulta);
254 | if (
255 | parametrosBusqueda.horaFin != undefined &&
256 | parametrosBusqueda.horaFin.includes(":")
257 | ) {
258 | const FechahoraFin = convertToEcuadorTimeZone(
259 | new Date(parametrosBusqueda.horaFin)
260 | );
261 | const horaFin = FechahoraFin.getHours();
262 | const minutosFin = FechahoraFin.getMinutes();
263 | const documentosHoraFin = publicaciones.filter((publicacion) => {
264 | const hora = publicacion.createdAt.getHours();
265 | const minutos = publicacion.createdAt.getMinutes();
266 |
267 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
268 | });
269 | publicaciones = documentosHoraFin;
270 | }
271 |
272 | if (
273 | parametrosBusqueda.horaInicio != undefined &&
274 | parametrosBusqueda.horaInicio.includes(":")
275 | ) {
276 | const FechahoraInicio = convertToEcuadorTimeZone(
277 | new Date(parametrosBusqueda.horaInicio)
278 | );
279 | const horaInicio = FechahoraInicio.getHours();
280 | const minutosInicio = FechahoraInicio.getMinutes();
281 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
282 | const hora = publicacion.createdAt.getHours();
283 | const minutos = publicacion.createdAt.getMinutes();
284 | return (
285 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
286 | );
287 | });
288 | publicaciones = documentosHoraInicio;
289 | }
290 |
291 | emergencias = Array.from(
292 | new Set(publicaciones.map((publicacion) => publicacion["titulo"]))
293 | );
294 | res.json({
295 | ok: true,
296 | msg: "Emergencias obtenidas correctamente",
297 | data: emergencias,
298 | });
299 | } catch (error) {
300 | console.log(error);
301 | res.status(500).json({
302 | ok: false,
303 | msg: "Por favor hable con el administrador",
304 | });
305 | }
306 | };
307 | const convertToEcuadorTimeZone = (date) => {
308 | const ecuadorTimeZoneOffset = -5 * 60; // -5 horas en minutos
309 | const userTimeZoneOffset = date.getTimezoneOffset(); // Obtener el offset del huso horario del usuario en minutos
310 | const gmtTime = date.getTime() + userTimeZoneOffset * 60 * 1000; // Convertir la hora a GMT
311 | const ecuadorTime = gmtTime + ecuadorTimeZoneOffset * 60 * 1000; // Agregar el offset de GMT-5
312 | return new Date(ecuadorTime);
313 | };
314 | const obtenerReporteBarras = async (req, res) => {
315 | let emergencias = [];
316 | let consulta = {};
317 | try {
318 | const parametrosBusqueda = req.body;
319 |
320 | Object.keys(parametrosBusqueda).forEach((key) => {
321 | if (
322 | parametrosBusqueda[key] !== "" &&
323 | parametrosBusqueda[key] !== undefined
324 | ) {
325 | consulta[key] = parametrosBusqueda[key];
326 | }
327 | });
328 |
329 | if (parametrosBusqueda.fechaFin) {
330 | const fechaFin = new Date(parametrosBusqueda.fechaFin);
331 | fechaFin.setHours(23, 59, 59); // Establecer la hora de finalización a las 23:59:59
332 | consulta.createdAt = consulta.createdAt || {};
333 | consulta.createdAt.$lte = fechaFin;
334 | }
335 |
336 | if (parametrosBusqueda.fechaInicio) {
337 | const fechaInicio = new Date(parametrosBusqueda.fechaInicio);
338 | consulta.createdAt = consulta.createdAt || {};
339 | consulta.createdAt.$gte = fechaInicio;
340 | }
341 |
342 | let publicaciones = await Publicacion.find(consulta);
343 |
344 | if (
345 | parametrosBusqueda.horaFin != undefined &&
346 | parametrosBusqueda.horaFin.includes(":")
347 | ) {
348 | const FechahoraFin = convertToEcuadorTimeZone(
349 | new Date(parametrosBusqueda.horaFin)
350 | );
351 | const horaFin = FechahoraFin.getHours();
352 | const minutosFin = FechahoraFin.getMinutes();
353 | const documentosHoraFin = publicaciones.filter((publicacion) => {
354 | const hora = publicacion.createdAt.getHours();
355 | const minutos = publicacion.createdAt.getMinutes();
356 |
357 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
358 | });
359 | publicaciones = documentosHoraFin;
360 | }
361 |
362 | if (
363 | parametrosBusqueda.horaInicio != undefined &&
364 | parametrosBusqueda.horaInicio.includes(":")
365 | ) {
366 | const FechahoraInicio = convertToEcuadorTimeZone(
367 | new Date(parametrosBusqueda.horaInicio)
368 | );
369 | const horaInicio = FechahoraInicio.getHours();
370 | const minutosInicio = FechahoraInicio.getMinutes();
371 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
372 | const hora = publicacion.createdAt.getHours();
373 | const minutos = publicacion.createdAt.getMinutes();
374 | return (
375 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
376 | );
377 | });
378 | publicaciones = documentosHoraInicio;
379 | }
380 |
381 | const conteoPorMes = {};
382 | for (
383 | let index = new Date(parametrosBusqueda.fechaInicio).getMonth();
384 | index <= new Date(parametrosBusqueda.fechaFin).getMonth();
385 | index++
386 | ) {
387 | conteoPorMes[index] = 0;
388 | }
389 |
390 | publicaciones.forEach((publicacion) => {
391 | const fecha = new Date(publicacion.createdAt);
392 | const mes = fecha.getMonth() + 1; // Los meses en JavaScript se representan del 0 al 11, por eso sumamos 1.
393 |
394 | if (conteoPorMes[mes]) {
395 | conteoPorMes[mes]++;
396 | } else {
397 | conteoPorMes[mes] = 1;
398 | }
399 | });
400 |
401 | res.json({
402 | ok: true,
403 | msg: "Datos para barras obtenidas correctamente",
404 | data: conteoPorMes,
405 | });
406 | } catch (error) {
407 | console.log(error);
408 | res.status(500).json({
409 | ok: false,
410 | msg: "Por favor hable con el administrador",
411 | });
412 | }
413 | };
414 | const obtenerReportePastel = async (req, res) => {
415 | const conteoEmergencias = {};
416 | let consulta = {};
417 | try {
418 | const parametrosBusqueda = req.body;
419 | Object.keys(parametrosBusqueda).forEach((key) => {
420 | if (
421 | parametrosBusqueda[key] !== "" &&
422 | parametrosBusqueda[key] !== undefined
423 | ) {
424 | consulta[key] = parametrosBusqueda[key];
425 | }
426 | });
427 |
428 | if (parametrosBusqueda.fechaFin) {
429 | const fechaFin = new Date(parametrosBusqueda.fechaFin);
430 | fechaFin.setHours(23, 59, 59); // Establecer la hora de finalización a las 23:59:59
431 | consulta.createdAt = consulta.createdAt || {};
432 | consulta.createdAt.$lte = fechaFin;
433 | }
434 |
435 | if (parametrosBusqueda.fechaInicio) {
436 | const fechaInicio = new Date(parametrosBusqueda.fechaInicio);
437 | consulta.createdAt = consulta.createdAt || {};
438 | consulta.createdAt.$gte = fechaInicio;
439 | }
440 |
441 | let publicaciones = await Publicacion.find(consulta);
442 | if (
443 | parametrosBusqueda.horaFin != undefined &&
444 | parametrosBusqueda.horaFin.includes(":")
445 | ) {
446 | const FechahoraFin = convertToEcuadorTimeZone(
447 | new Date(parametrosBusqueda.horaFin)
448 | );
449 | const horaFin = FechahoraFin.getHours();
450 | const minutosFin = FechahoraFin.getMinutes();
451 | const documentosHoraFin = publicaciones.filter((publicacion) => {
452 | const hora = publicacion.createdAt.getHours();
453 | const minutos = publicacion.createdAt.getMinutes();
454 |
455 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
456 | });
457 | publicaciones = documentosHoraFin;
458 | }
459 |
460 | if (
461 | parametrosBusqueda.horaInicio != undefined &&
462 | parametrosBusqueda.horaInicio.includes(":")
463 | ) {
464 | const FechahoraInicio = convertToEcuadorTimeZone(
465 | new Date(parametrosBusqueda.horaInicio)
466 | );
467 | const horaInicio = FechahoraInicio.getHours();
468 | const minutosInicio = FechahoraInicio.getMinutes();
469 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
470 | const hora = publicacion.createdAt.getHours();
471 | const minutos = publicacion.createdAt.getMinutes();
472 | return (
473 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
474 | );
475 | });
476 | publicaciones = documentosHoraInicio;
477 | }
478 |
479 | emergencias = publicaciones.forEach((publicacion) => {
480 | const { titulo } = publicacion;
481 | if (conteoEmergencias[titulo]) {
482 | conteoEmergencias[titulo]++;
483 | } else {
484 | conteoEmergencias[titulo] = 1;
485 | }
486 | });
487 | res.json({
488 | ok: true,
489 | msg: "Datos de pastel",
490 | data: conteoEmergencias,
491 | });
492 | } catch (error) {
493 | console.log(error);
494 | res.status(500).json({
495 | ok: false,
496 | msg: "Por favor hable con el administrador",
497 | });
498 | }
499 | };
500 | const obtenerMapaCalor = async (req, res) => {
501 | let consulta = {};
502 | try {
503 | const parametrosBusqueda = req.body;
504 | Object.keys(parametrosBusqueda).forEach((key) => {
505 | if (
506 | parametrosBusqueda[key] !== "" &&
507 | parametrosBusqueda[key] !== undefined
508 | ) {
509 | consulta[key] = parametrosBusqueda[key];
510 | }
511 | });
512 |
513 | if (parametrosBusqueda.fechaFin) {
514 | const fechaFin = new Date(parametrosBusqueda.fechaFin);
515 | fechaFin.setHours(23, 59, 59); // Establecer la hora de finalización a las 23:59:59
516 | consulta.createdAt = consulta.createdAt || {};
517 | consulta.createdAt.$lte = fechaFin;
518 | }
519 |
520 | if (parametrosBusqueda.fechaInicio) {
521 | const fechaInicio = new Date(parametrosBusqueda.fechaInicio);
522 | consulta.createdAt = consulta.createdAt || {};
523 | consulta.createdAt.$gte = fechaInicio;
524 | }
525 |
526 | let publicaciones = await Publicacion.find(consulta);
527 | if (
528 | parametrosBusqueda.horaFin != undefined &&
529 | parametrosBusqueda.horaFin.includes(":")
530 | ) {
531 | const FechahoraFin = convertToEcuadorTimeZone(
532 | new Date(parametrosBusqueda.horaFin)
533 | );
534 | const horaFin = FechahoraFin.getHours();
535 | const minutosFin = FechahoraFin.getMinutes();
536 | const documentosHoraFin = publicaciones.filter((publicacion) => {
537 | const hora = publicacion.createdAt.getHours();
538 | const minutos = publicacion.createdAt.getMinutes();
539 |
540 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
541 | });
542 | publicaciones = documentosHoraFin;
543 | }
544 |
545 | if (
546 | parametrosBusqueda.horaInicio != undefined &&
547 | parametrosBusqueda.horaInicio.includes(":")
548 | ) {
549 | const FechahoraInicio = convertToEcuadorTimeZone(
550 | new Date(parametrosBusqueda.horaInicio)
551 | );
552 | const horaInicio = FechahoraInicio.getHours();
553 | const minutosInicio = FechahoraInicio.getMinutes();
554 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
555 | const hora = publicacion.createdAt.getHours();
556 | const minutos = publicacion.createdAt.getMinutes();
557 | return (
558 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
559 | );
560 | });
561 | publicaciones = documentosHoraInicio;
562 | }
563 |
564 | const diasSemana = [
565 | "Domingo",
566 | "Lunes",
567 | "Martes",
568 | "Miércoles",
569 | "Jueves",
570 | "Viernes",
571 | "Sábado",
572 | ];
573 |
574 | const heatmapData = Array.from(
575 | {
576 | length: 7,
577 | },
578 | () => ({
579 | name: "",
580 | data: Array(24).fill(0),
581 | })
582 | );
583 |
584 | diasSemana.map((diaSemana, index) => {
585 | heatmapData[index].name = diasSemana[index];
586 | });
587 |
588 | publicaciones.forEach((publicacion) => {
589 | const fecha = new Date(publicacion.createdAt);
590 | const diaSemana = fecha.getDay();
591 | const hora = fecha.getHours();
592 |
593 | heatmapData[diaSemana].name = diasSemana[diaSemana];
594 | heatmapData[diaSemana].data[hora] += 1;
595 | });
596 |
597 | let maxCount = 0;
598 |
599 | heatmapData.forEach((data, index) => {
600 | const maxInDay = Math.max(...data.data);
601 | if (maxInDay > maxCount) {
602 | maxCount = maxInDay;
603 | }
604 | });
605 | const segmentSize = Math.ceil(maxCount / 3);
606 | const ranges = [
607 | {
608 | from: 1,
609 | to: segmentSize,
610 | name: "Bajo",
611 | color: "#008FFB",
612 | },
613 | {
614 | from: segmentSize + 1,
615 | to: segmentSize * 2,
616 | name: "Medio",
617 | color: "#efa94a",
618 | },
619 | {
620 | from: segmentSize * 2 + 1,
621 | to: maxCount,
622 | name: "Alto",
623 | color: "#FF4560",
624 | },
625 | ];
626 |
627 | res.json({
628 | ok: true,
629 | msg: "Datos de mapa de calor",
630 | data: {
631 | heatmapData,
632 | ranges,
633 | total: publicaciones.length,
634 | },
635 | });
636 | } catch (error) {
637 | console.log(error);
638 | res.status(500).json({
639 | ok: false,
640 | msg: "Por favor hable con el administrador",
641 | });
642 | }
643 | };
644 | const obtenerCoordenadas = async (req, res) => {
645 | let consulta = {};
646 | try {
647 | const parametrosBusqueda = req.body;
648 | Object.keys(parametrosBusqueda).forEach((key) => {
649 | if (
650 | parametrosBusqueda[key] !== "" &&
651 | parametrosBusqueda[key] !== undefined
652 | ) {
653 | consulta[key] = parametrosBusqueda[key];
654 | }
655 | });
656 |
657 | if (parametrosBusqueda.fechaFin) {
658 | const fechaFin = new Date(parametrosBusqueda.fechaFin);
659 | fechaFin.setHours(23, 59, 59); // Establecer la hora de finalización a las 23:59:59
660 | consulta.createdAt = consulta.createdAt || {};
661 | consulta.createdAt.$lte = fechaFin;
662 | }
663 |
664 | if (parametrosBusqueda.fechaInicio) {
665 | const fechaInicio = new Date(parametrosBusqueda.fechaInicio);
666 | consulta.createdAt = consulta.createdAt || {};
667 | consulta.createdAt.$gte = fechaInicio;
668 | }
669 |
670 | let publicaciones = await Publicacion.find(consulta);
671 | if (
672 | parametrosBusqueda.horaFin != undefined &&
673 | parametrosBusqueda.horaFin.includes(":")
674 | ) {
675 | const FechahoraFin = convertToEcuadorTimeZone(
676 | new Date(parametrosBusqueda.horaFin)
677 | );
678 | const horaFin = FechahoraFin.getHours();
679 | const minutosFin = FechahoraFin.getMinutes();
680 | const documentosHoraFin = publicaciones.filter((publicacion) => {
681 | const hora = publicacion.createdAt.getHours();
682 | const minutos = publicacion.createdAt.getMinutes();
683 |
684 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
685 | });
686 | publicaciones = documentosHoraFin;
687 | }
688 |
689 | if (
690 | parametrosBusqueda.horaInicio != undefined &&
691 | parametrosBusqueda.horaInicio.includes(":")
692 | ) {
693 | const FechahoraInicio = convertToEcuadorTimeZone(
694 | new Date(parametrosBusqueda.horaInicio)
695 | );
696 | const horaInicio = FechahoraInicio.getHours();
697 | const minutosInicio = FechahoraInicio.getMinutes();
698 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
699 | const hora = publicacion.createdAt.getHours();
700 | const minutos = publicacion.createdAt.getMinutes();
701 | return (
702 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
703 | );
704 | });
705 | publicaciones = documentosHoraInicio;
706 | }
707 |
708 | const coordenadas = publicaciones.map((publicacion) => {
709 | return {
710 | titulo: publicacion.titulo,
711 | position: [publicacion.latitud, publicacion.longitud],
712 | };
713 | });
714 |
715 | res.json({
716 | ok: true,
717 | msg: "Datos de mapa de calor",
718 | data: coordenadas,
719 | });
720 | } catch (error) {
721 | console.log(error);
722 | res.status(500).json({
723 | ok: false,
724 | msg: "Por favor hable con el administrador",
725 | });
726 | }
727 | };
728 |
729 | const descargarXLSX = async (req, res) => {
730 | let consulta = {};
731 | try {
732 | const parametrosBusqueda = req.body;
733 | Object.keys(parametrosBusqueda).forEach((key) => {
734 | if (
735 | parametrosBusqueda[key] !== "" &&
736 | parametrosBusqueda[key] !== undefined
737 | ) {
738 | consulta[key] = parametrosBusqueda[key];
739 | }
740 | });
741 |
742 | if (parametrosBusqueda.fechaFin) {
743 | const fechaFin = new Date(parametrosBusqueda.fechaFin);
744 | fechaFin.setHours(23, 59, 59); // Establecer la hora de finalización a las 23:59:59
745 | consulta.fechaPublicacion = consulta.fechaPublicacion || {};
746 | consulta.fechaPublicacion.$lte = fechaFin;
747 | }
748 |
749 | if (parametrosBusqueda.fechaInicio) {
750 | const fechaInicio = new Date(parametrosBusqueda.fechaInicio);
751 | consulta.fechaPublicacion = consulta.fechaPublicacion || {};
752 | consulta.fechaPublicacion.$gte = fechaInicio;
753 | }
754 |
755 | // Cambiar la propiedad de createdAt por fechaPublicacion
756 | let publicaciones = await Publicacion.find(consulta, { nombreUsuario: 0 });
757 |
758 | if (
759 | parametrosBusqueda.horaFin != undefined &&
760 | parametrosBusqueda.horaFin.includes(":")
761 | ) {
762 | const FechahoraFin = convertToEcuadorTimeZone(
763 | new Date(parametrosBusqueda.horaFin)
764 | );
765 | const horaFin = FechahoraFin.getHours();
766 | const minutosFin = FechahoraFin.getMinutes();
767 | const documentosHoraFin = publicaciones.filter((publicacion) => {
768 | const hora = publicacion.fechaPublicacion.getHours();
769 | const minutos = publicacion.fechaPublicacion.getMinutes();
770 |
771 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
772 | });
773 | publicaciones = documentosHoraFin;
774 | }
775 |
776 | if (
777 | parametrosBusqueda.horaInicio != undefined &&
778 | parametrosBusqueda.horaInicio.includes(":")
779 | ) {
780 | const FechahoraInicio = convertToEcuadorTimeZone(
781 | new Date(parametrosBusqueda.horaInicio)
782 | );
783 | const horaInicio = FechahoraInicio.getHours();
784 | const minutosInicio = FechahoraInicio.getMinutes();
785 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
786 | const hora = publicacion.fechaPublicacion.getHours();
787 | const minutos = publicacion.fechaPublicacion.getMinutes();
788 | return (
789 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
790 | );
791 | });
792 | publicaciones = documentosHoraInicio;
793 | }
794 |
795 | // ...
796 |
797 | //eliminar de publicaciones nombreUsuario
798 |
799 | //eliminar nombreUsuario de todos las publicaciones
800 |
801 | exportToExcel(publicaciones)
802 | .then((buffer) => {
803 | // Configurar las cabeceras para la descarga del archivo
804 | res.setHeader("Content-Disposition", "attachment; filename=datos.xlsx");
805 | res.setHeader(
806 | "Content-Type",
807 | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
808 | );
809 |
810 | // Enviar el archivo de Excel como respuesta
811 | res.send(buffer);
812 | })
813 | .catch((error) => {
814 | console.error("Error al generar el archivo de Excel:", error);
815 | res.status(500).send("Error al generar el archivo de Excel.");
816 | });
817 | } catch (error) {
818 | console.log(error);
819 | res.status(500).json({
820 | ok: false,
821 | msg: "Por favor hable con el administrador",
822 | });
823 | }
824 | };
825 |
826 | // Resto del código sin cambios
827 |
828 | const descargarCSV = async (req, res) => {
829 | let consulta = {};
830 | try {
831 | const parametrosBusqueda = req.body;
832 | Object.keys(parametrosBusqueda).forEach((key) => {
833 | if (
834 | parametrosBusqueda[key] !== "" &&
835 | parametrosBusqueda[key] !== undefined
836 | ) {
837 | consulta[key] = parametrosBusqueda[key];
838 | }
839 | });
840 |
841 | if (parametrosBusqueda.fechaFin) {
842 | const fechaFin = new Date(parametrosBusqueda.fechaFin);
843 | fechaFin.setHours(23, 59, 59); // Establecer la hora de finalización a las 23:59:59
844 | consulta.createdAt = consulta.createdAt || {};
845 | consulta.createdAt.$lte = fechaFin;
846 | }
847 |
848 | if (parametrosBusqueda.fechaInicio) {
849 | const fechaInicio = new Date(parametrosBusqueda.fechaInicio);
850 | consulta.createdAt = consulta.createdAt || {};
851 | consulta.createdAt.$gte = fechaInicio;
852 | }
853 |
854 |
855 |
856 | let publicaciones = await Publicacion.find(consulta, { nombreUsuario: 0 });
857 | if (
858 | parametrosBusqueda.horaFin != undefined &&
859 | parametrosBusqueda.horaFin.includes(":")
860 | ) {
861 | const FechahoraFin = convertToEcuadorTimeZone(
862 | new Date(parametrosBusqueda.horaFin)
863 | );
864 | const horaFin = FechahoraFin.getHours();
865 | const minutosFin = FechahoraFin.getMinutes();
866 | const documentosHoraFin = publicaciones.filter((publicacion) => {
867 | const hora = publicacion.createdAt.getHours();
868 | const minutos = publicacion.createdAt.getMinutes();
869 |
870 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
871 | });
872 | publicaciones = documentosHoraFin;
873 | }
874 |
875 | if (
876 | parametrosBusqueda.horaInicio != undefined &&
877 | parametrosBusqueda.horaInicio.includes(":")
878 | ) {
879 | const FechahoraInicio = convertToEcuadorTimeZone(
880 | new Date(parametrosBusqueda.horaInicio)
881 | );
882 | const horaInicio = FechahoraInicio.getHours();
883 | const minutosInicio = FechahoraInicio.getMinutes();
884 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
885 | const hora = publicacion.createdAt.getHours();
886 | const minutos = publicacion.createdAt.getMinutes();
887 | return (
888 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
889 | );
890 | });
891 | publicaciones = documentosHoraInicio;
892 | }
893 |
894 | exportToCSV(publicaciones)
895 | .then((buffer) => {
896 | // Configurar las cabeceras para la descarga del archivo
897 | res.setHeader("Content-Disposition", "attachment; filename=datos.xlsx");
898 | res.setHeader(
899 | "Content-Type",
900 | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
901 | );
902 |
903 | // Enviar el archivo de Excel como respuesta
904 | res.send(buffer);
905 | })
906 | .catch((error) => {
907 | console.error("Error al generar el archivo de Excel:", error);
908 | res.status(500).send("Error al generar el archivo de Excel.");
909 | });
910 | } catch (error) {
911 | console.log(error);
912 | res.status(500).json({
913 | ok: false,
914 | msg: "Por favor hable con el administrador",
915 | });
916 | }
917 | };
918 |
919 | process.env.OPENSSL_CONF = '/dev/null';
920 |
921 | const descargarPDF = async (req, res) => {
922 | let consulta = {};
923 | try {
924 | const parametrosBusqueda = req.body;
925 |
926 | Object.keys(parametrosBusqueda).forEach((key) => {
927 | if (
928 | parametrosBusqueda[key] !== "" &&
929 | parametrosBusqueda[key] !== undefined
930 | ) {
931 | consulta[key] = parametrosBusqueda[key];
932 | }
933 | });
934 |
935 | if (parametrosBusqueda.fechaFin) {
936 | const fechaFin = new Date(parametrosBusqueda.fechaFin);
937 | fechaFin.setHours(23, 59, 59); // Establecer la hora de finalización a las 23:59:59
938 | consulta.createdAt = consulta.createdAt || {};
939 | consulta.createdAt.$lte = fechaFin;
940 | }
941 |
942 | if (parametrosBusqueda.fechaInicio) {
943 | const fechaInicio = new Date(parametrosBusqueda.fechaInicio);
944 | consulta.createdAt = consulta.createdAt || {};
945 | consulta.createdAt.$gte = fechaInicio;
946 | }
947 |
948 | let publicaciones = await Publicacion.find(consulta);
949 | if (
950 | parametrosBusqueda.horaFin != undefined &&
951 | parametrosBusqueda.horaFin.includes(":")
952 | ) {
953 | const FechahoraFin = convertToEcuadorTimeZone(
954 | new Date(parametrosBusqueda.horaFin)
955 | );
956 | const horaFin = FechahoraFin.getHours();
957 | const minutosFin = FechahoraFin.getMinutes();
958 | const documentosHoraFin = publicaciones.filter((publicacion) => {
959 | const hora = publicacion.createdAt.getHours();
960 | const minutos = publicacion.createdAt.getMinutes();
961 |
962 | return hora < horaFin || (hora === horaFin && minutos <= minutosFin);
963 | });
964 | publicaciones = documentosHoraFin;
965 | }
966 |
967 | if (
968 | parametrosBusqueda.horaInicio != undefined &&
969 | parametrosBusqueda.horaInicio.includes(":")
970 | ) {
971 | const FechahoraInicio = convertToEcuadorTimeZone(
972 | new Date(parametrosBusqueda.horaInicio)
973 | );
974 | const horaInicio = FechahoraInicio.getHours();
975 | const minutosInicio = FechahoraInicio.getMinutes();
976 | const documentosHoraInicio = publicaciones.filter((publicacion) => {
977 | const hora = publicacion.createdAt.getHours();
978 | const minutos = publicacion.createdAt.getMinutes();
979 | return (
980 | hora > horaInicio || (hora === horaInicio && minutos >= minutosInicio)
981 | );
982 | });
983 | publicaciones = documentosHoraInicio;
984 | }
985 |
986 |
987 |
988 | const data = path.join( __dirname, 'aaaaaaaaaaa.txt');
989 | console.log(data);
990 | fs.writeFile(data, 'Hola mundo', (err) => {
991 | if (err) throw err;
992 |
993 | console.log('The file has been saved!');
994 | });
995 |
996 | //TODO: Generar el PDF
997 | console.log(publicaciones);
998 | const pathPDF = path.join( __dirname, 'datos.pdf');
999 | const pdfOptions = {
1000 | childProcessOptions: {
1001 | env: {
1002 | OPENSSL_CONF: '/dev/null', // Configuración para evitar problemas SSL
1003 | },
1004 | },
1005 | };
1006 |
1007 | //TODO: total usuarios
1008 | const totalUsuarios = await Usuario.countDocuments();
1009 | console.log(totalUsuarios);//46
1010 |
1011 | //TODO: total publicaciones por dia, dia acutal
1012 | const fechaActual = new Date();
1013 |
1014 | const fechaInicio = new Date(fechaActual.getFullYear(), fechaActual.getMonth(), fechaActual.getDate(), 0, 0, 0);
1015 | const fechaFin = new Date(fechaActual.getFullYear(), fechaActual.getMonth(), fechaActual.getDate(), 23, 59, 59);
1016 |
1017 | const totalPublicacionesDia = await Publicacion.countDocuments({
1018 | createdAt: {
1019 | $gte: fechaInicio,
1020 | $lte: fechaFin
1021 | }
1022 | });
1023 | console.log(totalPublicacionesDia);//29
1024 |
1025 | //TODO: total publicaciones por MES, mes actual
1026 | const fechaInicioMes = new Date(fechaActual.getFullYear(), fechaActual.getMonth(), 1, 0, 0, 0);
1027 | const fechaFinMes = new Date(fechaActual.getFullYear(), fechaActual.getMonth() + 1, 0, 23, 59, 59);
1028 |
1029 | const totalPublicacionesMes = await Publicacion.countDocuments({
1030 | createdAt: {
1031 | $gte: fechaInicioMes,
1032 | $lte: fechaFinMes
1033 | }
1034 | });
1035 |
1036 | console.log(publicaciones);//29
1037 |
1038 | //taotal publicaciones registradas en el sistema
1039 | const totalPublicacionesCoutn = await Publicacion.countDocuments();
1040 |
1041 |
1042 | //objeto de persona con nombre y edad
1043 | const dataInfo = {
1044 | totalUsuarios: totalUsuarios,
1045 | totalPublicacionesDia: totalPublicacionesDia,
1046 | totalPublicacionesMes: totalPublicacionesMes,
1047 | publicaciones: publicaciones,
1048 | totalPublicacionesCoutn: totalPublicacionesCoutn
1049 | }
1050 |
1051 |
1052 | // console.log(conteoPorMes);
1053 | const pdfFilePath = path.join(__dirname, 'datos.pdf'); // Ruta donde deseas guardar el PDF
1054 |
1055 | pdf.create(pdfTemplate(dataInfo), pdfOptions).toFile(pdfFilePath, (err) => {
1056 | if (err) {
1057 | console.log('Error creating PDF:', err);
1058 | // Maneja el error de acuerdo a tus necesidades
1059 | // res.send(Promise.reject());
1060 | } else {
1061 | console.log('PDF has been successfully created and saved.');
1062 | // Realiza acciones adicionales si es necesario
1063 | // res.send(Promise.resolve());
1064 | }
1065 | });
1066 |
1067 |
1068 |
1069 |
1070 |
1071 | // Configurar los encabezados de la respuesta para descargar el archivo PDF
1072 | const filename = "archivo.pdf";
1073 | res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
1074 | res.setHeader("Content-Type", "application/pdf");
1075 |
1076 | // Obtener la ruta absoluta de las fuentes Roboto
1077 | const fonts = {
1078 | Roboto: {
1079 | normal: require.resolve(
1080 | "pdfmake-unicode/src/fonts/Arial GEO/Roboto-Regular.ttf"
1081 | ),
1082 | bold: require.resolve(
1083 | "pdfmake-unicode/src/fonts/Arial GEO/Roboto-Medium.ttf"
1084 | ),
1085 | },
1086 | };
1087 |
1088 | // Crear un objeto de definición de PDF utilizando pdfmake
1089 | const printer = new pdfMakePrinter(fonts);
1090 | const docDefinition = {
1091 | content: [
1092 | { text: "Lista de Publicaciones", style: "header" },
1093 | {
1094 | table: {
1095 | headerRows: 1,
1096 | widths: ["auto", "auto", "auto", "auto", "auto", "auto", "auto"],
1097 | body: [
1098 | [
1099 | { text: "Título", style: "header2" },
1100 | { text: "Contenido", style: "header2" },
1101 | { text: "Ciudad", style: "header2" },
1102 | { text: "Barrio", style: "header2" },
1103 | { text: "Nombre de Usuario", style: "header2" },
1104 | { text: "Latitud", style: "header2" },
1105 | { text: "Longitud", style: "header2" },
1106 | ],
1107 | ...publicaciones.map((publicacion) => [
1108 | publicacion.titulo,
1109 | publicacion.contenido,
1110 | publicacion.ciudad,
1111 | publicacion.barrio,
1112 | publicacion.nombreUsuario,
1113 | publicacion.latitud.toString(),
1114 | publicacion.longitud.toString(),
1115 | ]),
1116 | ],
1117 | },
1118 | },
1119 | ],
1120 | styles: {
1121 | header: {
1122 | fontSize: 18,
1123 | bold: true,
1124 | alignment: "center",
1125 | },
1126 | header2: {
1127 | fontSize: 12,
1128 | bold: true,
1129 | alignment: "center",
1130 | },
1131 | },
1132 | };
1133 |
1134 |
1135 |
1136 |
1137 |
1138 | // Crear el documento PDF utilizando pdfmake
1139 | const pdfDoc = printer.createPdfKitDocument(docDefinition);
1140 | pdfDoc.pipe(res);
1141 | pdfDoc.end();
1142 | } catch (error) {
1143 | console.log(error);
1144 | res.status(500).json({
1145 | ok: false,
1146 | msg: "Por favor hable con el administrador",
1147 | });
1148 | }
1149 | };
1150 | // Función para exportar un array de objetos a Excel
1151 | async function exportToExcel(dataArray) {
1152 | const workbook = new ExcelJS.Workbook();
1153 | const worksheet = workbook.addWorksheet("Datos");
1154 |
1155 | // Definir los encabezados de las columnas en la hoja de cálculo
1156 | console.log(dataArray);
1157 | let objeto = dataArray[0]._doc;
1158 | delete objeto._id;
1159 | delete objeto.color;
1160 | delete objeto.isPublic;
1161 | delete objeto.usuario;
1162 | delete objeto.likes;
1163 | delete objeto.imagenes;
1164 | delete objeto.comentarios;
1165 | delete objeto.__v;
1166 | delete objeto.isActivo;
1167 | delete objeto.isLiked;
1168 | delete objeto.imgAlerta;
1169 | delete objeto.isPublicacionPendiente;
1170 | delete objeto.updatedAt;
1171 | delete objeto.fechaPublicacion;
1172 |
1173 | // Cambiar encabezado de createdAt por FechaCreacion
1174 | objeto.FechaCreacion = objeto.createdAt;
1175 | delete objeto.createdAt;
1176 |
1177 | // Cambiar los encabezados de las columnas a español y mayúsculas
1178 | const headerTranslations = {
1179 | titulo: "Tipo emergencia comunitaria",
1180 | contenido: "Descripción de la emergencia",
1181 | color: "Color",
1182 | ciudad: "Ciudad",
1183 | barrio: "Barrio",
1184 | isPublic: "Es Público",
1185 | usuario: "Usuario",
1186 | nombreUsuario: "Nombre de Usuario",
1187 | likes: "Likes",
1188 | imagenes: "Imágenes",
1189 | latitud: "Latitud",
1190 | longitud: "Longitud",
1191 | comentarios: "Comentarios",
1192 | imgAlerta: "Imagen de Alerta",
1193 | isLiked: "Es Favorito",
1194 | isActivo: "Es Activo",
1195 | FechaCreacion: "Fecha de publicación",
1196 | isPublicacionPendiente: "Publicación Pendiente",
1197 | };
1198 |
1199 | const columnHeaders = Object.keys(objeto).map(header => {
1200 | if (headerTranslations.hasOwnProperty(header)) {
1201 | return headerTranslations[header];
1202 | } else {
1203 | return header.charAt(0).toUpperCase() + header.slice(1);
1204 | }
1205 | });
1206 |
1207 | console.log(columnHeaders);
1208 | worksheet.addRow(columnHeaders);
1209 |
1210 | // Llenar la hoja de cálculo con los datos de los objetos
1211 | dataArray.forEach((dataObj) => {
1212 | let objeto = Object.values(dataObj)[2];
1213 | delete objeto._id;
1214 | delete objeto.color;
1215 | delete objeto.isPublic;
1216 | delete objeto.usuario;
1217 | delete objeto.likes;
1218 | delete objeto.imagenes;
1219 | delete objeto.comentarios;
1220 | delete objeto.__v;
1221 | delete objeto.isActivo;
1222 | delete objeto.isLiked;
1223 | delete objeto.imgAlerta;
1224 | delete objeto.isPublicacionPendiente;
1225 | delete objeto.fechaPublicacion;
1226 | delete objeto.updatedAt;
1227 |
1228 | worksheet.addRow(Object.values(objeto));
1229 | });
1230 |
1231 | worksheet.columns.forEach((column, index) => {
1232 | let maxLength = 0;
1233 | worksheet.eachRow((row, rowNumber) => {
1234 | if (rowNumber > 1) {
1235 | const cellValue = row.getCell(index + 1).value;
1236 | if (cellValue && cellValue.toString().length > maxLength) {
1237 | maxLength = cellValue.toString().length;
1238 | }
1239 | }
1240 | });
1241 | // Limitar el ancho de las celdas al máximo permitido (16384)
1242 | column.width = Math.min(maxLength < 12 ? 12 : maxLength, 16384);
1243 | });
1244 |
1245 | // Devolver el archivo de Excel como un buffer
1246 | const buffer = await workbook.xlsx.writeBuffer();
1247 | return buffer;
1248 | }
1249 |
1250 |
1251 | // Función para exportar un array de objetos a Excel
1252 | async function exportToCSV(dataArray) {
1253 | const workbook = new ExcelJS.Workbook();
1254 | const worksheet = workbook.addWorksheet('Datos');
1255 |
1256 | // Definir los encabezados de las columnas en la hoja de cálculo
1257 | let objeto = dataArray[0]._doc;
1258 |
1259 | // Agrega aquí los campos que deseas eliminar
1260 | const camposEliminar = ['_id', 'color', 'isPublic', 'usuario', 'likes', 'imagenes', 'comentarios', '__v', 'isActivo', 'isLiked', 'imgAlerta', 'isPublicacionPendiente', 'fechaPublicacion', 'updatedAt'];
1261 |
1262 | camposEliminar.forEach(campos => {
1263 | delete objeto[campos];
1264 | });
1265 |
1266 | // Cambiar encabezado de createdAt por FechaCreacion
1267 | objeto.FechaCreacion = objeto.createdAt;
1268 | delete objeto.createdAt;
1269 |
1270 | // Cambiar los encabezados de las columnas a español y mayúsculas
1271 | const headerTranslations = {
1272 | titulo: "Tipo emergencia comunitaria",
1273 | contenido: "Descripción de la emergencia",
1274 | color: "Color",
1275 | ciudad: "Ciudad",
1276 | barrio: "Barrio",
1277 | isPublic: "Es Público",
1278 | usuario: "Usuario",
1279 | nombreUsuario: "Nombre de Usuario",
1280 | likes: "Likes",
1281 | imagenes: "Imágenes",
1282 | latitud: "Latitud",
1283 | longitud: "Longitud",
1284 | comentarios: "Comentarios",
1285 | imgAlerta: "Imagen de Alerta",
1286 | isLiked: "Es Favorito",
1287 | isActivo: "Es Activo",
1288 | FechaCreacion: "Fecha de publicación",
1289 | isPublicacionPendiente: "Publicación Pendiente",
1290 | };
1291 |
1292 | const columnHeaders = Object.keys(objeto).map(header => {
1293 | if (headerTranslations.hasOwnProperty(header)) {
1294 | return headerTranslations[header];
1295 | } else {
1296 | return header.charAt(0).toUpperCase() + header.slice(1);
1297 | }
1298 | });
1299 |
1300 | worksheet.addRow(columnHeaders);
1301 |
1302 | // Llenar la hoja de cálculo con los datos de los objetos
1303 | dataArray.forEach((dataObj) => {
1304 | let objeto = Object.values(dataObj)[2];
1305 |
1306 | camposEliminar.forEach(campos => {
1307 | delete objeto[campos];
1308 | });
1309 |
1310 | worksheet.addRow(Object.values(objeto));
1311 | });
1312 |
1313 | worksheet.columns.forEach((column, index) => {
1314 | let maxLength = 0;
1315 | worksheet.eachRow((row, rowNumber) => {
1316 | if (rowNumber > 1) {
1317 | const cellValue = row.getCell(index + 1).value;
1318 | if (cellValue && cellValue.toString().length > maxLength) {
1319 | maxLength = cellValue.toString().length;
1320 | }
1321 | }
1322 | });
1323 | // Limitar el ancho de las celdas al máximo permitido (16384)
1324 | column.width = Math.min(maxLength < 12 ? 12 : maxLength, 16384);
1325 | });
1326 |
1327 | // Devolver el archivo de Excel como un buffer
1328 | const buffer = await workbook.xlsx.writeBuffer();
1329 | return buffer;
1330 | }
1331 |
1332 |
1333 | module.exports = {
1334 | obtenerCiudades,
1335 | obtenerBarrios,
1336 | obtenerEmergencias,
1337 | obtenerAnios,
1338 | obtenerReporteBarras,
1339 | obtenerReportePastel,
1340 | obtenerMapaCalor,
1341 | obtenerDatosCards,
1342 | obtenerCoordenadas,
1343 | descargarXLSX,
1344 | descargarPDF,
1345 | descargarCSV,
1346 | };
1347 |
--------------------------------------------------------------------------------