Proje dosyaları eklendi
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\EarnApiToken;
|
||||
use App\Models\EarnTaskAssignment;
|
||||
use App\Models\EarnTaskResult;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class EarnTaskResultService
|
||||
{
|
||||
/**
|
||||
* Sonuç işleme olaylarını mevcut güvenli Earn access logger ile kaydeder.
|
||||
*
|
||||
* @author Gökhan Engin - İletişim : https://bit.ly/YazılımUzmanı
|
||||
*/
|
||||
public function __construct(private readonly EarnApiAccessLogger $logs) {}
|
||||
|
||||
/**
|
||||
* Doğrulanmış token ve cihazdan gelen sonuçları sunucudaki atamaya göre idempotent kaydeder.
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $items Doğrulanmış görev sonucu nesneleri.
|
||||
* @return array{received: int, accepted: int, rejected: int, results: array<int, array<string, mixed>>}
|
||||
*
|
||||
* @author Gökhan Engin - İletişim : https://bit.ly/YazılımUzmanı
|
||||
*/
|
||||
public function store(Request $request, array $items): array
|
||||
{
|
||||
/**
|
||||
* @var EarnApiToken $token Middleware tarafından doğrulanmış API anahtarı kaydı.
|
||||
*
|
||||
* @author Gökhan Engin - İletişim : https://bit.ly/YazılımUzmanı
|
||||
*/
|
||||
$token = $request->attributes->get('earn_api_token');
|
||||
$deviceHash = (string) $request->attributes->get('earn_device_hash');
|
||||
$results = [];
|
||||
$accepted = 0;
|
||||
|
||||
foreach ($items as $item) {
|
||||
// Atama doğrulaması ile ilk sonuç kaydını aynı kilitli işlemde tutar.
|
||||
// Yazar: Gökhan Engin - İletişim : https://bit.ly/YazılımUzmanı
|
||||
$outcome = DB::transaction(function () use ($item, $token, $deviceHash): array {
|
||||
$assignment = EarnTaskAssignment::query()->where('task_id', $item['task_id'])->lockForUpdate()->first();
|
||||
if (! $assignment instanceof EarnTaskAssignment
|
||||
|| $assignment->personal_access_token_id !== $token->id
|
||||
|| ! hash_equals($assignment->device_id_hash, $deviceHash)) {
|
||||
return ['accepted' => false, 'code' => 'TASK_NOT_ASSIGNED'];
|
||||
}
|
||||
if ($assignment->user_id !== $item['CID']) {
|
||||
return ['accepted' => false, 'code' => 'CID_MISMATCH'];
|
||||
}
|
||||
|
||||
$existing = EarnTaskResult::query()->where('earn_task_assignment_id', $assignment->id)->first();
|
||||
if ($existing instanceof EarnTaskResult) {
|
||||
return ['accepted' => true, 'code' => 'ALREADY_RECORDED', 'duplicate' => true];
|
||||
}
|
||||
|
||||
EarnTaskResult::query()->create([
|
||||
'earn_task_assignment_id' => $assignment->id, 'user_id' => $assignment->user_id,
|
||||
'earn_member_id' => $token->tokenable_id, 'personal_access_token_id' => $token->id,
|
||||
'device_id_hash' => $deviceHash, 'completed' => $item['completed'],
|
||||
'response_code' => $item['responseCode'], 'error_message' => $item['error'],
|
||||
'submitted_at' => now(),
|
||||
]);
|
||||
|
||||
return ['accepted' => true, 'code' => null];
|
||||
}, 3);
|
||||
|
||||
$results[] = ['task_id' => $item['task_id'], 'accepted' => $outcome['accepted'], 'code' => $outcome['code']];
|
||||
if ($outcome['accepted']) {
|
||||
$accepted++;
|
||||
}
|
||||
$event = match ($outcome['code']) {
|
||||
'ALREADY_RECORDED' => 'task_result_duplicate',
|
||||
'CID_MISMATCH' => 'task_result_cid_mismatch',
|
||||
'TASK_NOT_ASSIGNED' => 'task_result_not_assigned',
|
||||
default => 'task_result_accepted',
|
||||
};
|
||||
$this->logs->record($request, $event, $outcome['accepted'] ? 200 : 422, $outcome['code']);
|
||||
if (! $outcome['accepted']) {
|
||||
$this->logs->record($request, 'task_result_rejected', 422, $outcome['code']);
|
||||
}
|
||||
}
|
||||
|
||||
return ['received' => count($items), 'accepted' => $accepted,
|
||||
'rejected' => count($items) - $accepted, 'results' => $results];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user