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'); } } }