prepare('SELECT id FROM tenants WHERE slug = ?'); $stmt->execute([$slug]); $tenantId = $stmt->fetchColumn(); if ($tenantId !== false) { $tenantId = (int)$tenantId; $pdo->prepare('DELETE FROM participants WHERE tenant_id = ?')->execute([$tenantId]); $pdo->prepare('DELETE FROM tenant_memberships WHERE tenant_id = ?')->execute([$tenantId]); $pdo->prepare('DELETE FROM tenant_settings WHERE tenant_id = ?')->execute([$tenantId]); $pdo->prepare('DELETE FROM tenants WHERE id = ?')->execute([$tenantId]); } $pdo->prepare('DELETE FROM users WHERE email_norm = ?')->execute([$emailNorm]); } $pdo = dev_pdo(); dev_apply_schema($pdo); $slug = 'm3-password-email-check'; $email = 'm3-password-email-check@test.local'; $emailNorm = saas_email_norm($email); $password = 'M3-password-email-123'; $newPassword = 'M3-password-email-456'; $failures = []; $passes = 0; password_email_check_cleanup($pdo, $slug, $emailNorm); $registration = saas_register_tenant_owner($pdo, [ 'tenant_name' => 'M3 Password Email Check', 'tenant_slug' => $slug, 'display_name' => 'M3 Password Email', 'email' => $email, 'password' => $password, 'password_confirm' => $password, ]); password_email_check_assert('registration succeeds', $registration['ok'] === true, $failures, $passes); password_email_check_assert('registration returns verification token', !empty($registration['email_verification_token']), $failures, $passes); if ($registration['ok']) { $userId = (int)$registration['identity']['user_id']; $stmt = $pdo->prepare('SELECT email_verified_at FROM users WHERE id = ?'); $stmt->execute([$userId]); password_email_check_assert('email starts unverified', $stmt->fetchColumn() === null, $failures, $passes); $verification = saas_verify_email_token($pdo, (string)$registration['email_verification_token']); password_email_check_assert('email verification succeeds', $verification['ok'] === true, $failures, $passes); $stmt = $pdo->prepare('SELECT email_verified_at FROM users WHERE id = ?'); $stmt->execute([$userId]); password_email_check_assert('email is verified', $stmt->fetchColumn() !== null, $failures, $passes); $verificationAgain = saas_verify_email_token($pdo, (string)$registration['email_verification_token']); password_email_check_assert('email verification token is single use', $verificationAgain['ok'] === false, $failures, $passes); $resetRequest = saas_request_password_reset($pdo, $email, $slug); password_email_check_assert('password reset request succeeds', $resetRequest['ok'] === true, $failures, $passes); password_email_check_assert('password reset returns token', !empty($resetRequest['token']), $failures, $passes); $reset = saas_reset_password_with_token( $pdo, (string)$resetRequest['token'], $newPassword, $newPassword ); password_email_check_assert('password reset succeeds', $reset['ok'] === true, $failures, $passes); $oldLogin = saas_authenticate($pdo, $email, $password, $slug); password_email_check_assert('old password is rejected', $oldLogin['ok'] === false, $failures, $passes); $newLogin = saas_authenticate($pdo, $email, $newPassword, $slug); password_email_check_assert('new password works', $newLogin['ok'] === true, $failures, $passes); $reuse = saas_reset_password_with_token( $pdo, (string)$resetRequest['token'], 'M3-password-email-789', 'M3-password-email-789' ); password_email_check_assert('password reset token is single use', $reuse['ok'] === false, $failures, $passes); } $unknownRequest = saas_request_password_reset($pdo, 'unknown-password-email@test.local', $slug); password_email_check_assert('unknown reset request is generic success', $unknownRequest['ok'] === true, $failures, $passes); password_email_check_assert('unknown reset request has no token', empty($unknownRequest['token']), $failures, $passes); password_email_check_cleanup($pdo, $slug, $emailNorm); if ($failures !== []) { echo "\nM3 password/email flow check failed with " . count($failures) . " failure(s):\n"; foreach ($failures as $failure) { echo "- {$failure}\n"; } exit(1); } echo "\nM3 password/email flow check passed with {$passes} assertions.\n";