- Implemented the full Fat Bottom Grille storefront and staff dashboard.
Highlights include configurable menus, specials, cart/checkout, taxes, customer accounts with email 2FA, newsletters, analytics, refunds, PDF/CSV exports, Square/Mailgun adapters, and optional MySQL migration. See README.md for setup and production configuration. Verified PHP/JavaScript syntax, responsive layouts, registration, 2FA, checkout, dashboard workflows, settings persistence, and PDF generation. Real Square, Mailgun, and MySQL connections require credentials/server access. Square implementation follows the official Payments API and Refunds API.
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FatBottom\Services;
|
||||
|
||||
use FatBottom\Core\Config;
|
||||
use FatBottom\Core\Database;
|
||||
|
||||
final class TwoFactorService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Database $db,
|
||||
private readonly Mailer $mailer,
|
||||
private readonly Config $config
|
||||
) {
|
||||
}
|
||||
|
||||
public function issue(array $user, string $purpose = 'login'): ?string
|
||||
{
|
||||
$code = (string) random_int(100000, 999999);
|
||||
$expiresAt = gmdate('Y-m-d H:i:s', time() + 600);
|
||||
|
||||
$this->db->execute(
|
||||
'INSERT INTO login_codes (user_id, code_hash, purpose, expires_at) VALUES (?, ?, ?, ?)',
|
||||
[(int) $user['id'], password_hash($code, PASSWORD_DEFAULT), $purpose, $expiresAt]
|
||||
);
|
||||
|
||||
$name = htmlspecialchars((string) $user['full_name'], ENT_QUOTES, 'UTF-8');
|
||||
$this->mailer->send(
|
||||
(string) $user['email'],
|
||||
'Your Fat Bottom Grille verification code',
|
||||
"<p>Hi {$name},</p><p>Your verification code is <strong>{$code}</strong>.</p><p>It expires in 10 minutes.</p>"
|
||||
);
|
||||
|
||||
return (bool) $this->config->get('mailgun.enabled', false) ? null : $code;
|
||||
}
|
||||
|
||||
public function verify(int $userId, string $code, string $purpose = 'login'): bool
|
||||
{
|
||||
$record = $this->db->fetch(
|
||||
'SELECT * FROM login_codes
|
||||
WHERE user_id = ? AND purpose = ? AND used_at IS NULL AND expires_at > CURRENT_TIMESTAMP
|
||||
ORDER BY id DESC LIMIT 1',
|
||||
[$userId, $purpose]
|
||||
);
|
||||
if ($record === null || !password_verify($code, (string) $record['code_hash'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->db->execute('UPDATE login_codes SET used_at = CURRENT_TIMESTAMP WHERE id = ?', [(int) $record['id']]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user