You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
2.6 KiB

4 days ago
<?php
namespace App\Support;
use App\Models\Venue;
use App\Models\VerifyPortalCredential;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
/** 抢票核销:场馆维度 6 位口令(与活动共用同一核销入口页);凭证 kind = ticket_grab_venue */
final class VenueVerifyPortalPin
{
public const CRED_USERNAME = '__tg_pin__';
public static function syncPinCredential(Venue $venue): VerifyPortalCredential
{
$pin = trim((string) ($venue->verify_portal_pin ?? ''));
if ($pin === '' || ! preg_match('/^\d{6}$/', $pin)) {
throw new \InvalidArgumentException('场馆抢票核销口令无效');
}
$vid = (int) $venue->id;
/** @var VerifyPortalCredential|null $cred */
$cred = VerifyPortalCredential::query()
->where('portal_kind', VerifyPortalCredential::KIND_TICKET_GRAB_VENUE)
->where('portal_id', $vid)
->where('username', self::CRED_USERNAME)
->first();
$attributes = [
'venue_id' => $vid,
'password' => Hash::make($pin),
'password_plain_enc' => Crypt::encryptString($pin),
'note' => null,
];
if ($cred !== null) {
$cred->forceFill($attributes)->save();
return $cred;
}
return VerifyPortalCredential::query()->create(array_merge([
'portal_kind' => VerifyPortalCredential::KIND_TICKET_GRAB_VENUE,
'portal_id' => $vid,
'username' => self::CRED_USERNAME,
], $attributes));
}
public static function ensure(Venue $venue): string
{
$venue->refresh();
$pinOut = trim((string) ($venue->verify_portal_pin ?? ''));
if ($pinOut !== '' && preg_match('/^\d{6}$/', $pinOut)) {
self::syncPinCredential($venue);
return $pinOut;
}
DB::transaction(function () use ($venue): void {
$fresh = Venue::query()->whereKey($venue->id)->lockForUpdate()->first();
if ($fresh === null) {
return;
}
$p = trim((string) ($fresh->verify_portal_pin ?? ''));
if ($p !== '' && preg_match('/^\d{6}$/', $p)) {
return;
}
$fresh->forceFill(['verify_portal_pin' => PortalSixDigitPin::generateUnique()])->saveQuietly();
});
$venue->refresh();
$pinOut = trim((string) ($venue->verify_portal_pin ?? ''));
self::syncPinCredential($venue);
return $pinOut;
}
}