feat: log section

This commit is contained in:
2026-08-19 12:10:13 +03:30
parent 315b3170c8
commit 2123adef2b
5 changed files with 370 additions and 4 deletions
+90
View File
@@ -0,0 +1,90 @@
<?php
namespace App\Models;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
/**
* One row per authentication event. Used by the admin panel to count how many
* users request/verify OTPs (i.e. how many verification SMS are billed) and how
* many log in through each method.
*/
class AuthLog extends Model
{
protected $guarded = [];
protected $casts = [
'success' => 'boolean',
'sms_sent' => 'boolean',
'source' => 'integer',
];
// Login OTP requested — an SMS was queued (unless the admin shortcut mobile)
public const EVENT_OTP_SENT = 'otp_sent';
// Login OTP checked successfully — the user is now logged in
public const EVENT_OTP_VERIFIED = 'otp_verified';
// Login OTP checked with a wrong/expired token
public const EVENT_OTP_FAILED = 'otp_failed';
// In-app mobile verification OTP requested — also a billed SMS
public const EVENT_MOBILE_OTP_SENT = 'mobile_otp_sent';
public const EVENT_MOBILE_VERIFIED = 'mobile_verified';
public const EVENT_MOBILE_VERIFY_FAILED = 'mobile_verify_failed';
// Password login
public const EVENT_LOGIN = 'login';
public const EVENT_LOGIN_FAILED = 'login_failed';
public const EVENT_REGISTER = 'register';
public const EVENT_GOOGLE_LOGIN = 'google_login';
public const EVENTS = [
self::EVENT_OTP_SENT,
self::EVENT_OTP_VERIFIED,
self::EVENT_OTP_FAILED,
self::EVENT_MOBILE_OTP_SENT,
self::EVENT_MOBILE_VERIFIED,
self::EVENT_MOBILE_VERIFY_FAILED,
self::EVENT_LOGIN,
self::EVENT_LOGIN_FAILED,
self::EVENT_REGISTER,
self::EVENT_GOOGLE_LOGIN,
];
// Events that cost an outgoing verification SMS
public const SMS_EVENTS = [
self::EVENT_OTP_SENT,
self::EVENT_MOBILE_OTP_SENT,
];
/**
* Record an event. Never lets a logging failure break the auth flow.
*/
public static function record(string $event, array $attributes = [], ?Request $request = null): ?self
{
try {
$request ??= request();
return static::create(array_merge([
'event' => $event,
'success' => !str_ends_with($event, '_failed'),
'sms_sent' => in_array($event, self::SMS_EVENTS, true),
'ip' => $request?->ip(),
'user_agent' => substr((string) $request?->userAgent(), 0, 255) ?: null,
], $attributes));
} catch (\Throwable $e) {
logger()->warning('auth log failed', ['event' => $event, 'error' => $e->getMessage()]);
return null;
}
}
public function user()
{
return $this->belongsTo(User::class);
}
protected function serializeDate(DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
}