Fix mail config not reaching vm420 + let admins view/set a user's email
docker-compose.yml (the file vm420 actually runs, not
docker-compose.prod.yml) hardcoded MAIL_HOST=mailhog and
MAIL_SMTP_AUTH=false with no way to override from .env, and never
passed MAIL_USERNAME/MAIL_PASSWORD through at all - so setting real
values in .env silently had no effect on the running container.
Registrations succeeded and created accounts, but the password email
was never actually sent (PHPMailer tried to reach a nonexistent
"mailhog" host inside vm420's network). Switched to
${MAIL_HOST:-mailhog}-style fallbacks, same pattern already used for
DATABASE_PASSWORD, so local dev still defaults to mailhog for free
while a real .env override now actually takes effect.
Separately: the admin-panel user form never had an email field at
all (only register.php could set one) - a superadmin had no way to
view or correct a self-registered user's email address. Added the
field (optional, uniqueness-checked, defaults to forcing
must_set_email on next login if left blank) to form_users.php,
Users::addUser()/editUser(), and the users list/table.
This commit is contained in:
@@ -12,6 +12,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-envelope"></i></span>
|
||||
</div>
|
||||
|
||||
<input type="email" name="email" placeholder="Email" class="form-control" value="<?php echo ($edit) ? htmlspecialchars($user['email'] ?? '', ENT_QUOTES, 'UTF-8') : ''; ?>" autocomplete="off">
|
||||
</div>
|
||||
<small class="form-text text-muted">Used to log in once set. Leave blank to prompt for it on next login.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="password">Password *</label>
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%">ID</th>
|
||||
<th width="45%">Username</th>
|
||||
<th width="40%">Type</th>
|
||||
<th width="25%">Username</th>
|
||||
<th width="30%">Email</th>
|
||||
<th width="30%">Type</th>
|
||||
<th width="10%">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -16,6 +17,7 @@
|
||||
<tr>
|
||||
<td><?php echo $row['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($row['username']); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['email'] ?? ''); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['type']); ?></td>
|
||||
<td>
|
||||
<!-- EDIT -->
|
||||
|
||||
@@ -32,6 +32,23 @@ class Users
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side validation of the (optional, for admin-created accounts) email address.
|
||||
* Empty is allowed here - an account without one gets must_set_email=1, same as a
|
||||
* pre-migration legacy account (see the callers below).
|
||||
*/
|
||||
private function validateEmail($email) {
|
||||
if ($email === '' || $email === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!is_string($email) || strlen($email) > 255 || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
return 'Please enter a valid email address.';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -114,11 +131,19 @@ class Users
|
||||
$this->failure($validation_error, 'Location: user.php');
|
||||
}
|
||||
|
||||
$email = trim($input_data['email'] ?? '');
|
||||
$email_error = $this->validateEmail($email);
|
||||
if ($email_error !== null) {
|
||||
$this->failure($email_error, 'Location: user.php');
|
||||
}
|
||||
|
||||
if (!isset($input_data['password']) || strlen($input_data['password']) < 10) {
|
||||
$this->failure('Password must be at least 10 characters long.', 'Location: user.php');
|
||||
}
|
||||
|
||||
$data_to_db["username"] = $input_data["username"];
|
||||
$data_to_db["email"] = $email !== '' ? $email : null;
|
||||
$data_to_db['must_set_email'] = $email === '' ? 1 : 0;
|
||||
$data_to_db['password'] = password_hash($input_data['password'], PASSWORD_DEFAULT);
|
||||
$data_to_db["type"] = $requested_type;
|
||||
$data_to_db['owner_admin_id'] = $owner_admin_id;
|
||||
@@ -131,6 +156,16 @@ class Users
|
||||
if ($db->count >= 1)
|
||||
$this->failure('Username already exists');
|
||||
|
||||
if ($email !== '') {
|
||||
$db = getDbInstance();
|
||||
$db->where('email', $email);
|
||||
$db->get('users');
|
||||
|
||||
if ($db->count >= 1)
|
||||
$this->failure('An account with this email already exists', 'Location: user.php');
|
||||
}
|
||||
|
||||
$db = getDbInstance();
|
||||
$last_id = $db->insert('users', $data_to_db);
|
||||
|
||||
if ($last_id) {
|
||||
@@ -258,6 +293,12 @@ class Users
|
||||
$this->failure($validation_error, 'Location: user.php?'.$query_string);
|
||||
}
|
||||
|
||||
$email = trim($input_data['email'] ?? '');
|
||||
$email_error = $this->validateEmail($email);
|
||||
if ($email_error !== null) {
|
||||
$this->failure($email_error, 'Location: user.php?'.$query_string);
|
||||
}
|
||||
|
||||
if (isset($input_data['password']) && strlen($input_data['password']) > 0 && strlen($input_data['password']) < 10) {
|
||||
$this->failure('Password must be at least 10 characters long.', 'Location: user.php?'.$query_string);
|
||||
}
|
||||
@@ -271,8 +312,25 @@ class Users
|
||||
$this->failure('Username already exists', 'Location: user.php?'.$query_string);
|
||||
}
|
||||
|
||||
if ($email !== '') {
|
||||
$db = getDbInstance();
|
||||
$db->where('email', $email);
|
||||
$db->where('id', $input_data["id"], '!=');
|
||||
$row = $db->getOne('users');
|
||||
|
||||
if (!empty($row['email'])) {
|
||||
$this->failure('An account with this email already exists', 'Location: user.php?'.$query_string);
|
||||
}
|
||||
}
|
||||
|
||||
$data_to_db["username"] = $input_data["username"];
|
||||
$data_to_db["type"] = $requested_type;
|
||||
// Only touch email/must_set_email if an email was actually submitted - an admin
|
||||
// leaving the field blank on an already-set account shouldn't wipe it back out.
|
||||
if ($email !== '') {
|
||||
$data_to_db['email'] = $email;
|
||||
$data_to_db['must_set_email'] = 0;
|
||||
}
|
||||
$data_to_db['can_view_static'] = !empty($input_data['can_view_static']) ? 1 : 0;
|
||||
$data_to_db['can_view_dynamic'] = !empty($input_data['can_view_dynamic']) ? 1 : 0;
|
||||
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ $users = new Users();
|
||||
if (!in_array($_SESSION['type'], ['super', 'admin'], true))
|
||||
$users->failure('Only "super admin" and "admin" accounts can access the user management page', 'Location: index.php');
|
||||
|
||||
$select = array('id', 'username', 'type');
|
||||
$select = array('id', 'username', 'email', 'type');
|
||||
$search_fields = array('username');
|
||||
require_once BASE_PATH . '/includes/search_order.php';
|
||||
$page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? 1;
|
||||
|
||||
Reference in New Issue
Block a user