MSIN-4478 — Add functionality for managing pending invites and account activation for promoteur access. Implement methods to refresh reset tokens, revoke other roles, and deactivate orphan invite stubs. Update invitation handling to support reactivation of previously deactivated accounts. Increment version code.
This commit is contained in:
@ -71,6 +71,11 @@ function fxEveAccesPromoteurT($strClef, $strLangue = 'fr')
|
||||
'fr' => 'Compte créé et accès assigné. Un courriel avec le lien de mot de passe a été envoyé.',
|
||||
'en' => 'Account created and access granted. An email with the password link was sent.',
|
||||
),
|
||||
// MSIN-4478 — réinvite d'un stub jamais activé
|
||||
'eve_acces_promoteur_ok_pending' => array(
|
||||
'fr' => 'Invitation mise à jour. Un courriel avec le lien de mot de passe a été envoyé.',
|
||||
'en' => 'Invitation updated. An email with the password link was sent.',
|
||||
),
|
||||
'eve_acces_promoteur_ok_revoked' => array('fr' => 'Accès retiré.', 'en' => 'Access revoked.'),
|
||||
'eve_acces_promoteur_ok_resent' => array(
|
||||
'fr' => 'Courriel d\'invitation renvoyé.',
|
||||
@ -176,6 +181,145 @@ function fxEveAccesPromoteurHasInviteTeamColumn()
|
||||
return $blnHas;
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4478 — compte stub d'invitation jamais vraiment utilisé (pas de 1re visite).
|
||||
*/
|
||||
function fxEveAccesPromoteurCompteIsPendingInvite($arrCompte)
|
||||
{
|
||||
if (!is_array($arrCompte) || empty($arrCompte['com_id'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$strLastVisit = trim((string)($arrCompte['com_lastvisit'] ?? ''));
|
||||
$blnNeverVisited = ($strLastVisit === '' || strpos($strLastVisit, '0000-00-00') === 0);
|
||||
if (!$blnNeverVisited) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fxEveAccesPromoteurHasInviteTeamColumn()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return intval($arrCompte['com_invite_team'] ?? 0) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4478 — nouveau jeton reset pour renvoyer le mail « créez votre mot de passe ».
|
||||
*
|
||||
* @return string token ('' si colonnes absentes)
|
||||
*/
|
||||
function fxEveAccesPromoteurRefreshResetToken($intComId)
|
||||
{
|
||||
global $objDatabase;
|
||||
|
||||
$intComId = intval($intComId);
|
||||
if ($intComId <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$strToken = uniqid('inv', true);
|
||||
$strNow = function_exists('fxGetDateTime') ? fxGetDateTime() : date('Y-m-d H:i:s');
|
||||
$arrSet = array();
|
||||
|
||||
$tabResetTok = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_comptes LIKE 'com_reset_token'");
|
||||
if ($tabResetTok != null && count($tabResetTok) > 0) {
|
||||
$arrSet[] = "com_reset_token = '" . $objDatabase->fxEscape($strToken) . "'";
|
||||
}
|
||||
$tabResetDate = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_comptes LIKE 'com_reset_date'");
|
||||
if ($tabResetDate != null && count($tabResetDate) > 0) {
|
||||
$arrSet[] = "com_reset_date = '" . $objDatabase->fxEscape($strNow) . "'";
|
||||
}
|
||||
|
||||
if (count($arrSet) === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$objDatabase->fxQuery(
|
||||
'UPDATE inscriptions_comptes SET ' . implode(', ', $arrSet)
|
||||
. ' WHERE com_id = ' . $intComId
|
||||
);
|
||||
|
||||
return $strToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4478 — un seul kit actif/invite par personne+événement : révoque les autres rôles.
|
||||
*/
|
||||
function fxEveAccesPromoteurRevokeOtherKits($intComId, $intEveId, $intKeepRoleId, $intActorComId)
|
||||
{
|
||||
global $objDatabase;
|
||||
|
||||
$intComId = intval($intComId);
|
||||
$intEveId = intval($intEveId);
|
||||
$intKeepRoleId = intval($intKeepRoleId);
|
||||
$intActorComId = intval($intActorComId);
|
||||
|
||||
if ($intComId <= 0 || $intEveId <= 0 || $intKeepRoleId <= 0 || !fxEveAccesIsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tab = $objDatabase->fxGetResults(
|
||||
"SELECT ea_id FROM inscriptions_eve_acces
|
||||
WHERE com_id = $intComId
|
||||
AND eve_id = $intEveId
|
||||
AND role_id <> $intKeepRoleId
|
||||
AND ea_statut IN ('actif', 'invite')"
|
||||
);
|
||||
if ($tab == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($tab as $row) {
|
||||
fxEveAccesRevoke(intval($row['ea_id']), $intActorComId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4478 — après revoke : si stub jamais activé et plus aucun accès, désactive le compte (libère le courriel).
|
||||
*/
|
||||
function fxEveAccesPromoteurDeactivateOrphanInviteStub($intComId)
|
||||
{
|
||||
global $objDatabase;
|
||||
|
||||
$intComId = intval($intComId);
|
||||
if ($intComId <= 0 || !fxEveAccesIsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$arrCompte = $objDatabase->fxGetRow(
|
||||
'SELECT com_id, com_actif, com_invite_team, com_lastvisit
|
||||
FROM inscriptions_comptes WHERE com_id = ' . $intComId . ' LIMIT 1'
|
||||
);
|
||||
if (empty($arrCompte) || !fxEveAccesPromoteurCompteIsPendingInvite($arrCompte)) {
|
||||
return false;
|
||||
}
|
||||
if (intval($arrCompte['com_actif'] ?? 0) !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$intLeft = intval($objDatabase->fxGetVar(
|
||||
"SELECT COUNT(*) FROM inscriptions_eve_acces
|
||||
WHERE com_id = $intComId
|
||||
AND ea_statut IN ('actif', 'invite')"
|
||||
));
|
||||
if ($intLeft > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$arrSet = array('com_actif = 0');
|
||||
$tabResetTok = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_comptes LIKE 'com_reset_token'");
|
||||
if ($tabResetTok != null && count($tabResetTok) > 0) {
|
||||
$arrSet[] = "com_reset_token = ''";
|
||||
}
|
||||
|
||||
$objDatabase->fxQuery(
|
||||
'UPDATE inscriptions_comptes SET ' . implode(', ', $arrSet)
|
||||
. ' WHERE com_id = ' . $intComId
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4401 — crée un compte MS1 minimal pour invitation promoteur.
|
||||
*
|
||||
@ -371,7 +515,7 @@ function fxEveAccesPromoteurSendInviteMail($arrCompte, $arrEve, $arrRole, $strLa
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4401 — invitation / assignation par promoteur.
|
||||
* MSIN-4401 / MSIN-4478 — invitation / assignation par promoteur.
|
||||
*
|
||||
* @return array{state:string,message:string,created?:bool}
|
||||
*/
|
||||
@ -417,8 +561,13 @@ function fxEveAccesPromoteurInvite($intEveId, $intGrantedBy, $arrPost, $strLangu
|
||||
return array('state' => 'error', 'message' => fxEveAccesPromoteurT('eve_acces_promoteur_err_generic', $strLangue));
|
||||
}
|
||||
|
||||
$strCompteCols = 'com_id, com_prenom, com_nom, com_courriel, com_login, com_actif, com_lastvisit';
|
||||
if (fxEveAccesPromoteurHasInviteTeamColumn()) {
|
||||
$strCompteCols .= ', com_invite_team';
|
||||
}
|
||||
|
||||
$rowExisting = $objDatabase->fxGetRow(
|
||||
"SELECT com_id, com_prenom, com_nom, com_courriel, com_login, com_actif
|
||||
"SELECT $strCompteCols
|
||||
FROM inscriptions_comptes
|
||||
WHERE com_courriel = '" . $objDatabase->fxEscape($strCourriel) . "'
|
||||
ORDER BY com_actif DESC, com_id DESC
|
||||
@ -426,13 +575,24 @@ function fxEveAccesPromoteurInvite($intEveId, $intGrantedBy, $arrPost, $strLangu
|
||||
);
|
||||
|
||||
$blnCreated = false;
|
||||
$blnPending = false;
|
||||
$strResetToken = '';
|
||||
$arrCompte = null;
|
||||
|
||||
if (!empty($rowExisting) && is_array($rowExisting)) {
|
||||
$blnPending = fxEveAccesPromoteurCompteIsPendingInvite($rowExisting);
|
||||
|
||||
// MSIN-4478 — stub désactivé après revoke : on le réactive pour réinviter.
|
||||
if (intval($rowExisting['com_actif']) !== 1) {
|
||||
return array('state' => 'error', 'message' => fxEveAccesPromoteurT('eve_acces_promoteur_err_inactive', $strLangue));
|
||||
if (!$blnPending) {
|
||||
return array('state' => 'error', 'message' => fxEveAccesPromoteurT('eve_acces_promoteur_err_inactive', $strLangue));
|
||||
}
|
||||
$objDatabase->fxQuery(
|
||||
'UPDATE inscriptions_comptes SET com_actif = 1 WHERE com_id = ' . intval($rowExisting['com_id'])
|
||||
);
|
||||
$rowExisting['com_actif'] = 1;
|
||||
}
|
||||
|
||||
$arrCompte = $rowExisting;
|
||||
if ($strPrenom !== '' && trim((string)$arrCompte['com_prenom']) === '') {
|
||||
$objDatabase->fxQuery(
|
||||
@ -448,6 +608,10 @@ function fxEveAccesPromoteurInvite($intEveId, $intGrantedBy, $arrPost, $strLangu
|
||||
);
|
||||
$arrCompte['com_nom'] = $strNom;
|
||||
}
|
||||
|
||||
if ($blnPending) {
|
||||
$strResetToken = fxEveAccesPromoteurRefreshResetToken(intval($arrCompte['com_id']));
|
||||
}
|
||||
} else {
|
||||
if ($strPrenom === '' || $strNom === '') {
|
||||
return array('state' => 'error', 'message' => fxEveAccesPromoteurT('eve_acces_promoteur_err_nom', $strLangue));
|
||||
@ -463,6 +627,7 @@ function fxEveAccesPromoteurInvite($intEveId, $intGrantedBy, $arrPost, $strLangu
|
||||
return array('state' => 'error', 'message' => fxEveAccesPromoteurT('eve_acces_promoteur_err_generic', $strLangue));
|
||||
}
|
||||
$blnCreated = true;
|
||||
$blnPending = true;
|
||||
$strResetToken = (string)($arrCreate['reset_token'] ?? '');
|
||||
$arrCompte = array(
|
||||
'com_id' => intval($arrCreate['com_id']),
|
||||
@ -470,17 +635,29 @@ function fxEveAccesPromoteurInvite($intEveId, $intGrantedBy, $arrPost, $strLangu
|
||||
'com_nom' => $strNom,
|
||||
'com_courriel' => $strCourriel,
|
||||
'com_login' => $strCourriel,
|
||||
'com_invite_team' => 1,
|
||||
'com_lastvisit' => '',
|
||||
);
|
||||
}
|
||||
|
||||
// MSIN-4478 — changer de kit = remplacer, pas empiler.
|
||||
fxEveAccesPromoteurRevokeOtherKits(
|
||||
intval($arrCompte['com_id']),
|
||||
$intEveId,
|
||||
$intRoleId,
|
||||
$intGrantedBy
|
||||
);
|
||||
|
||||
// Stub jamais activé → statut invite + mail mot de passe (même au 2e envoi).
|
||||
$strGrantStatut = $blnPending ? 'invite' : 'actif';
|
||||
$arrGrant = fxEveAccesGrant(
|
||||
intval($arrCompte['com_id']),
|
||||
$intEveId,
|
||||
$intRoleId,
|
||||
$intJours,
|
||||
$intGrantedBy,
|
||||
'MSIN-4401 invitation promoteur',
|
||||
$blnCreated ? 'invite' : 'actif'
|
||||
'MSIN-4478 invitation promoteur',
|
||||
$strGrantStatut
|
||||
);
|
||||
|
||||
if (($arrGrant['state'] ?? '') !== 'success') {
|
||||
@ -492,22 +669,35 @@ function fxEveAccesPromoteurInvite($intEveId, $intGrantedBy, $arrPost, $strLangu
|
||||
|
||||
// L'accès est déjà enregistré : un échec mail ne doit pas faire planter la page.
|
||||
try {
|
||||
fxEveAccesPromoteurSendInviteMail($arrCompte, $arrEve, $arrRole, $strLangue, $blnCreated, $strResetToken);
|
||||
fxEveAccesPromoteurSendInviteMail(
|
||||
$arrCompte,
|
||||
$arrEve,
|
||||
$arrRole,
|
||||
$strLangue,
|
||||
$blnPending,
|
||||
$strResetToken
|
||||
);
|
||||
} catch (Throwable $e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if ($blnCreated) {
|
||||
$strMsg = fxEveAccesPromoteurT('eve_acces_promoteur_ok_created', $strLangue);
|
||||
} elseif ($blnPending) {
|
||||
$strMsg = fxEveAccesPromoteurT('eve_acces_promoteur_ok_pending', $strLangue);
|
||||
} else {
|
||||
$strMsg = fxEveAccesPromoteurT('eve_acces_promoteur_ok_existing', $strLangue);
|
||||
}
|
||||
|
||||
return array(
|
||||
'state' => 'success',
|
||||
'created' => $blnCreated,
|
||||
'message' => $blnCreated
|
||||
? fxEveAccesPromoteurT('eve_acces_promoteur_ok_created', $strLangue)
|
||||
: fxEveAccesPromoteurT('eve_acces_promoteur_ok_existing', $strLangue),
|
||||
'message' => $strMsg,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* MSIN-4401 — révocation par le promoteur (team.manage ou auteur du grant / super admin).
|
||||
* MSIN-4401 / MSIN-4478 — révocation par le promoteur (team.manage ou auteur du grant / super admin).
|
||||
*/
|
||||
function fxEveAccesPromoteurRevoke($intEaId, $intActorComId, $intEveId)
|
||||
{
|
||||
@ -531,7 +721,12 @@ function fxEveAccesPromoteurRevoke($intEaId, $intActorComId, $intEveId)
|
||||
return array('state' => 'error');
|
||||
}
|
||||
|
||||
return fxEveAccesRevoke($intEaId, $intActorComId);
|
||||
$arrResult = fxEveAccesRevoke($intEaId, $intActorComId);
|
||||
if (($arrResult['state'] ?? '') === 'success') {
|
||||
fxEveAccesPromoteurDeactivateOrphanInviteStub(intval($tab['com_id'] ?? 0));
|
||||
}
|
||||
|
||||
return $arrResult;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -592,27 +787,12 @@ function fxEveAccesPromoteurResendMail($intEaId, $intActorComId, $intEveId, $str
|
||||
$strLastVisit = trim((string)($arrCompte['com_lastvisit'] ?? ''));
|
||||
$blnInviteTeam = intval($arrCompte['com_invite_team'] ?? 0) === 1;
|
||||
$blnPending = ($strStatut === 'invite')
|
||||
|| fxEveAccesPromoteurCompteIsPendingInvite($arrCompte)
|
||||
|| ($blnInviteTeam && ($strLastVisit === '' || strpos($strLastVisit, '0000-00-00') === 0));
|
||||
|
||||
$strResetToken = '';
|
||||
if ($blnPending) {
|
||||
$strResetToken = uniqid('inv', true);
|
||||
$strNow = function_exists('fxGetDateTime') ? fxGetDateTime() : date('Y-m-d H:i:s');
|
||||
$arrSet = array();
|
||||
$tabResetTok = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_comptes LIKE 'com_reset_token'");
|
||||
if ($tabResetTok != null && count($tabResetTok) > 0) {
|
||||
$arrSet[] = "com_reset_token = '" . $objDatabase->fxEscape($strResetToken) . "'";
|
||||
}
|
||||
$tabResetDate = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_comptes LIKE 'com_reset_date'");
|
||||
if ($tabResetDate != null && count($tabResetDate) > 0) {
|
||||
$arrSet[] = "com_reset_date = '" . $objDatabase->fxEscape($strNow) . "'";
|
||||
}
|
||||
if (count($arrSet) > 0) {
|
||||
$objDatabase->fxQuery(
|
||||
'UPDATE inscriptions_comptes SET ' . implode(', ', $arrSet)
|
||||
. ' WHERE com_id = ' . $intComId
|
||||
);
|
||||
}
|
||||
$strResetToken = fxEveAccesPromoteurRefreshResetToken($intComId);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
12
sql/MSIN-4478-eve-acces-invite-pending-reinvite.sql
Normal file
12
sql/MSIN-4478-eve-acces-invite-pending-reinvite.sql
Normal file
@ -0,0 +1,12 @@
|
||||
-- MSIN-4478 — Réinvitation stub non activé (libellé Info)
|
||||
-- Contexte : invite / réinvite promoteur — mail « créez votre mot de passe » si compte jamais activé
|
||||
-- Notes : exécution UNIQUEMENT sur dev préprod ; autres env = Navicat structure + sync_static_db
|
||||
-- Idempotent : DELETE + INSERT de la clé ajoutée
|
||||
|
||||
DELETE FROM info
|
||||
WHERE info_clef = 'eve_acces_promoteur_ok_pending'
|
||||
AND info_prg = 'compte.php';
|
||||
|
||||
INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) VALUES
|
||||
('eve_acces_promoteur_ok_pending', 'fr', 'Invitation mise à jour. Un courriel avec le lien de mot de passe a été envoyé.', '', 'compte.php', '', 0, 1, '', '', '', NOW()),
|
||||
('eve_acces_promoteur_ok_pending', 'en', 'Invitation updated. An email with the password link was sent.', '', 'compte.php', '', 0, 1, '', '', '', NOW());
|
||||
Reference in New Issue
Block a user