feat(G6): контроллер + роут GET /api/v1/deals (публичный read-API сделок)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Deal;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Публичный read-API сделок тенанта (G6). Аутентификация — middleware ApiKeyAuth
|
||||
* (tenant_id в request->attributes['api_tenant_id']). Только сделки (deals), не
|
||||
* supplier_leads.
|
||||
*/
|
||||
class DealsController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$tenantId = (int) $request->attributes->get('api_tenant_id');
|
||||
|
||||
$limit = max(1, min(500, (int) $request->query('limit', '100')));
|
||||
|
||||
$since = trim((string) $request->query('since', ''));
|
||||
$sinceDt = null;
|
||||
if ($since !== '') {
|
||||
try {
|
||||
$sinceDt = Carbon::parse($since);
|
||||
} catch (\Throwable) {
|
||||
return response()->json(['message' => 'Невалидный since.'], 422);
|
||||
}
|
||||
}
|
||||
|
||||
$cursorRaw = (string) $request->query('cursor', '');
|
||||
$cursor = null;
|
||||
if ($cursorRaw !== '') {
|
||||
$decoded = base64_decode($cursorRaw, true);
|
||||
$parsed = $decoded === false ? null : json_decode($decoded, true);
|
||||
if (! is_array($parsed) || ! isset($parsed['r'], $parsed['i'])) {
|
||||
return response()->json(['message' => 'Невалидный cursor.'], 422);
|
||||
}
|
||||
$cursor = ['r' => (string) $parsed['r'], 'i' => (int) $parsed['i']];
|
||||
}
|
||||
|
||||
[$rows, $next] = DB::transaction(function () use ($tenantId, $limit, $sinceDt, $cursor) {
|
||||
DB::statement('SET LOCAL app.current_tenant_id = '.$tenantId);
|
||||
|
||||
$query = Deal::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->with('project:id,name');
|
||||
|
||||
if ($sinceDt !== null) {
|
||||
$query->where('received_at', '>=', $sinceDt);
|
||||
}
|
||||
if ($cursor !== null) {
|
||||
$query->whereRaw('(received_at, id) < (?, ?)', [$cursor['r'], $cursor['i']]);
|
||||
}
|
||||
|
||||
$rows = $query->orderByDesc('received_at')->orderByDesc('id')
|
||||
->limit($limit + 1)->get();
|
||||
|
||||
$hasNext = $rows->count() > $limit;
|
||||
if ($hasNext) {
|
||||
$rows = $rows->slice(0, $limit)->values();
|
||||
}
|
||||
|
||||
$next = null;
|
||||
if ($hasNext && $rows->isNotEmpty()) {
|
||||
$last = $rows->last();
|
||||
$next = base64_encode((string) json_encode([
|
||||
'r' => $last->received_at?->toIso8601String(),
|
||||
'i' => $last->id,
|
||||
]));
|
||||
}
|
||||
|
||||
return [$rows, $next];
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'data' => $rows->map(fn (Deal $d) => [
|
||||
'id' => $d->id,
|
||||
'received_at' => $d->received_at?->toIso8601String(),
|
||||
'phone' => $d->phone,
|
||||
'contact_name' => $d->contact_name,
|
||||
'city' => $d->city,
|
||||
'status' => $d->status,
|
||||
'project' => $d->project?->name,
|
||||
])->all(),
|
||||
'next_cursor' => $next,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -220,6 +220,11 @@ Route::middleware(['auth:sanctum', 'tenant'])->prefix('/api/api-keys')->group(fu
|
||||
Route::post('/regenerate', 'App\Http\Controllers\Api\ApiKeyController@regenerate');
|
||||
});
|
||||
|
||||
// G6: публичный read-API сделок по API-ключу (middleware apikey — без sanctum/tenant).
|
||||
Route::middleware('apikey')->prefix('/api/v1')->group(function () {
|
||||
Route::get('/deals', 'App\Http\Controllers\Api\V1\DealsController@index')->name('api.v1.deals.index');
|
||||
});
|
||||
|
||||
// Настройки исходящего webhook'а тенанта (audit D4/D5/J5).
|
||||
Route::middleware(['auth:sanctum', 'tenant'])->group(function () {
|
||||
Route::get('/api/tenants/me/webhook-settings', 'App\Http\Controllers\Api\WebhookSettingsController@show');
|
||||
|
||||
Reference in New Issue
Block a user