From fdbf9a32107318fe52f51733c8dc7e8bcda83fcc Mon Sep 17 00:00:00 2001 From: Ruben Date: Sun, 1 Feb 2026 20:27:34 +0100 Subject: [PATCH] Add manual signature confirmation by email address Add new menu option to manually confirm signatures by email address Search through all petition files to find matching emails Update status from pending to confirmed when found Display results with confirmation status and petition IDs Handle multiple emails via comma-separated input Maintain proper file locking to prevent race conditions --- custom/petition-cli.php | 154 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/custom/petition-cli.php b/custom/petition-cli.php index f409ca5..f49985a 100755 --- a/custom/petition-cli.php +++ b/custom/petition-cli.php @@ -407,7 +407,8 @@ function showMenu(): void { echo " 3) Send e-post pa nytt til mislykkede\n"; echo " 4) Send bekreftelse pa nytt til ubekreftede\n"; echo " 5) Marker oppforinger som ignorert\n"; - echo " 6) Avslutt\n"; + echo " 6) Manuell bekreftelse av signaturer\n"; + echo " 7) Avslutt\n"; echo "\n"; } @@ -642,6 +643,152 @@ function resendToUnconfirmed(): void { printColor("Ferdig: {$success} vellykket, {$failures} mislykket\n", $failures > 0 ? 'yellow' : 'green'); } +/** + * Manually confirm signatures by email address + */ +function manuallyConfirmSignatures(): void { + echo "\n"; + printColor("Manuell bekreftelse av signaturer\n", 'cyan'); + echo "\n"; + + $input = prompt("Skriv inn e-postadresse(r) (kommaseparert): "); + if (empty(trim($input))) { + echo "Ingen e-postadresser oppgitt.\n"; + return; + } + + // Parse and clean email addresses + $emails = array_map('trim', explode(',', $input)); + $emails = array_filter($emails, fn($e) => !empty($e)); + $emails = array_map('strtolower', $emails); + + if (empty($emails)) { + echo "Ingen gyldige e-postadresser oppgitt.\n"; + return; + } + + echo "\n"; + echo "Soker etter " . count($emails) . " e-postadresse(r)...\n\n"; + + $found = []; + $notFound = []; + + // Search through all petition files + foreach (getPetitionFiles() as $petitionId) { + $csvPath = PETITIONS_DIR . '/' . $petitionId . '.csv'; + if (!file_exists($csvPath)) { + continue; + } + + // Open with r+ to allow reading and writing, acquire exclusive lock immediately + // This matches the pattern used in petition-form.php to prevent race conditions + $fp = fopen($csvPath, 'r+'); + if (!$fp) { + printColor(" Advarsel: Kunne ikke apne {$petitionId}.csv\n", 'yellow'); + continue; + } + + if (!flock($fp, LOCK_EX)) { + fclose($fp); + printColor(" Advarsel: Kunne ikke lase {$petitionId}.csv\n", 'yellow'); + continue; + } + + // Read all rows while holding the lock + $rows = []; + $header = fgetcsv($fp, null, ',', '"', ''); + if ($header === false) { + // Empty file, skip + flock($fp, LOCK_UN); + fclose($fp); + continue; + } + + while (($row = fgetcsv($fp, null, ',', '"', '')) !== false) { + $rows[] = $row; + } + + $modified = false; + foreach ($rows as &$row) { + if (!isset($row[1]) || !isset($row[6])) { + continue; + } + + $rowEmail = strtolower($row[1]); + if (in_array($rowEmail, $emails)) { + if ($row[6] === 'pending') { + $row[6] = 'confirmed'; + $modified = true; + $found[] = [ + 'email' => $row[1], + 'name' => ($row[2] ?? '') . ' ' . ($row[3] ?? ''), + 'petition_id' => $petitionId, + 'was_pending' => true + ]; + } else { + $found[] = [ + 'email' => $row[1], + 'name' => ($row[2] ?? '') . ' ' . ($row[3] ?? ''), + 'petition_id' => $petitionId, + 'was_pending' => false, + 'status' => $row[6] + ]; + } + } + } + unset($row); + + // Write back if modified (still holding the lock) + if ($modified) { + rewind($fp); + ftruncate($fp, 0); + fputcsv($fp, $header, ',', '"', ''); + foreach ($rows as $row) { + fputcsv($fp, $row, ',', '"', ''); + } + } + + flock($fp, LOCK_UN); + fclose($fp); + } + + // Determine which emails were not found + $foundEmails = array_map(fn($f) => strtolower($f['email']), $found); + foreach ($emails as $email) { + if (!in_array($email, $foundEmails)) { + $notFound[] = $email; + } + } + + // Display results + if (!empty($found)) { + printColor("Funnet:\n", 'green'); + foreach ($found as $entry) { + $status = $entry['was_pending'] + ? "BEKREFTET" + : "allerede " . $entry['status']; + echo " - {$entry['email']} ({$entry['name']}) - {$entry['petition_id']}: "; + if ($entry['was_pending']) { + printColor("{$status}\n", 'green'); + } else { + printColor("{$status}\n", 'yellow'); + } + } + } + + if (!empty($notFound)) { + echo "\n"; + printColor("Ikke funnet:\n", 'red'); + foreach ($notFound as $email) { + echo " - {$email}\n"; + } + } + + $confirmedCount = count(array_filter($found, fn($f) => $f['was_pending'])); + echo "\n"; + printColor("Ferdig: {$confirmedCount} signatur(er) bekreftet\n", 'green'); +} + /** * Interactive ignore marking */ @@ -823,13 +970,16 @@ function main(): void { markAsIgnored(); break; case '6': + manuallyConfirmSignatures(); + break; + case '7': case 'q': case 'quit': case 'exit': echo "Ha det!\n"; exit(0); default: - printColor("Ugyldig valg. Velg 1-6.\n", 'red'); + printColor("Ugyldig valg. Velg 1-7.\n", 'red'); } } }