Files
maria_uslugi/public/cabinet/accepter_invitation.php
T
2026-03-05 10:25:39 +01:00

298 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../includes/header_cabinet.php';
if (!function_exists('h')) { function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); } }
$token = trim((string)($_GET['token'] ?? ''));
$inv = null;
if ($token) {
$q = $pdo->prepare("SELECT * FROM invitations WHERE token=:t AND status='envoyee' LIMIT 1");
$q->execute(['t'=>$token]);
$inv = $q->fetch(PDO::FETCH_ASSOC);
}
if (!$inv) {
echo '<div class="container my-4"><div class="alert alert-danger">'.h($translations['inv_token_invalide'] ?? 'Lien invalide.').'</div></div>';
exit;
}
if (!empty($inv['expires_at']) && new DateTime($inv['expires_at']) < new DateTime()) {
echo '<div class="container my-4"><div class="alert alert-warning">'.h($translations['inv_token_expire'] ?? 'Lien expiré.').'</div></div>';
exit;
}
$email = strtolower((string)$inv['email']);
$praticien_id = (int)$inv['praticien_id'];
$connectedRole = strtolower((string)($_SESSION['role'] ?? ''));
$connectedId = (int)($_SESSION['compte_id'] ?? 0);
$connectedEmail= strtolower((string)($_SESSION['email'] ?? ''));
$done = false;
$msg = '';
// =====================================================
// CAS 1 : Déjà connecté comme secrétaire
// =====================================================
if ($connectedRole === 'secretaire' && $connectedId > 0) {
if ($connectedEmail === $email) {
// rattachement au praticien si pas encore lié
$chk = $pdo->prepare("SELECT id FROM secretaire_praticien WHERE secretaire_user_id=:u AND praticien_id=:p");
$chk->execute(['u'=>$connectedId,'p'=>$praticien_id]);
if (!$chk->fetch()) {
$ins = $pdo->prepare("INSERT INTO secretaire_praticien (secretaire_user_id, praticien_id, can_manage_rdv, can_edit_slots, is_active)
VALUES (:u,:p,1,1,1)");
$ins->execute(['u'=>$connectedId,'p'=>$praticien_id]);
}
$pdo->prepare("UPDATE invitations SET status='acceptee' WHERE id=:id")->execute(['id'=>$inv['id']]);
$done = true;
} else {
// autre email → doit se connecter avec le bon compte
$msg = sprintf(
$translations['inv_email_diff'] ?? "Vous êtes connecté avec %s, mais l’invitation est pour %s. Veuillez vous connecter avec le bon compte.",
h($connectedEmail), h($email)
);
}
}
// =====================================================
// CAS 2 : POST (création compte si inexistant)
// =====================================================
elseif (($_SERVER['REQUEST_METHOD']??'')==='POST') {
$pwd = (string)($_POST['pwd'] ?? '');
$pwd2 = (string)($_POST['pwd2'] ?? '');
if (strlen($pwd) < 8 || $pwd !== $pwd2) {
$msg = $translations['inv_pwd_invalid'] ?? 'Mot de passe invalide ou non identique.';
} else {
// Vérifier si un compte existe déjà avec ce mail
$chk = $pdo->prepare("SELECT id, role FROM compte WHERE email=:e LIMIT 1");
$chk->execute(['e'=>$email]);
$acc = $chk->fetch(PDO::FETCH_ASSOC);
if ($acc) {
if ($acc['role'] !== 'secretaire') {
$msg = $translations['inv_email_occupe'] ?? "Un compte avec cet email existe déjà avec un autre rôle.";
} else {
// compte secrétaire déjà existant → rediriger vers login AVEC token
header("Location: /connexion.php?next=" . urlencode("/public/cabinet/accepter_invitation.php?token=".$token));
exit;
}
} else {
// création nouveau compte secrétaire
$ins = $pdo->prepare("INSERT INTO compte (email, mot_de_passe, role, reference_id, token_validation, email_valide)
VALUES (:e, :pwd, 'secretaire', 0, NULL, 1)");
$ins->execute([
'e' => $email,
'pwd' => password_hash($pwd, PASSWORD_BCRYPT)
]);
$newId = (int)$pdo->lastInsertId();
$_SESSION['compte_id'] = $newId;
$_SESSION['role'] = 'secretaire';
$_SESSION['reference_id'] = 0;
$_SESSION['email'] = $email;
$pdo->prepare("INSERT INTO secretaire_praticien (secretaire_user_id, praticien_id, can_manage_rdv, can_edit_slots, is_active)
VALUES (:u,:p,1,1,1)")
->execute(['u'=>$newId,'p'=>$praticien_id]);
$pdo->prepare("UPDATE invitations SET status='acceptee' WHERE id=:id")->execute(['id'=>$inv['id']]);
$done = true;
}
}
}
// =====================================================
// CAS 3 : GET initial (ni connecté ni posté)
// Vérifier si compte existe déjà
// =====================================================
else {
$chk = $pdo->prepare("SELECT id, role FROM compte WHERE email=:e LIMIT 1");
$chk->execute(['e'=>$email]);
$acc = $chk->fetch(PDO::FETCH_ASSOC);
if ($acc && $acc['role']==='secretaire') {
echo '<div class="container my-4"><div class="alert alert-info">'.
h($translations['inv_compte_existe'] ?? 'Un compte secrétaire existe déjà, veuillez vous connecter.').
'</div><a href="/connexion.php?next='.urlencode("/public/cabinet/accepter_invitation.php?token=".$token).'" class="btn btn-primary">Connexion</a></div>';
exit;
}
}
?>
<div class="main1">
<div class="container py-5">
<div class="shadow p-4 rounded bg-light mx-auto" style="max-width:600px;">
<h1 class="h4 mb-3"><?= h($translations['inv_accepter_titre'] ?? 'Accepter l’invitation') ?></h1>
<?php if($done): ?>
<div class="alert alert-success mb-4"><?= h($translations['inv_ok'] ?? 'Invitation acceptée. Vous avez désormais accès au secrétariat.') ?></div>
<a class="btn btn-primary" href="/public/cabinet/dashboard.php"><?= h($translations['btn_aller_dashboard_sec'] ?? 'Aller au tableau de bord secrétaire') ?></a>
<?php else: ?>
<div class="card mb-3"><div class="card-body">
<p class="mb-1"><strong><?= h($translations['inv_email'] ?? 'Email') ?>:</strong> <?= h($email) ?></p>
<p class="mb-0"><strong><?= h($translations['inv_praticien'] ?? 'Praticien') ?>:</strong> #<?= (int)$praticien_id ?></p>
</div></div>
<?php if(!empty($msg)): ?>
<div class="alert alert-warning"><?= $msg ?></div>
<?php endif; ?>
<?php if($connectedRole!=='secretaire' || $connectedEmail!==$email): ?>
<form method="post" class="card p-3" id="create-secretary-form">
<label class="form-label mb-2">
<?= h($translations['inv_choisir_pwd'] ?? 'Choisissez un mot de passe (min. 8 caractères)') ?>
</label>
<!-- Mot de passe -->
<!-- MDP -->
<div class="mb-2 position-relative">
<input type="password" name="pwd" id="pwd" class="form-control pe-5"
minlength="8" required autocomplete="new-password"
placeholder="<?= h($translations['motdepasse_placeholder'] ?? 'Mot de passe') ?>">
<span class="toggle-password" onclick="togglePassword('pwd')"
style="position:absolute;right:12px;top:50%;transform:translateY(-50%);cursor:pointer;user-select:none;">👁️</span>
</div>
<div id="niveau-securite" class="mb-2 text-muted">
<?= h($translations['mdp_regle_min'] ?? 'min 8: (A–z)+(1–9)+(&–!)') ?>
</div>
<div class="strength-bar d-flex gap-1 mb-3" aria-hidden="true" style="height:8px;">
<div class="strength-fill flex-fill" style="background:#d9d9d9;border-radius:6px;"></div>
<div class="strength-fill flex-fill" style="background:#d9d9d9;border-radius:6px;"></div>
<div class="strength-fill flex-fill" style="background:#d9d9d9;border-radius:6px;"></div>
</div>
<!-- Confirmation -->
<div class="mb-2 position-relative">
<input type="password" name="pwd2" id="pwd2" class="form-control pe-5"
minlength="8" required autocomplete="new-password"
placeholder="<?= h($translations['confirm_mdp_placeholder'] ?? 'Confirmer le mot de passe') ?>">
<span class="toggle-password" onclick="togglePassword('pwd2')"
style="position:absolute;right:12px;top:50%;transform:translateY(-50%);cursor:pointer;user-select:none;">👁️</span>
</div>
<small id="confirm-feedback" class="d-block mb-3 text-muted" style="display:none;">—</small>
<button id="btn-submit" class="btn btn-primary" disabled>
<?= h($translations['inv_btn_creer_compte'] ?? 'Créer mon compte & accepter') ?>
</button>
</form>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</div>
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?? '&copy; '.date('Y') ?></p>
</div>
</footer>
<script>
function togglePassword(id){
const i = document.getElementById(id);
if (i) i.type = (i.type === 'password') ? 'text' : 'password';
}
(function(){
const form = document.getElementById('create-secretary-form') || document.getElementById('form-inscription') || document.forms[0];
const pwd = document.getElementById('pwd');
const cpwd = document.getElementById('pwd2');
const fills = Array.from(document.querySelectorAll('.strength-fill'));
const hint = document.getElementById('niveau-securite');
const fb = document.getElementById('confirm-feedback');
const submit = document.getElementById('btn-submit');
const T = {
rule : '<?= addslashes($translations['mdp_regle_min'] ?? 'min 8: (A–z)+(1–9)+(&–!)') ?>',
weak : '<?= addslashes($translations['securite_faible'] ?? 'Sécurité : faible') ?>',
medium: '<?= addslashes($translations['securite_moyen'] ?? 'Sécurité : moyen') ?>',
strong: '<?= addslashes($translations['securite_fort'] ?? 'Sécurité : fort') ?>',
ok : '<?= addslashes($translations['mdp_identiques_ok'] ?? 'Les mots de passe correspondent.') ?>',
ko : '<?= addslashes($translations['mdp_non_identiques'] ?? 'Les mots de passe ne correspondent pas.') ?>'
};
function score(val){
if(!val) return 0;
let s = 0;
if(/[a-z]/.test(val)) s++;
if(/[A-Z]/.test(val)) s++;
if(/\d/.test(val)) s++;
if(/[\W_]/.test(val)) s++;
if(val.length>=8) s++;
return Math.min(s,5); // 0..5
}
function paintStrength(s){
// reset
fills.forEach(el => el.style.background = '#d9d9d9');
// niveaux: 0-1 faible(1 segment), 2-3 moyen(2), 4-5 fort(3)
let n = 0, color = '#dc3545'; // rouge
if (s <= 1) { n = 1; color = '#dc3545'; }
else if (s <= 3) { n = 2; color = '#ffc107'; } // jaune
else { n = 3; color = '#28a745'; } // vert
for (let i=0;i<n;i++) fills[i].style.background = color;
if (hint){
hint.classList.remove('text-danger','text-warning','text-success');
if (n===1){ hint.textContent = T.weak; hint.classList.add('text-danger'); }
else if (n===2){ hint.textContent = T.medium; hint.classList.add('text-warning'); }
else { hint.textContent = T.strong; hint.classList.add('text-success'); }
}
}
function checkMatch(){
if (!fb) return false;
if (!cpwd.value){ fb.style.display='none'; return false; }
const same = (pwd.value === cpwd.value) && cpwd.value.length>=8;
fb.textContent = same ? T.ok : T.ko;
fb.style.color = same ? '#198754' : '#dc3545';
fb.style.display = 'block';
return same;
}
function update(){
const v = pwd.value;
// ——— ÉTAT NEUTRE TANT QUE RIEN N'EST SAISI ———
if (!v) {
// barre toute grise
fills.forEach(el => el.style.background = '#d9d9d9');
// texte d'aide (règle) en gris
if (hint){
hint.textContent = T.rule;
hint.classList.remove('text-danger','text-warning','text-success');
hint.classList.add('text-muted');
}
// reset confirmation
if (fb){ fb.style.display = 'none'; }
// bouton désactivé
if (submit){ submit.disabled = true; }
return; // <<< on sort ici, pas de rouge par défaut
}
// ——— LOGIQUE NORMALE SI QUELQUE CHOSE EST SAISI ———
const sc = score(v);
paintStrength(sc);
const same = checkMatch();
if (submit){
// OK si force >= moyen (>=2 segments), longueur >=8 et confirmation OK
const ok = (sc >= 2) && (v.length >= 8) && same;
submit.disabled = !ok;
}
}
if (hint) hint.classList.remove('text-muted');
if (pwd) pwd.addEventListener('input', update);
if (cpwd) cpwd.addEventListener('input', update);
if (form) form.addEventListener('submit', function(e){
if (submit && submit.disabled){ e.preventDefault(); }
});
update(); // init
})();
</script>