Email d'invitation HTML généré depuis l'administration des rencontres
Chaque rencontre dispose d'un bouton « ✉ Email » dans l'administration (admins et modérateurs) qui génère un email HTML prêt à envoyer, aux couleurs du site avec le logo du club : titre, description, encadré date/heure/lieu/places restantes et bouton d'inscription. - Nouvelle route GET /api/admin/rencontres/:id/email : construit l'email (mise en page en tables + styles inline, compatible clients mail) avec des URL absolues dérivées de l'hôte de la requête. - Le bouton de l'email pointe vers /?inscription=<id> : la page d'accueil ouvre alors automatiquement la modale d'inscription de la rencontre. - Modale d'aperçu dans l'admin : copie de l'email (HTML enrichi presse- papiers pour coller directement dans un logiciel de messagerie), copie de l'objet et du lien d'inscription, téléchargement du fichier .html. - Les images publiques (logo, uploads) sont maintenant servies avec Cross-Origin-Resource-Policy: cross-origin pour que le logo se charge dans les webmails et l'aperçu. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fkg15RCxNgUys4ru73He2o
This commit is contained in:
5 files changed
+235
-4
No files matched your search
@@ -18,6 +18,7 @@ import { imageUpload, saveImage, deleteImage } from '../uploads.js';
|
||||
import { ensureMemberAccess } from '../memberAccess.js';
|
||||
import { createStaffUser, resetStaffAccess } from '../userAccess.js';
|
||||
import { AccessError } from '../errors.js';
|
||||
import { buildInvitationEmail } from '../emailTemplate.js';
|
||||
|
||||
export const adminRouter = Router();
|
||||
|
||||
@@ -227,6 +228,22 @@ adminRouter.post('/rencontres/:id/image', validate(idParam, 'params'), (req, res
|
||||
});
|
||||
});
|
||||
|
||||
// Ready-to-send HTML invitation email for a rencontre (admin + moderator).
|
||||
// The registration link opens the public site with the inscription modal
|
||||
// pre-opened (/?inscription=<id>). URLs are absolute, built from the
|
||||
// request's host so they match however the site is reached (direct port
|
||||
// or reverse proxy).
|
||||
adminRouter.get('/rencontres/:id/email', validate(idParam, 'params'), async (req, res, next) => {
|
||||
try {
|
||||
const result = await query(`${RENC_SQL} WHERE r.id = $1 GROUP BY r.id`, [req.params.id]);
|
||||
if (result.rowCount === 0) return res.status(404).json({ error: 'Rencontre introuvable' });
|
||||
const baseUrl = `${req.protocol}://${req.get('host')}`;
|
||||
res.json(buildInvitationEmail({ rencontre: result.rows[0], baseUrl }));
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
adminRouter.get('/rencontres/:id/inscriptions', validate(idParam, 'params'), async (req, res, next) => {
|
||||
try {
|
||||
const result = await query(`${INSCR_SQL} WHERE i.rencontre_id = $1 ORDER BY i.nom`, [req.params.id]);
|
||||
|
||||
Reference in new issue
Block a user