Ajoute le suivi des demandes d'adhésion

This commit is contained in:
Michael committed 2026-07-15 11:02:13 +02:00
1 parent b4a3019098
commit c49c45e65f
6 files changed
+291 -7

No files matched your search

+108 -4
View File
@@ -1,5 +1,5 @@
import { Router } from 'express';
import { query } from '../db.js';
import { pool, query } from '../db.js';
import { requireAuth } from '../middleware/auth.js';
import { validate } from '../middleware/validate.js';
import {
@@ -552,16 +552,120 @@ adminRouter.post('/content/hero-photo', adminOnly, (req, res, next) => {
});
});
// ---------- Demandes d'adhésion (admin only) ----------
adminRouter.get('/demandes', adminOnly, async (_req, res, next) => {
// ---------- Demandes d'adhésion (admin + moderator) ----------
adminRouter.get('/demandes', async (_req, res, next) => {
try {
const result = await query('SELECT * FROM demandes_adhesion ORDER BY created_at DESC');
const result = await query(`
SELECT d.*, m.nom AS membre_nom
FROM demandes_adhesion d
LEFT JOIN members m ON m.id = d.member_id
ORDER BY CASE d.statut WHEN 'nouvelle' THEN 0 WHEN 'contactee' THEN 1 ELSE 2 END,
d.created_at DESC`);
res.json({ demandes: result.rows });
} catch (err) {
next(err);
}
});
adminRouter.post('/demandes/:id/contact', validate(idParam, 'params'), async (req, res, next) => {
try {
const result = await query(
`UPDATE demandes_adhesion
SET statut = 'contactee', contacted_at = COALESCE(contacted_at, now())
WHERE id = $1 AND statut = 'nouvelle'
RETURNING *`,
[req.params.id]
);
if (result.rowCount === 0) {
const existing = await query('SELECT statut FROM demandes_adhesion WHERE id = $1', [req.params.id]);
if (existing.rowCount === 0) return res.status(404).json({ error: 'Demande introuvable' });
return res.status(409).json({ error: 'Cette demande a déjà été prise en charge.' });
}
res.json({ demande: result.rows[0] });
} catch (err) {
next(err);
}
});
adminRouter.post('/demandes/:id/validate', validate(idParam, 'params'), async (req, res, next) => {
let client;
try {
client = await pool.connect();
await client.query('BEGIN');
const request = await client.query(
'SELECT * FROM demandes_adhesion WHERE id = $1 FOR UPDATE',
[req.params.id]
);
if (request.rowCount === 0) {
await client.query('ROLLBACK');
return res.status(404).json({ error: 'Demande introuvable' });
}
const d = request.rows[0];
if (d.statut !== 'contactee') {
await client.query('ROLLBACK');
return res.status(409).json({
error: d.statut === 'validee'
? 'Cette demande a déjà été validée.'
: "Validez d'abord la prise de contact.",
});
}
if (!d.email) {
await client.query('ROLLBACK');
return res.status(400).json({ error: 'Une adresse email est nécessaire pour créer le compte membre.' });
}
let member = await client.query(
'SELECT id FROM members WHERE email = $1 ORDER BY id LIMIT 1 FOR UPDATE',
[d.email]
);
let memberId;
if (member.rowCount > 0) {
memberId = member.rows[0].id;
await client.query(
`UPDATE members
SET valide = true, adhesion = $1, dirigeant = CASE WHEN dirigeant = '' THEN $2 ELSE dirigeant END,
tel = COALESCE(tel, $3), updated_at = now()
WHERE id = $4`,
[new Date().getFullYear(), d.nom, d.tel, memberId]
);
} else {
member = await client.query(
`INSERT INTO members (nom, secteur, dirigeant, adhesion, email, tel, presentation, valide)
VALUES ($1, '', $2, $3, $4, $5, '', true) RETURNING id`,
[d.entreprise, d.nom, new Date().getFullYear(), d.email, d.tel]
);
memberId = member.rows[0].id;
}
const login = await client.query('SELECT id FROM users WHERE member_id = $1', [memberId]);
await client.query(
`UPDATE demandes_adhesion
SET statut = 'validee', contacted_at = COALESCE(contacted_at, now()),
validated_at = now(), member_id = $1
WHERE id = $2`,
[memberId, d.id]
);
await client.query('COMMIT');
let tempPassword = null;
let accessError = null;
if (login.rowCount === 0) {
try {
tempPassword = await ensureMemberAccess(memberId, d.email);
} catch (err) {
if (!(err instanceof AccessError)) throw err;
accessError = err.message;
}
}
res.json({ memberId, email: d.email, tempPassword, accessError });
} catch (err) {
if (client) await client.query('ROLLBACK').catch(() => {});
next(err);
} finally {
client?.release();
}
});
// ---------- Admin & moderator accounts (admin only) ----------
adminRouter.get('/users', adminOnly, async (req, res, next) => {
try {
+12 -1
View File
@@ -136,10 +136,21 @@ CREATE TABLE IF NOT EXISTS demandes_adhesion (
entreprise TEXT NOT NULL CHECK (char_length(entreprise) BETWEEN 1 AND 120),
email CITEXT NOT NULL CHECK (char_length(email) <= 254),
tel TEXT CHECK (char_length(tel) <= 30),
statut TEXT NOT NULL DEFAULT 'nouvelle' CHECK (statut IN ('nouvelle', 'traitee')),
statut TEXT NOT NULL DEFAULT 'nouvelle' CHECK (statut IN ('nouvelle', 'contactee', 'validee')),
contacted_at TIMESTAMPTZ,
validated_at TIMESTAMPTZ,
member_id INTEGER REFERENCES members(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
ALTER TABLE demandes_adhesion ADD COLUMN IF NOT EXISTS tel TEXT CHECK (char_length(tel) <= 30);
ALTER TABLE demandes_adhesion ADD COLUMN IF NOT EXISTS contacted_at TIMESTAMPTZ;
ALTER TABLE demandes_adhesion ADD COLUMN IF NOT EXISTS validated_at TIMESTAMPTZ;
ALTER TABLE demandes_adhesion ADD COLUMN IF NOT EXISTS member_id INTEGER REFERENCES members(id) ON DELETE SET NULL;
ALTER TABLE demandes_adhesion DROP CONSTRAINT IF EXISTS demandes_adhesion_statut_check;
UPDATE demandes_adhesion SET statut = 'contactee', contacted_at = COALESCE(contacted_at, created_at)
WHERE statut = 'traitee';
ALTER TABLE demandes_adhesion ADD CONSTRAINT demandes_adhesion_statut_check
CHECK (statut IN ('nouvelle', 'contactee', 'validee'));
CREATE TABLE IF NOT EXISTS site_content (
key TEXT PRIMARY KEY,