Initial commit of the complete City10 virtual city simulation platform. Backend (Laravel 13): - REST API with Sanctum tokens and session-based web authentication - Role-based access control (admin/user) with middleware protection - AI agent CRUD with OpenRouter.ai integration restricted to free models - Store management with 3D coordinates and AI shopkeeper assignment - Versioned legal documents (Terms, Privacy, Cookies) with LGPD audit trail - Math CAPTCHA on public forms and multi-language support (pt_BR, en, es) Frontend: - Responsive Blade templates with Tailwind CSS v4 - Three.js 3D city viewer with SSE chat streaming to AI agents - Admin panel for store and user administration Infrastructure: - MariaDB/MySQL database with comprehensive migrations - Database seeders for demo content and test accounts - PHPUnit test suite and Laravel Pint code styling - Vite build configuration with hot reload
113 lines
3.4 KiB
PHP
Executable File
113 lines
3.4 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\StoreRequest as StoreFormRequest;
|
|
use App\Models\Store;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
|
|
/**
|
|
* Store management endpoints.
|
|
*
|
|
* Regular users may list stores and manage the ones they own; admins may
|
|
* manage the entire registry. Coordinates follow the 3D city grid.
|
|
*/
|
|
class StoreController extends Controller
|
|
{
|
|
/**
|
|
* Paginated listing of stores with geographic filtering.
|
|
*/
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$query = Store::query()->with(['owner:id,name', 'agent:id,name,status'])->orderBy('name');
|
|
|
|
if ($search = $request->query('search')) {
|
|
$query->where('name', 'like', "%{$search}%");
|
|
}
|
|
|
|
if ($type = $request->query('type')) {
|
|
$query->where('type', $type);
|
|
}
|
|
|
|
if ($request->boolean('only_open')) {
|
|
$query->where('is_open', true);
|
|
}
|
|
|
|
return response()->json($query->paginate((int) $request->query('per_page', 15)));
|
|
}
|
|
|
|
/**
|
|
* Return a compact snapshot of all stores for the 3D renderer.
|
|
*/
|
|
public function world(): JsonResponse
|
|
{
|
|
$stores = Store::query()
|
|
->get(['id', 'name', 'type', 'pos_x', 'pos_y', 'pos_z', 'width', 'height', 'depth', 'is_open'])
|
|
->map(fn (Store $store): array => [
|
|
'id' => $store->id,
|
|
'name' => $store->name,
|
|
'type' => $store->type,
|
|
'position' => [(float) $store->pos_x, (float) $store->pos_y, (float) $store->pos_z],
|
|
'size' => [(float) $store->width, (float) $store->height, (float) $store->depth],
|
|
'is_open' => $store->is_open,
|
|
]);
|
|
|
|
return response()->json(['stores' => $stores]);
|
|
}
|
|
|
|
/**
|
|
* Persist a new store.
|
|
*/
|
|
public function store(StoreFormRequest $request): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
|
|
// Regular users always own the stores they create.
|
|
if (! $request->user()->isAdmin()) {
|
|
$data['owner_id'] = $request->user()->id;
|
|
}
|
|
|
|
$store = Store::create($data);
|
|
|
|
return response()->json($store->load(['owner:id,name', 'agent:id,name']), 201);
|
|
}
|
|
|
|
/**
|
|
* Return a single store.
|
|
*/
|
|
public function show(Store $store): JsonResponse
|
|
{
|
|
return response()->json($store->load(['owner:id,name,email', 'agent:id,name,type,status']));
|
|
}
|
|
|
|
/**
|
|
* Update a store (owner or admin only).
|
|
*/
|
|
public function update(StoreFormRequest $request, Store $store): JsonResponse
|
|
{
|
|
if (! $request->user()->isAdmin() && $store->owner_id !== $request->user()->id) {
|
|
return response()->json(['message' => __('auth.forbidden')], 403);
|
|
}
|
|
|
|
$store->update($request->validated());
|
|
|
|
return response()->json($store->fresh()->load(['owner:id,name', 'agent:id,name']));
|
|
}
|
|
|
|
/**
|
|
* Delete a store (owner or admin only).
|
|
*/
|
|
public function destroy(Request $request, Store $store): JsonResponse
|
|
{
|
|
if (! $request->user()->isAdmin() && $store->owner_id !== $request->user()->id) {
|
|
return response()->json(['message' => __('auth.forbidden')], 403);
|
|
}
|
|
|
|
$store->delete();
|
|
|
|
return response()->json(['message' => __('stores.deleted')]);
|
|
}
|
|
}
|