mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-07 03:29:19 +02:00
smtp: add notify_email field; fix admin notification sent to no-reply sender
This commit is contained in:
11
TODO.md
11
TODO.md
@@ -63,6 +63,17 @@
|
|||||||
- [ ] Verify TCP reachability from XAMXAM VM to LDAP server (port 636)
|
- [ ] Verify TCP reachability from XAMXAM VM to LDAP server (port 636)
|
||||||
- [ ] See `docs/LDAP_AUTH_PLAN.md` for full phase-by-phase plan
|
- [ ] See `docs/LDAP_AUTH_PLAN.md` for full phase-by-phase plan
|
||||||
|
|
||||||
|
## SMTP notify_email fix
|
||||||
|
|
||||||
|
- [x] Migration 006: add `notify_email` column to `smtp_settings`
|
||||||
|
- [x] `SmtpRelay::getSettings()` — include `notify_email` in SELECT + defaults
|
||||||
|
- [x] `SmtpRelay::updateSettings()` — persist `notify_email`
|
||||||
|
- [x] `SmtpRelay::getNotifyEmail()` — returns `notify_email` ?? `from_email`
|
||||||
|
- [x] `request-access.php` — use `getNotifyEmail()` instead of `from_email` for admin notifications
|
||||||
|
- [x] `actions/settings.php` — wire `smtp_notify_email` POST field
|
||||||
|
- [x] Template: add "Adresse de notification admin" field to SMTP form
|
||||||
|
- [x] `schema.sql` — updated DDL
|
||||||
|
|
||||||
## SMTP credential validation
|
## SMTP credential validation
|
||||||
|
|
||||||
- [x] Add `SmtpProbeException` with `field` property for structured error classification
|
- [x] Add `SmtpProbeException` with `field` property for structured error classification
|
||||||
|
|||||||
4
app/migrations/applied/006_smtp_notify_email.sql
Normal file
4
app/migrations/applied/006_smtp_notify_email.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
-- Migration 006: add notify_email to smtp_settings
|
||||||
|
-- notify_email is the address that receives admin notifications (access requests, etc.)
|
||||||
|
-- It is separate from from_email (the sender/no-reply address).
|
||||||
|
ALTER TABLE smtp_settings ADD COLUMN notify_email TEXT NOT NULL DEFAULT '';
|
||||||
@@ -34,12 +34,13 @@ if ($section === 'formulaire') {
|
|||||||
App::flash('success', "Types de travaux mis à jour.");
|
App::flash('success', "Types de travaux mis à jour.");
|
||||||
} elseif ($section === 'smtp') {
|
} elseif ($section === 'smtp') {
|
||||||
$smtpData = [
|
$smtpData = [
|
||||||
'host' => $_POST['smtp_host'] ?? '',
|
'host' => $_POST['smtp_host'] ?? '',
|
||||||
'port' => $_POST['smtp_port'] ?? 587,
|
'port' => $_POST['smtp_port'] ?? 587,
|
||||||
'encryption' => $_POST['smtp_encryption'] ?? 'tls',
|
'encryption' => $_POST['smtp_encryption'] ?? 'tls',
|
||||||
'username' => $_POST['smtp_username'] ?? '',
|
'username' => $_POST['smtp_username'] ?? '',
|
||||||
'from_email' => $_POST['smtp_from_email'] ?? '',
|
'from_email' => $_POST['smtp_from_email'] ?? '',
|
||||||
'from_name' => $_POST['smtp_from_name'] ?? 'XAMXAM',
|
'from_name' => $_POST['smtp_from_name'] ?? 'XAMXAM',
|
||||||
|
'notify_email' => $_POST['smtp_notify_email'] ?? '',
|
||||||
];
|
];
|
||||||
// Only update password when user actually typed something.
|
// Only update password when user actually typed something.
|
||||||
$pwd = $_POST['smtp_password'] ?? '';
|
$pwd = $_POST['smtp_password'] ?? '';
|
||||||
|
|||||||
@@ -188,9 +188,9 @@ try {
|
|||||||
);
|
);
|
||||||
$plain = htmlToPlain($body);
|
$plain = htmlToPlain($body);
|
||||||
|
|
||||||
$settings = SmtpRelay::getSettings($db);
|
$notifyEmail = SmtpRelay::getNotifyEmail($db);
|
||||||
if (!empty($settings['from_email'])) {
|
if ($notifyEmail !== '') {
|
||||||
SmtpRelay::send($db, $settings['from_email'], $subject, $body, $plain);
|
SmtpRelay::send($db, $notifyEmail, $subject, $body, $plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
http_response_code(200);
|
http_response_code(200);
|
||||||
|
|||||||
@@ -39,22 +39,34 @@ class SmtpRelay {
|
|||||||
*/
|
*/
|
||||||
public static function getSettings(Database $db): array {
|
public static function getSettings(Database $db): array {
|
||||||
$stmt = $db->getPDO()->query(
|
$stmt = $db->getPDO()->query(
|
||||||
"SELECT host, port, encryption, username, password, from_email, from_name
|
"SELECT host, port, encryption, username, password, from_email, from_name, notify_email
|
||||||
FROM v_smtp_active LIMIT 1"
|
FROM v_smtp_active LIMIT 1"
|
||||||
);
|
);
|
||||||
$row = $stmt->fetch();
|
$row = $stmt->fetch();
|
||||||
|
|
||||||
return $row ?: [
|
return $row ?: [
|
||||||
'host' => '',
|
'host' => '',
|
||||||
'port' => 587,
|
'port' => 587,
|
||||||
'encryption' => 'tls',
|
'encryption' => 'tls',
|
||||||
'username' => '',
|
'username' => '',
|
||||||
'password' => '',
|
'password' => '',
|
||||||
'from_email' => '',
|
'from_email' => '',
|
||||||
'from_name' => 'XAMXAM',
|
'from_name' => 'XAMXAM',
|
||||||
|
'notify_email' => '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the address that should receive admin notification emails.
|
||||||
|
* Uses notify_email when set, falls back to from_email.
|
||||||
|
*/
|
||||||
|
public static function getNotifyEmail(Database $db): string
|
||||||
|
{
|
||||||
|
$s = self::getSettings($db);
|
||||||
|
$notify = trim($s['notify_email'] ?? '');
|
||||||
|
return $notify !== '' ? $notify : trim($s['from_email'] ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upsert SMTP settings.
|
* Upsert SMTP settings.
|
||||||
*
|
*
|
||||||
@@ -71,25 +83,27 @@ class SmtpRelay {
|
|||||||
|
|
||||||
$stmt = $db->getPDO()->prepare(
|
$stmt = $db->getPDO()->prepare(
|
||||||
"UPDATE smtp_settings
|
"UPDATE smtp_settings
|
||||||
SET host = :host,
|
SET host = :host,
|
||||||
port = :port,
|
port = :port,
|
||||||
encryption = :encryption,
|
encryption = :encryption,
|
||||||
username = :username,
|
username = :username,
|
||||||
password = :password,
|
password = :password,
|
||||||
from_email = :from_email,
|
from_email = :from_email,
|
||||||
from_name = :from_name,
|
from_name = :from_name,
|
||||||
updated_at = CURRENT_TIMESTAMP
|
notify_email = :notify_email,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE id = 1"
|
WHERE id = 1"
|
||||||
);
|
);
|
||||||
|
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
':host' => trim($merged['host']),
|
':host' => trim($merged['host']),
|
||||||
':port' => $port,
|
':port' => $port,
|
||||||
':encryption' => $encryption,
|
':encryption' => $encryption,
|
||||||
':username' => trim($merged['username']),
|
':username' => trim($merged['username']),
|
||||||
':password' => $merged['password'],
|
':password' => $merged['password'],
|
||||||
':from_email' => trim($merged['from_email']),
|
':from_email' => trim($merged['from_email']),
|
||||||
':from_name' => trim($merged['from_name']),
|
':from_name' => trim($merged['from_name']),
|
||||||
|
':notify_email' => trim($merged['notify_email'] ?? ''),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -352,15 +352,16 @@ CREATE INDEX IF NOT EXISTS idx_share_links_active ON share_links(is_active);
|
|||||||
|
|
||||||
-- Singleton row — id is always 1. Credentials stored in clear for now.
|
-- Singleton row — id is always 1. Credentials stored in clear for now.
|
||||||
CREATE TABLE IF NOT EXISTS smtp_settings (
|
CREATE TABLE IF NOT EXISTS smtp_settings (
|
||||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||||
host TEXT NOT NULL DEFAULT '',
|
host TEXT NOT NULL DEFAULT '',
|
||||||
port INTEGER NOT NULL DEFAULT 587,
|
port INTEGER NOT NULL DEFAULT 587,
|
||||||
encryption TEXT NOT NULL DEFAULT 'tls', -- 'tls' | 'ssl' | 'none'
|
encryption TEXT NOT NULL DEFAULT 'tls', -- 'tls' | 'ssl' | 'none'
|
||||||
username TEXT NOT NULL DEFAULT '',
|
username TEXT NOT NULL DEFAULT '',
|
||||||
password TEXT NOT NULL DEFAULT '', -- stored in clear for now; encrypt later
|
password TEXT NOT NULL DEFAULT '', -- stored in clear for now; encrypt later
|
||||||
from_email TEXT NOT NULL DEFAULT '',
|
from_email TEXT NOT NULL DEFAULT '',
|
||||||
from_name TEXT NOT NULL DEFAULT 'XAMXAM',
|
from_name TEXT NOT NULL DEFAULT 'XAMXAM',
|
||||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
notify_email TEXT NOT NULL DEFAULT '', -- recipient for admin notifications
|
||||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT OR IGNORE INTO smtp_settings (id) VALUES (1);
|
INSERT OR IGNORE INTO smtp_settings (id) VALUES (1);
|
||||||
|
|||||||
@@ -265,16 +265,24 @@
|
|||||||
<legend>Expéditeur par défaut</legend>
|
<legend>Expéditeur par défaut</legend>
|
||||||
<div class="param-grid">
|
<div class="param-grid">
|
||||||
<div>
|
<div>
|
||||||
<label for="smtp_from_email">Adresse e-mail</label>
|
<label for="smtp_from_email">Adresse e-mail d'expédition</label>
|
||||||
<input type="email" id="smtp_from_email" name="smtp_from_email"
|
<input type="email" id="smtp_from_email" name="smtp_from_email"
|
||||||
value="<?= htmlspecialchars($smtpSettings['from_email']) ?>"
|
value="<?= htmlspecialchars($smtpSettings['from_email']) ?>"
|
||||||
placeholder="noreply@example.com">
|
placeholder="noreply@example.com">
|
||||||
|
<small>Adresse utilisée comme expéditeur (champ From:).</small>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="smtp_from_name">Nom d'expéditeur</label>
|
<label for="smtp_from_name">Nom d'expéditeur</label>
|
||||||
<input type="text" id="smtp_from_name" name="smtp_from_name"
|
<input type="text" id="smtp_from_name" name="smtp_from_name"
|
||||||
value="<?= htmlspecialchars($smtpSettings['from_name']) ?>">
|
value="<?= htmlspecialchars($smtpSettings['from_name']) ?>">
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="smtp_notify_email">Adresse de notification admin</label>
|
||||||
|
<input type="email" id="smtp_notify_email" name="smtp_notify_email"
|
||||||
|
value="<?= htmlspecialchars($smtpSettings['notify_email'] ?? '') ?>"
|
||||||
|
placeholder="admin@example.com">
|
||||||
|
<small>Reçoit les notifications (demandes d’accès, etc.). Si vide, utilise l’adresse d’expédition.</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user