- Add newsletter database table migration - Create newsletter controller with subscribe/unsubscribe endpoints - Add newsletter routes and validation - Implement newsletter service with email validation - Add setup documentation and migration scripts - Include test page for newsletter functionality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
155 lines
3.8 KiB
JavaScript
155 lines
3.8 KiB
JavaScript
/**
|
|
* Controller Newsletter
|
|
*/
|
|
import { pool } from '../../db.js';
|
|
import { AppError, asyncHandler } from '../middleware/errorHandler.js';
|
|
import { sendNewsletterConfirmationEmail } from '../services/newsletter.service.js';
|
|
|
|
/**
|
|
* S'abonner à la newsletter
|
|
* POST /api/newsletter/subscribe
|
|
*/
|
|
export const subscribe = asyncHandler(async (req, res, next) => {
|
|
const { email } = req.body;
|
|
|
|
if (!email) {
|
|
return next(new AppError('Email requis', 400));
|
|
}
|
|
|
|
// Vérifier si l'email existe déjà
|
|
const existingSubscription = await pool.query(
|
|
'SELECT * FROM newsletters WHERE email = $1',
|
|
[email]
|
|
);
|
|
|
|
if (existingSubscription.rows.length > 0) {
|
|
const subscription = existingSubscription.rows[0];
|
|
|
|
// Si déjà abonné et actif
|
|
if (subscription.is_active) {
|
|
return res.json({
|
|
success: true,
|
|
message: 'Vous êtes déjà abonné à notre newsletter',
|
|
});
|
|
}
|
|
|
|
// Si désabonné, réactiver l'abonnement
|
|
await pool.query(
|
|
'UPDATE newsletters SET is_active = TRUE, unsubscribed_at = NULL, updated_at = NOW() WHERE email = $1',
|
|
[email]
|
|
);
|
|
|
|
// Envoyer l'email de confirmation
|
|
try {
|
|
await sendNewsletterConfirmationEmail(email);
|
|
} catch (error) {
|
|
console.error('Erreur envoi email confirmation:', error);
|
|
// On continue même si l'email échoue
|
|
}
|
|
|
|
return res.json({
|
|
success: true,
|
|
message: 'Votre abonnement à la newsletter a été réactivé avec succès',
|
|
});
|
|
}
|
|
|
|
// Créer un nouvel abonnement
|
|
await pool.query(
|
|
'INSERT INTO newsletters (email, is_active) VALUES ($1, TRUE)',
|
|
[email]
|
|
);
|
|
|
|
// Envoyer l'email de confirmation
|
|
try {
|
|
await sendNewsletterConfirmationEmail(email);
|
|
} catch (error) {
|
|
console.error('Erreur envoi email confirmation:', error);
|
|
// On continue même si l'email échoue
|
|
}
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
message: 'Merci ! Vous êtes maintenant abonné à notre newsletter',
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Se désabonner de la newsletter
|
|
* POST /api/newsletter/unsubscribe
|
|
*/
|
|
export const unsubscribe = asyncHandler(async (req, res, next) => {
|
|
const { email } = req.body;
|
|
|
|
if (!email) {
|
|
return next(new AppError('Email requis', 400));
|
|
}
|
|
|
|
// Vérifier si l'abonnement existe
|
|
const subscription = await pool.query(
|
|
'SELECT * FROM newsletters WHERE email = $1',
|
|
[email]
|
|
);
|
|
|
|
if (subscription.rows.length === 0) {
|
|
return next(new AppError('Aucun abonnement trouvé pour cet email', 404));
|
|
}
|
|
|
|
// Désactiver l'abonnement
|
|
await pool.query(
|
|
'UPDATE newsletters SET is_active = FALSE, unsubscribed_at = NOW(), updated_at = NOW() WHERE email = $1',
|
|
[email]
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Vous avez été désabonné de notre newsletter',
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Obtenir tous les abonnés (Admin seulement)
|
|
* GET /api/newsletter/subscribers
|
|
*/
|
|
export const getSubscribers = asyncHandler(async (req, res) => {
|
|
const result = await pool.query(
|
|
`SELECT id, email, is_active, subscribed_at, unsubscribed_at, created_at
|
|
FROM newsletters
|
|
ORDER BY created_at DESC`
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
count: result.rows.length,
|
|
data: result.rows.map(row => ({
|
|
id: row.id,
|
|
email: row.email,
|
|
isActive: row.is_active,
|
|
subscribedAt: row.subscribed_at,
|
|
unsubscribedAt: row.unsubscribed_at,
|
|
createdAt: row.created_at,
|
|
})),
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Obtenir le nombre d'abonnés actifs (Admin seulement)
|
|
* GET /api/newsletter/count
|
|
*/
|
|
export const getActiveCount = asyncHandler(async (req, res) => {
|
|
const result = await pool.query(
|
|
'SELECT COUNT(*) as count FROM newsletters WHERE is_active = TRUE'
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
count: parseInt(result.rows[0].count),
|
|
});
|
|
});
|
|
|
|
export default {
|
|
subscribe,
|
|
unsubscribe,
|
|
getSubscribers,
|
|
getActiveCount,
|
|
};
|