Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
David-TP committed Oct 14, 2024
2 parents 619206b + be10130 commit bd707fc
Show file tree
Hide file tree
Showing 21 changed files with 1,222 additions and 27 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
permissions:
contents: read
checks: write
pull-requests: write
pull-requests: write

jobs:
build-and-test:
Expand All @@ -20,6 +20,7 @@ jobs:
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
JWT_EXPIRATION: "6h"
DB_PORT: 5432
NODE_ENV: development
Expand Down
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\server.js"
}
]
}
54 changes: 53 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,21 @@
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const swaggerFile = require('./swagger-output.json');
const bodyParser = require('body-parser');
const cors = require('cors');

if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}


const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);


const app = express();

app.use(bodyParser.json());

app.use(cors());
// Routes
const categoriesRoutes = require('./src/categories/categoriesRoutes');
Expand All @@ -22,6 +29,8 @@ const likesRoutes = require('./src/likes/likesRoutes');
const cartStatusRoutes = require('./src/cartStatus/cartStatusRoutes');
const shoppingCart = require('./src/shoppingCart/shoppingCartRoutes');
const notifications = require('./src/notifications/notificationsRoutes')
const spacesRoutes = require('./src/spaces/spacesRoutes');
const reservationsRoutes = require('./src/reservations/reservationsRoutes');
// TODO: Use verifyRole middleware
const { verifyToken } = require('./src/auth/authMiddleware');

Expand All @@ -38,9 +47,46 @@ app.get('/', (req, res) => {
);
});

app.use('/auth', authRoutes);
app.post('/create-payment-intent', async (req, res) => {
const { amount, currency, customer } = req.body; // Aquí puedes recibir la cantidad y la moneda desde el frontend

try {
// Crear un PaymentIntent con el monto y la moneda
const paymentIntent = await stripe.paymentIntents.create({
amount: amount, // El monto debe estar en la unidad más pequeña de la moneda (ej. centavos)
currency: currency,
customer: customer,
payment_method_types: ['card'], // Métodos de pago aceptados
});

// Enviar el client secret al frontend para completar el pago
res.send({
clientSecret: paymentIntent.client_secret,
});
} catch (error) {
res.status(500).send({ error: error.message });
}
});


app.post('/webhook', bodyParser.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['stripe-signature'];

try {
const event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);

if (event.type === 'payment_intent.succeeded') {
const paymentIntent = event.data.object;
console.log('Pago exitoso', paymentIntent.id);
}

res.json({ received: true });
} catch (err) {
res.status(400).send(`Webhook Error: ${err.message}`);
}
});

app.use('/auth', authRoutes);
app.use('/categories', verifyToken, categoriesRoutes);
app.use('/products', verifyToken, productsRoutes);
app.use('/paymentMethods', verifyToken, paymentMethodsRoutes);
Expand All @@ -50,5 +96,11 @@ app.use('/likes', verifyToken, likesRoutes);
app.use('/cartStatus', verifyToken, cartStatusRoutes);
app.use('/shoppingCart', verifyToken, shoppingCart);
app.use('/notifications', verifyToken, notifications);
app.use('/spaces', verifyToken, spacesRoutes);
app.use('/reservations', verifyToken, reservationsRoutes);





module.exports = app;
25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
"express": "^4.21.0",
"jsonwebtoken": "^9.0.2",
"morgan": "^1.10.0",
"node-cron": "^3.0.3",
"nodemailer": "^6.9.15",
"pg": "^8.13.0",
"pg-hstore": "^2.3.4",
"sequelize": "^6.37.3",
"stripe": "^17.2.0",
"swagger-autogen": "^2.23.7",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1"
Expand Down
2 changes: 1 addition & 1 deletion src/auth/authController.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const loginUser = async (req, res) => {
{ expiresIn: process.env.JWT_EXPIRATION }
);

res.json({ token: token, userID: user.id });
res.json({ token: token, userID: user.id, stripeid: 'cus_R0u5BxAeykbbZm' });
} catch (error) {
res.status(500).json({ message: 'Error logging in', error: error.message });
}
Expand Down
13 changes: 12 additions & 1 deletion src/data/models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const ShoppingCart = require('../../shoppingCart/shoppingCart');
const CartDetails = require('../../cartDetails/cartDetail');
const OrderDetails = require('./orderDetails');
const Notifications = require('../../notifications/notifications');
const Reservations = require('../../reservations/reservations');
const Spaces = require('../../spaces/spaces');

require('../middlewares/updateMiddleware')(sequelize);

Expand Down Expand Up @@ -63,6 +65,13 @@ OrderDetails.belongsTo(Orders, { foreignKey: 'OrderID' });
Users.hasMany(Notifications, { foreignKey: 'UserID' });
Notifications.belongsTo(Users, { foreignKey: 'UserID' });

