188 lines
6.2 KiB
PHP
188 lines
6.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Tenant;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Tenant\EmotionStoreRequest;
|
|
use App\Http\Requests\Tenant\EmotionUpdateRequest;
|
|
use App\Http\Resources\Tenant\EmotionResource;
|
|
use App\Models\Emotion;
|
|
use App\Models\Tenant;
|
|
use App\Support\TenantRequestResolver;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class EmotionController extends Controller
|
|
{
|
|
public function index(Request $request): AnonymousResourceCollection
|
|
{
|
|
$tenantId = $this->currentTenant($request)->id;
|
|
|
|
$query = Emotion::query()
|
|
->when(true, function ($builder) use ($tenantId) {
|
|
// Prefer tenant-specific and global emotions if the column exists
|
|
if (Schema::hasColumn('emotions', 'tenant_id')) {
|
|
$builder->where(function ($inner) use ($tenantId) {
|
|
$inner->whereNull('tenant_id')
|
|
->orWhere('tenant_id', $tenantId);
|
|
});
|
|
}
|
|
})
|
|
->with('eventTypes');
|
|
|
|
if ($request->boolean('only_tenant')) {
|
|
$query->where('tenant_id', $tenantId);
|
|
}
|
|
|
|
if ($request->boolean('only_global')) {
|
|
$query->whereNull('tenant_id');
|
|
}
|
|
|
|
$query->orderByRaw('tenant_id is null desc')->orderBy('sort_order')->orderBy('id');
|
|
|
|
$emotions = $query->paginate($request->integer('per_page', 50));
|
|
|
|
if ($emotions->isEmpty() && ! $request->boolean('only_tenant')) {
|
|
// Fallback: return any emotions regardless of tenant to avoid empty selectors
|
|
$fallback = Emotion::query()
|
|
->with('eventTypes')
|
|
->orderBy('sort_order')
|
|
->orderBy('id')
|
|
->paginate($request->integer('per_page', 50));
|
|
|
|
return EmotionResource::collection($fallback);
|
|
}
|
|
|
|
return EmotionResource::collection($emotions);
|
|
}
|
|
|
|
public function store(EmotionStoreRequest $request): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
$tenantId = $this->currentTenant($request)->id;
|
|
|
|
$payload = [
|
|
'tenant_id' => $tenantId,
|
|
'name' => $this->localizeValue($data['name']),
|
|
'description' => $this->localizeValue($data['description'] ?? null, allowNull: true),
|
|
'icon' => $data['icon'] ?? 'lucide-smile',
|
|
'color' => $this->normalizeColor($data['color'] ?? '#6366f1'),
|
|
'sort_order' => $data['sort_order'] ?? 0,
|
|
'is_active' => $data['is_active'] ?? true,
|
|
];
|
|
|
|
$emotion = null;
|
|
|
|
DB::transaction(function () use (&$emotion, $payload, $data) {
|
|
$emotion = Emotion::create($payload);
|
|
|
|
if (! empty($data['event_type_ids'])) {
|
|
$emotion->eventTypes()->sync($data['event_type_ids']);
|
|
}
|
|
});
|
|
|
|
return response()->json([
|
|
'message' => __('Emotion erfolgreich erstellt.'),
|
|
'data' => new EmotionResource($emotion->fresh('eventTypes')),
|
|
], 201);
|
|
}
|
|
|
|
public function update(EmotionUpdateRequest $request, Emotion $emotion): JsonResponse
|
|
{
|
|
$tenantId = $this->currentTenant($request)->id;
|
|
|
|
if ($emotion->tenant_id && $emotion->tenant_id !== $tenantId) {
|
|
abort(403, 'Emotion gehört nicht zu diesem Tenant.');
|
|
}
|
|
|
|
if (is_null($emotion->tenant_id) && $request->hasAny(['name', 'description', 'icon', 'color', 'sort_order'])) {
|
|
abort(403, 'Globale Emotions können nicht bearbeitet werden.');
|
|
}
|
|
|
|
$data = $request->validated();
|
|
|
|
DB::transaction(function () use ($emotion, $data) {
|
|
$update = [];
|
|
|
|
if (array_key_exists('name', $data)) {
|
|
$update['name'] = $this->localizeValue($data['name'], allowNull: false, fallback: $emotion->name);
|
|
}
|
|
|
|
if (array_key_exists('description', $data)) {
|
|
$update['description'] = $this->localizeValue($data['description'], allowNull: true, fallback: $emotion->description);
|
|
}
|
|
|
|
if (array_key_exists('icon', $data)) {
|
|
$update['icon'] = $data['icon'] ?? $emotion->icon;
|
|
}
|
|
|
|
if (array_key_exists('color', $data)) {
|
|
$update['color'] = $this->normalizeColor($data['color'] ?? $emotion->color);
|
|
}
|
|
|
|
if (array_key_exists('sort_order', $data)) {
|
|
$update['sort_order'] = $data['sort_order'] ?? 0;
|
|
}
|
|
|
|
if (array_key_exists('is_active', $data)) {
|
|
$update['is_active'] = $data['is_active'];
|
|
}
|
|
|
|
if (! empty($update)) {
|
|
$emotion->update($update);
|
|
}
|
|
|
|
if (array_key_exists('event_type_ids', $data)) {
|
|
$emotion->eventTypes()->sync($data['event_type_ids'] ?? []);
|
|
}
|
|
});
|
|
|
|
return response()->json([
|
|
'message' => __('Emotion aktualisiert.'),
|
|
'data' => new EmotionResource($emotion->fresh('eventTypes')),
|
|
]);
|
|
}
|
|
|
|
protected function localizeValue(mixed $value, bool $allowNull = false, ?array $fallback = null): ?array
|
|
{
|
|
if ($allowNull && ($value === null || $value === '')) {
|
|
return null;
|
|
}
|
|
|
|
if (is_array($value)) {
|
|
$filtered = array_filter($value, static fn ($text) => is_string($text) && $text !== '');
|
|
if (! empty($filtered)) {
|
|
return $filtered;
|
|
}
|
|
|
|
return $allowNull ? null : ($fallback ?? []);
|
|
}
|
|
|
|
if (is_string($value) && $value !== '') {
|
|
$locale = app()->getLocale() ?: 'de';
|
|
|
|
return [$locale => $value];
|
|
}
|
|
|
|
return $allowNull ? null : $fallback;
|
|
}
|
|
|
|
protected function normalizeColor(string $color): string
|
|
{
|
|
$normalized = ltrim($color, '#');
|
|
if (strlen($normalized) === 6) {
|
|
return '#'.strtolower($normalized);
|
|
}
|
|
|
|
return '#6366f1';
|
|
}
|
|
|
|
protected function currentTenant(Request $request): Tenant
|
|
{
|
|
return TenantRequestResolver::resolve($request);
|
|
}
|
|
}
|