Add Database connection
This commit is contained in:
parent
9f14ae59ff
commit
bbb5b5ae36
14
.env.exemple
14
.env.exemple
@ -7,13 +7,12 @@ OVH_SMS_SERVICE_NAME=
|
|||||||
# Configuration SMS Factor
|
# Configuration SMS Factor
|
||||||
SMS_FACTOR_TOKEN=
|
SMS_FACTOR_TOKEN=
|
||||||
|
|
||||||
#Configuration Mailchimp
|
# Configuration Mailchimp
|
||||||
MAILCHIMP_API_KEY=
|
MAILCHIMP_API_KEY=
|
||||||
MAILCHIMP_KEY=
|
MAILCHIMP_KEY=
|
||||||
MAILCHIMP_LIST_ID=
|
MAILCHIMP_LIST_ID=
|
||||||
|
|
||||||
|
# Configuration Stripe
|
||||||
#Configuration Stripe
|
|
||||||
STRIPE_SECRET_KEY=
|
STRIPE_SECRET_KEY=
|
||||||
STRIPE_WEBHOOK_SECRET=
|
STRIPE_WEBHOOK_SECRET=
|
||||||
STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID=
|
STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID=
|
||||||
@ -21,10 +20,17 @@ STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
|||||||
STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID=
|
STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID=
|
||||||
STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID=
|
||||||
|
|
||||||
#Cartes de test Stripe
|
# Cartes de test Stripe
|
||||||
SUCCES= 4242 4242 4242 4242 #Paiement réussi
|
SUCCES= 4242 4242 4242 4242 #Paiement réussi
|
||||||
DECLINED= 4000 0025 0000 3155 #Paiement refusé
|
DECLINED= 4000 0025 0000 3155 #Paiement refusé
|
||||||
|
|
||||||
# Configuration serveur
|
# Configuration serveur
|
||||||
APP_HOST=
|
APP_HOST=
|
||||||
PORT=
|
PORT=
|
||||||
|
|
||||||
|
# Configuration PostgreSQL
|
||||||
|
DB_HOST=
|
||||||
|
DB_PORT=
|
||||||
|
DB_NAME=
|
||||||
|
DB_USER=
|
||||||
|
DB_PASSWORD=
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"node-fetch": "^2.6.7",
|
"node-fetch": "^2.6.7",
|
||||||
"ovh": "^2.0.3",
|
"ovh": "^2.0.3",
|
||||||
|
"pg": "^8.11.3",
|
||||||
"stripe": "^18.3.0",
|
"stripe": "^18.3.0",
|
||||||
"uuid": "^11.1.0"
|
"uuid": "^11.1.0"
|
||||||
},
|
},
|
||||||
|
105
src/database.js
Normal file
105
src/database.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
const { Pool } = require('pg');
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration de la base de données PostgreSQL
|
||||||
|
*/
|
||||||
|
const dbConfig = {
|
||||||
|
user: process.env.DB_USER || 'postgres',
|
||||||
|
host: process.env.DB_HOST || 'localhost',
|
||||||
|
database: process.env.DB_NAME || 'prd',
|
||||||
|
password: process.env.DB_PASSWORD || 'admin',
|
||||||
|
port: process.env.DB_PORT || 5432,
|
||||||
|
|
||||||
|
// Configuration du pool de connexions
|
||||||
|
max: parseInt(process.env.DB_POOL_MAX) || 20, // Nombre maximum de connexions dans le pool
|
||||||
|
min: parseInt(process.env.DB_POOL_MIN) || 2, // Nombre minimum de connexions maintenues
|
||||||
|
idleTimeoutMillis: parseInt(process.env.DB_IDLE_TIMEOUT) || 30000, // Temps d'inactivité avant fermeture
|
||||||
|
connectionTimeoutMillis: parseInt(process.env.DB_CONNECTION_TIMEOUT) || 2000, // Timeout pour établir une connexion
|
||||||
|
acquireTimeoutMillis: parseInt(process.env.DB_ACQUIRE_TIMEOUT) || 60000, // Timeout pour acquérir une connexion
|
||||||
|
|
||||||
|
// Configuration SSL si nécessaire
|
||||||
|
ssl: process.env.DB_SSL === 'true' ? {
|
||||||
|
rejectUnauthorized: process.env.DB_SSL_REJECT_UNAUTHORIZED !== 'false'
|
||||||
|
} : false
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pool de connexions PostgreSQL
|
||||||
|
*/
|
||||||
|
const pool = new Pool(dbConfig);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gestionnaire d'erreur pour le pool
|
||||||
|
*/
|
||||||
|
pool.on('error', (err) => {
|
||||||
|
console.error('PostgreSQL Error:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe pour gérer les opérations de base de données
|
||||||
|
*/
|
||||||
|
class Database {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exécute une requête SQL avec des paramètres
|
||||||
|
* @param {string} text - La requête SQL
|
||||||
|
* @param {Array} params - Les paramètres de la requête
|
||||||
|
* @returns {Promise<Object>} - Le résultat de la requête
|
||||||
|
*/
|
||||||
|
static async query(text, params) {
|
||||||
|
try {
|
||||||
|
return await pool.query(text, params);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error executing query:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Teste la connexion à la base de données
|
||||||
|
* @returns {Promise<boolean>} - True si la connexion est réussie
|
||||||
|
*/
|
||||||
|
static async testConnection() {
|
||||||
|
try {
|
||||||
|
const result = await this.query('SELECT NOW() as current_time');
|
||||||
|
console.log('Database connection successful:', result.rows[0].current_time);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Database connection failed:', error.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ferme toutes les connexions du pool
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
static async close() {
|
||||||
|
try {
|
||||||
|
await pool.end();
|
||||||
|
console.log('PostgreSQL connection pool closed');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error closing connection pool:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gestion propre de l'arrêt de l'application
|
||||||
|
*/
|
||||||
|
process.on('SIGINT', async () => {
|
||||||
|
console.log('SIGINT signal received, closing connections...');
|
||||||
|
await Database.close();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGTERM', async () => {
|
||||||
|
console.log('SIGTERM signal received, closing connections...');
|
||||||
|
await Database.close();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Database
|
||||||
|
};
|
120
src/server.js
120
src/server.js
@ -5,6 +5,7 @@ const { v4: uuidv4 } = require('uuid');
|
|||||||
const ovh = require('ovh');
|
const ovh = require('ovh');
|
||||||
const mailchimp = require('@mailchimp/mailchimp_transactional');
|
const mailchimp = require('@mailchimp/mailchimp_transactional');
|
||||||
const Stripe = require('stripe');
|
const Stripe = require('stripe');
|
||||||
|
const { Database } = require('./database');
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
// Initialisation de l'application Express
|
// Initialisation de l'application Express
|
||||||
@ -121,6 +122,82 @@ app.get('/api/v1/health', (req, res) => {
|
|||||||
res.json({ message: 'OK' });
|
res.json({ message: 'OK' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/api/v1/db/:tableName', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { tableName } = req.params;
|
||||||
|
const page = parseInt(req.query.page) || 1;
|
||||||
|
const limit = parseInt(req.query.limit) || 10;
|
||||||
|
const offset = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Validation du nom de table pour éviter les injections SQL
|
||||||
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: 'Nom de table invalide'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compter le total d'enregistrements
|
||||||
|
const countResult = await Database.query(`SELECT COUNT(*) as total FROM ${tableName}`);
|
||||||
|
const total = parseInt(countResult.rows[0].total);
|
||||||
|
|
||||||
|
if (tableName === 'rules_groups') {
|
||||||
|
const rulesGroups = await Promise.all((await Database.query(`SELECT * FROM ${tableName} ORDER BY 1 LIMIT $1 OFFSET $2`, [limit, offset])).rows.map(async (ruleGroup) => {
|
||||||
|
const result = await Database.query(`SELECT a.* FROM rules AS a JOIN "_RulesGroupsHasRules" as b ON a.uid = b."A" AND b."B" = '${ruleGroup.uid}';`);
|
||||||
|
return {
|
||||||
|
uid: ruleGroup.uid,
|
||||||
|
name: ruleGroup.name,
|
||||||
|
rules: result.rows.map((rule) => {
|
||||||
|
return {
|
||||||
|
uid: rule.uid
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
created_at: ruleGroup.created_at,
|
||||||
|
updated_at: ruleGroup.updated_at
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: rulesGroups,
|
||||||
|
pagination: {
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
total,
|
||||||
|
totalPages: Math.ceil(total / limit),
|
||||||
|
hasNextPage: page < Math.ceil(total / limit),
|
||||||
|
hasPrevPage: page > 1
|
||||||
|
},
|
||||||
|
table: tableName,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const result = await Database.query(`SELECT * FROM ${tableName} ORDER BY 1 LIMIT $1 OFFSET $2`, [limit, offset]);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: result.rows,
|
||||||
|
pagination: {
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
total,
|
||||||
|
totalPages: Math.ceil(total / limit),
|
||||||
|
hasNextPage: page < Math.ceil(total / limit),
|
||||||
|
hasPrevPage: page > 1
|
||||||
|
},
|
||||||
|
table: tableName,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: 'Erreur lors de l\'exécution de la requête',
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.post('/api/v1/idnot/user/:code', async (req, res) => {
|
app.post('/api/v1/idnot/user/:code', async (req, res) => {
|
||||||
const code = req.params.code;
|
const code = req.params.code;
|
||||||
|
|
||||||
@ -383,7 +460,7 @@ app.post('/api/send-code', validatePhoneNumber, async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erreur:', error);
|
console.error('Error:', error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'Erreur serveur lors de l\'envoi du code'
|
message: 'Erreur serveur lors de l\'envoi du code'
|
||||||
@ -853,7 +930,7 @@ app.post('/api/subscriptions/checkout', validateSubscription, async (req, res) =
|
|||||||
const session = await stripeService.createCheckoutSession(req.body, req.body.frequency);
|
const session = await stripeService.createCheckoutSession(req.body, req.body.frequency);
|
||||||
res.json({ success: true, sessionId: session.id });
|
res.json({ success: true, sessionId: session.id });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erreur création checkout:', error);
|
console.error('Error creating checkout:', error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'Erreur lors de la création de la session de paiement'
|
message: 'Erreur lors de la création de la session de paiement'
|
||||||
@ -903,7 +980,7 @@ app.post('/api/webhooks/stripe', express.raw({ type: 'application/json' }), asyn
|
|||||||
if (session.status === 'complete') {
|
if (session.status === 'complete') {
|
||||||
const subscription = JSON.parse(session.metadata.subscription);
|
const subscription = JSON.parse(session.metadata.subscription);
|
||||||
// Stock subscription (create process)
|
// Stock subscription (create process)
|
||||||
console.log('Nouvel abonnement:', subscription);
|
console.log('New subscription:', subscription);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -912,29 +989,52 @@ app.post('/api/webhooks/stripe', express.raw({ type: 'application/json' }), asyn
|
|||||||
if (['subscription_update', 'subscription_cycle'].includes(invoice.billing_reason)) {
|
if (['subscription_update', 'subscription_cycle'].includes(invoice.billing_reason)) {
|
||||||
const subscription = await stripeService.getSubscription(invoice.subscription);
|
const subscription = await stripeService.getSubscription(invoice.subscription);
|
||||||
// Update subscription (update process)
|
// Update subscription (update process)
|
||||||
console.log('Mise à jour abonnement:', subscription);
|
console.log('Subscription update:', subscription);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'customer.subscription.deleted':
|
case 'customer.subscription.deleted':
|
||||||
const deletedSubscription = event.data.object;
|
const deletedSubscription = event.data.object;
|
||||||
// Delete subscription (update process to delete)
|
// Delete subscription (update process to delete)
|
||||||
console.log('Suppression abonnement:', deletedSubscription.id);
|
console.log('Subscription deleted:', deletedSubscription.id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({ received: true });
|
res.json({ received: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erreur webhook:', error);
|
console.error('Webhook error:', error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'Erreur lors du traitement du webhook'
|
message: 'Error processing webhook'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//------------------------------------ End of Stripe Section -----------------------------------
|
//------------------------------------ End of Stripe Section -----------------------------------
|
||||||
|
|
||||||
app.listen(PORT, () => {
|
// Initialisation et démarrage du serveur
|
||||||
console.log(`Server is running on port ${PORT}`);
|
async function startServer() {
|
||||||
});
|
try {
|
||||||
|
// Test de la connexion à la base de données au démarrage
|
||||||
|
console.log('Initializing database connection...');
|
||||||
|
const isDbConnected = await Database.testConnection();
|
||||||
|
|
||||||
|
if (!isDbConnected) {
|
||||||
|
console.warn('Warning: Database connection failed, but the server will start anyway');
|
||||||
|
} else {
|
||||||
|
console.log('Database connection established successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Démarrage du serveur
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`Server started on port ${PORT}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error starting the server:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Démarrage de l'application
|
||||||
|
startServer();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user