// Relación entre Usuarios y Reservas
Users.hasMany(Reservations, { foreignKey: 'UserID' });
Reservations.belongsTo(Users, { foreignKey: 'UserID' });

// Relación entre Espacios y Reservas
Spaces.hasMany(Reservations, { foreignKey: 'SpaceID' });
Reservations.belongsTo(Spaces, { foreignKey: 'SpaceID' });

module.exports = {
sequelize,
Expand All @@ -79,5 +88,7 @@ module.exports = {
ShoppingCart,
CartDetails,
OrderDetails,
Notifications
Notifications,
Reservations,
Spaces,
};
107 changes: 106 additions & 1 deletion src/data/seeder.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// src/data/seeder.js
const { Users, Roles, UserRoles, Products, Categories, OrderStatus, PaymentMethods, UserLikedProducts, ShoppingCart, CartDetails, Orders, OrderDetails, CartStatus } = require('../../src/data/models/index');
const { Users, Roles, UserRoles, Products, Categories, OrderStatus, PaymentMethods, UserLikedProducts, ShoppingCart, CartDetails, Orders, OrderDetails, CartStatus, Spaces } = require('../../src/data/models/index');

async function seedDatabase() {
try {
Expand Down Expand Up @@ -596,6 +596,111 @@ async function seedDatabase() {
{ OrderID: 4, ProductID: 8, Count: 4, UnitPrice: 6.00 }, // Cuatro marcadores en la orden 4
]);

await Spaces.bulkCreate([
{
Name: 'Mesa de PingPong 1',
Description: 'Mesa de ping pong cerca de la cafetería',
Capacity: 2,
Type: 'PingPong',
Location: 'Edificio A, Planta Baja',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},
{
Name: 'Mesa de PingPong 2',
Description: 'Mesa de ping pong cerca de la cancha deportiva',
Capacity: 2,
Type: 'PingPong',
Location: 'Edificio Deportivo',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},
{
Name: 'Mesa de PingPong 3',
Description: 'Mesa de ping pong cerca de la cancha deportiva',
Capacity: 2,
Type: 'PingPong',
Location: 'Edificio Deportivo',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},
{
Name: 'Mesa de PingPong 4',
Description: 'Mesa de ping pong cerca de la cancha deportiva',
Capacity: 2,
Type: 'PingPong',
Location: 'Edificio Deportivo',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},
{
Name: 'Cubículo de Estudio 1',
Description: 'Cubículo con capacidad para 4 personas, incluye proyector.',
Capacity: 4,
Type: 'Cubiculo',
Location: 'Biblioteca, Piso 1',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},
{
Name: 'Cubículo de Estudio 2',
Description: 'Cubículo con capacidad para 6 personas.',
Capacity: 6,
Type: 'Cubiculo',
Location: 'Biblioteca, Piso 1',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},
{
Name: 'Cubículo de Estudio 3',
Description: 'Cubículo con capacidad para 6 personas.',
Capacity: 6,
Type: 'Cubiculo',
Location: 'Biblioteca, Piso 1',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},
{
Name: 'Cubículo de Estudio 4',
Description: 'Cubículo con capacidad para 6 personas.',
Capacity: 6,
Type: 'Cubiculo',
Location: 'Biblioteca, Piso 2',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},
{
Name: 'Parcela de Emprendimiento 1',
Description: 'Espacio designado para mostrar y promocionar productos de emprendimiento estudiantil.',
Capacity: 10,
Type: 'Parcela',
Location: 'Plaza Central',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},
{
Name: 'Parcela de Emprendimiento 2',
Description: 'Espacio en la entrada principal para emprendimientos estudiantiles',
Capacity: 15,
Type: 'Parcela',
Location: 'Entrada Principal',
Available: true,
CreatedBy: 'System',
UpdatedBy: 'System'
},


]);

console.log('Seeding completed successfully');
} catch (error) {
console.error('Error during seeding:', error);
Expand Down
24 changes: 24 additions & 0 deletions src/reservations/activeSpacesCron.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const cron = require('node-cron');
const { Spaces, Reservations } = require('../data/models');
const { Op } = require('sequelize');

cron.schedule('*/2 * * * *', async () => { // Se ejecuta cada 5 minutos
const now = new Date();

// Buscar las reservas que hayan terminado pero que no se hayan marcado como canceladas
const finishedReservations = await Reservations.findAll({
where: {
EndTime: { [Op.lt]: now },
DeletedAt: null,
},
});

for (const reservation of finishedReservations) {
// Cambiar el estado del espacio a disponible
const space = await Spaces.findByPk(reservation.SpaceID);
space.Available = true;
await space.save();
}

console.log('Checked reservations and updated space availability.');
});
Loading

0 comments on commit bd707fc

Please sign in to comment.