Limit-Status im Upload-Flow anzeigen (Warnbanner + Sperrzustände).
Upload-Fehlercodes auswerten und freundliche Dialoge zeigen.
This commit is contained in:
@@ -13,6 +13,7 @@ use App\Models\Package;
|
||||
use App\Models\Photo;
|
||||
use App\Models\Tenant;
|
||||
use App\Services\EventJoinTokenService;
|
||||
use App\Support\ApiError;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
@@ -204,7 +205,13 @@ class EventController extends Controller
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
if ($event->tenant_id !== $tenantId) {
|
||||
return response()->json(['error' => 'Event not found'], 404);
|
||||
return ApiError::response(
|
||||
'event_not_found',
|
||||
'Event not accessible',
|
||||
'Das Event konnte nicht gefunden werden.',
|
||||
404,
|
||||
['event_slug' => $event->slug ?? null]
|
||||
);
|
||||
}
|
||||
|
||||
$event->load([
|
||||
@@ -228,7 +235,13 @@ class EventController extends Controller
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
if ($event->tenant_id !== $tenantId) {
|
||||
return response()->json(['error' => 'Event not found'], 404);
|
||||
return ApiError::response(
|
||||
'event_not_found',
|
||||
'Event not accessible',
|
||||
'Das Event konnte nicht gefunden werden.',
|
||||
404,
|
||||
['event_slug' => $event->slug ?? null]
|
||||
);
|
||||
}
|
||||
|
||||
$validated = $request->validated();
|
||||
@@ -264,7 +277,13 @@ class EventController extends Controller
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
if ($event->tenant_id !== $tenantId) {
|
||||
return response()->json(['error' => 'Event not found'], 404);
|
||||
return ApiError::response(
|
||||
'event_not_found',
|
||||
'Event not accessible',
|
||||
'Das Event konnte nicht gefunden werden.',
|
||||
404,
|
||||
['event_slug' => $event->slug ?? null]
|
||||
);
|
||||
}
|
||||
|
||||
$event->delete();
|
||||
@@ -279,7 +298,13 @@ class EventController extends Controller
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
if ($event->tenant_id !== $tenantId) {
|
||||
return response()->json(['error' => 'Event not found'], 404);
|
||||
return ApiError::response(
|
||||
'event_not_found',
|
||||
'Event not accessible',
|
||||
'Das Event konnte nicht gefunden werden.',
|
||||
404,
|
||||
['event_slug' => $event->slug ?? null]
|
||||
);
|
||||
}
|
||||
|
||||
$totalPhotos = Photo::where('event_id', $event->id)->count();
|
||||
@@ -304,7 +329,13 @@ class EventController extends Controller
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
if ($event->tenant_id !== $tenantId) {
|
||||
return response()->json(['error' => 'Event not found'], 404);
|
||||
return ApiError::response(
|
||||
'event_not_found',
|
||||
'Event not accessible',
|
||||
'Das Event konnte nicht gefunden werden.',
|
||||
404,
|
||||
['event_slug' => $event->slug ?? null]
|
||||
);
|
||||
}
|
||||
|
||||
$event->load(['eventType', 'eventPackage.package']);
|
||||
@@ -439,7 +470,13 @@ class EventController extends Controller
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
if ($event->tenant_id !== $tenantId) {
|
||||
return response()->json(['error' => 'Event not found'], 404);
|
||||
return ApiError::response(
|
||||
'event_not_found',
|
||||
'Event not accessible',
|
||||
'Das Event konnte nicht gefunden werden.',
|
||||
404,
|
||||
['event_slug' => $event->slug ?? null]
|
||||
);
|
||||
}
|
||||
|
||||
$activate = ! (bool) $event->is_active;
|
||||
@@ -466,7 +503,13 @@ class EventController extends Controller
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
|
||||
if ($event->tenant_id !== $tenantId) {
|
||||
return response()->json(['error' => 'Event not found'], 404);
|
||||
return ApiError::response(
|
||||
'event_not_found',
|
||||
'Event not accessible',
|
||||
'Das Event konnte nicht gefunden werden.',
|
||||
404,
|
||||
['event_slug' => $event->slug ?? null]
|
||||
);
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
|
||||
@@ -22,6 +22,7 @@ use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class PhotoController extends Controller
|
||||
{
|
||||
@@ -46,27 +47,16 @@ class PhotoController extends Controller
|
||||
->where('tenant_id', $tenantId)
|
||||
->firstOrFail();
|
||||
|
||||
$event->loadMissing(['tenant', 'eventPackage.package', 'eventPackages.package']);
|
||||
$tenant = $event->tenant;
|
||||
|
||||
if ($tenant) {
|
||||
$violation = $this->packageLimitEvaluator->assessPhotoUpload($tenant, $event->id, $event);
|
||||
|
||||
if ($violation !== null) {
|
||||
return ApiError::response(
|
||||
$violation['code'],
|
||||
$violation['title'],
|
||||
$violation['message'],
|
||||
$violation['status'],
|
||||
$violation['meta']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$eventPackage = $tenant
|
||||
? $this->packageLimitEvaluator->resolveEventPackageForPhotoUpload($tenant, $event->id, $event)
|
||||
: null;
|
||||
|
||||
$previousUsedPhotos = $eventPackage?->used_photos ?? 0;
|
||||
$limitSummary = $eventPackage
|
||||
? $this->packageLimitEvaluator->summarizeEventPackage($eventPackage)
|
||||
: null;
|
||||
|
||||
$query = Photo::where('event_id', $event->id)
|
||||
->with('event')->withCount('likes')
|
||||
@@ -84,7 +74,9 @@ class PhotoController extends Controller
|
||||
$perPage = $request->get('per_page', 20);
|
||||
$photos = $query->paginate($perPage);
|
||||
|
||||
return PhotoResource::collection($photos);
|
||||
return PhotoResource::collection($photos)->additional([
|
||||
'limits' => $limitSummary,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,6 +89,29 @@ class PhotoController extends Controller
|
||||
->where('tenant_id', $tenantId)
|
||||
->firstOrFail();
|
||||
|
||||
$event->loadMissing(['tenant', 'eventPackage.package', 'eventPackages.package']);
|
||||
$tenant = $event->tenant;
|
||||
|
||||
$eventPackage = $tenant
|
||||
? $this->packageLimitEvaluator->resolveEventPackageForPhotoUpload($tenant, $event->id, $event)
|
||||
: null;
|
||||
|
||||
if ($tenant) {
|
||||
$violation = $this->packageLimitEvaluator->assessPhotoUpload($tenant, $event->id, $event);
|
||||
|
||||
if ($violation !== null) {
|
||||
return ApiError::response(
|
||||
$violation['code'],
|
||||
$violation['title'],
|
||||
$violation['message'],
|
||||
$violation['status'],
|
||||
$violation['meta']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$previousUsedPhotos = $eventPackage?->used_photos ?? 0;
|
||||
|
||||
$validated = $request->validated();
|
||||
$file = $request->file('photo');
|
||||
|
||||
@@ -197,12 +212,17 @@ class PhotoController extends Controller
|
||||
$this->packageUsageTracker->recordPhotoUsage($eventPackage, $previousUsedPhotos, 1);
|
||||
}
|
||||
|
||||
$limitSummary = $eventPackage
|
||||
? $this->packageLimitEvaluator->summarizeEventPackage($eventPackage)
|
||||
: null;
|
||||
|
||||
$photo->load('event')->loadCount('likes');
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Photo uploaded successfully. Awaiting moderation.',
|
||||
'data' => new PhotoResource($photo),
|
||||
'moderation_notice' => 'Your photo has been uploaded and will be reviewed shortly.',
|
||||
'limits' => $limitSummary,
|
||||
], 201);
|
||||
}
|
||||
|
||||
@@ -217,7 +237,13 @@ class PhotoController extends Controller
|
||||
->firstOrFail();
|
||||
|
||||
if ($photo->event_id !== $event->id) {
|
||||
return response()->json(['error' => 'Photo not found'], 404);
|
||||
return ApiError::response(
|
||||
'photo_not_found',
|
||||
'Foto nicht gefunden',
|
||||
'Das Foto gehört nicht zu diesem Event.',
|
||||
404,
|
||||
['photo_id' => $photo->id]
|
||||
);
|
||||
}
|
||||
|
||||
$photo->load('event')->loadCount('likes');
|
||||
@@ -239,7 +265,13 @@ class PhotoController extends Controller
|
||||
->firstOrFail();
|
||||
|
||||
if ($photo->event_id !== $event->id) {
|
||||
return response()->json(['error' => 'Photo not found'], 404);
|
||||
return ApiError::response(
|
||||
'photo_not_found',
|
||||
'Foto nicht gefunden',
|
||||
'Das Foto gehört nicht zu diesem Event.',
|
||||
404,
|
||||
['photo_id' => $photo->id]
|
||||
);
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
@@ -251,7 +283,13 @@ class PhotoController extends Controller
|
||||
|
||||
// Only tenant admins can moderate
|
||||
if (isset($validated['status']) && ! $this->tokenHasScope($request, 'tenant:write')) {
|
||||
return response()->json(['error' => 'Insufficient scopes'], 403);
|
||||
return ApiError::response(
|
||||
'insufficient_scope',
|
||||
'Insufficient Scopes',
|
||||
'You are not allowed to moderate photos for this event.',
|
||||
Response::HTTP_FORBIDDEN,
|
||||
['required_scope' => 'tenant:write']
|
||||
);
|
||||
}
|
||||
|
||||
$photo->update($validated);
|
||||
@@ -279,7 +317,13 @@ class PhotoController extends Controller
|
||||
->firstOrFail();
|
||||
|
||||
if ($photo->event_id !== $event->id) {
|
||||
return response()->json(['error' => 'Photo not found'], 404);
|
||||
return ApiError::response(
|
||||
'photo_not_found',
|
||||
'Foto nicht gefunden',
|
||||
'Das Foto gehört nicht zu diesem Event.',
|
||||
404,
|
||||
['photo_id' => $photo->id]
|
||||
);
|
||||
}
|
||||
|
||||
$assets = EventMediaAsset::where('photo_id', $photo->id)->get();
|
||||
@@ -303,6 +347,9 @@ class PhotoController extends Controller
|
||||
Storage::disk($fallbackDisk)->delete([$photo->path, $photo->thumbnail_path]);
|
||||
}
|
||||
|
||||
$eventPackage = $event->eventPackage;
|
||||
$usageTracker = app(\App\Services\Packages\PackageUsageTracker::class);
|
||||
|
||||
// Delete record and likes
|
||||
DB::transaction(function () use ($photo, $assets) {
|
||||
$photo->likes()->delete();
|
||||
@@ -312,6 +359,15 @@ class PhotoController extends Controller
|
||||
$photo->delete();
|
||||
});
|
||||
|
||||
if ($eventPackage && $eventPackage->package) {
|
||||
$previousUsed = (int) $eventPackage->used_photos;
|
||||
if ($previousUsed > 0) {
|
||||
$eventPackage->decrement('used_photos');
|
||||
$eventPackage->refresh();
|
||||
$usageTracker->recordPhotoUsage($eventPackage, $previousUsed, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Photo deleted successfully',
|
||||
]);
|
||||
@@ -328,7 +384,13 @@ class PhotoController extends Controller
|
||||
->firstOrFail();
|
||||
|
||||
if ($photo->event_id !== $event->id) {
|
||||
return response()->json(['error' => 'Photo not found'], 404);
|
||||
return ApiError::response(
|
||||
'photo_not_found',
|
||||
'Photo not found',
|
||||
'The specified photo could not be located for this event.',
|
||||
Response::HTTP_NOT_FOUND,
|
||||
['photo_id' => $photo->id, 'event_id' => $event->id]
|
||||
);
|
||||
}
|
||||
|
||||
$photo->update(['is_featured' => true]);
|
||||
@@ -345,7 +407,13 @@ class PhotoController extends Controller
|
||||
->firstOrFail();
|
||||
|
||||
if ($photo->event_id !== $event->id) {
|
||||
return response()->json(['error' => 'Photo not found'], 404);
|
||||
return ApiError::response(
|
||||
'photo_not_found',
|
||||
'Photo not found',
|
||||
'The specified photo could not be located for this event.',
|
||||
Response::HTTP_NOT_FOUND,
|
||||
['photo_id' => $photo->id, 'event_id' => $event->id]
|
||||
);
|
||||
}
|
||||
|
||||
$photo->update(['is_featured' => false]);
|
||||
@@ -569,7 +637,13 @@ class PhotoController extends Controller
|
||||
]);
|
||||
|
||||
if ($request->event_id !== $event->id) {
|
||||
return response()->json(['error' => 'Invalid event ID'], 400);
|
||||
return ApiError::response(
|
||||
'event_mismatch',
|
||||
'Invalid Event',
|
||||
'The provided event does not match the authenticated tenant event.',
|
||||
Response::HTTP_BAD_REQUEST,
|
||||
['payload_event_id' => $request->event_id, 'expected_event_id' => $event->id]
|
||||
);
|
||||
}
|
||||
|
||||
$event->load('storageAssignments.storageTarget');
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
namespace App\Http\Controllers\Api\Tenant;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Tenant\NotificationPreferencesRequest;
|
||||
use App\Http\Requests\Tenant\SettingsStoreRequest;
|
||||
use App\Models\Tenant;
|
||||
use App\Services\Packages\TenantNotificationPreferences;
|
||||
use App\Support\ApiError;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
@@ -27,6 +31,62 @@ class SettingsController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function notificationPreferences(
|
||||
Request $request,
|
||||
TenantNotificationPreferences $preferencesService
|
||||
): JsonResponse {
|
||||
$tenant = $request->tenant;
|
||||
$defaults = TenantNotificationPreferences::defaults();
|
||||
$resolved = [];
|
||||
|
||||
foreach (array_keys($defaults) as $key) {
|
||||
$resolved[$key] = $preferencesService->shouldNotify($tenant, $key);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'data' => [
|
||||
'defaults' => $defaults,
|
||||
'preferences' => $resolved,
|
||||
'overrides' => $tenant->notification_preferences ?? null,
|
||||
'meta' => [
|
||||
'credit_warning_sent_at' => $tenant->credit_warning_sent_at?->toIso8601String(),
|
||||
'credit_warning_threshold' => $tenant->credit_warning_threshold,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateNotificationPreferences(
|
||||
NotificationPreferencesRequest $request,
|
||||
TenantNotificationPreferences $preferencesService
|
||||
): JsonResponse {
|
||||
$tenant = $request->tenant;
|
||||
$payload = $request->validated()['preferences'];
|
||||
|
||||
$tenant->update([
|
||||
'notification_preferences' => $payload,
|
||||
]);
|
||||
|
||||
$tenant->refresh();
|
||||
|
||||
$resolved = [];
|
||||
foreach (array_keys(TenantNotificationPreferences::defaults()) as $key) {
|
||||
$resolved[$key] = $preferencesService->shouldNotify($tenant->fresh(), $key);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Benachrichtigungseinstellungen aktualisiert.',
|
||||
'data' => [
|
||||
'preferences' => $resolved,
|
||||
'overrides' => $tenant->notification_preferences,
|
||||
'meta' => [
|
||||
'credit_warning_sent_at' => $tenant->credit_warning_sent_at?->toIso8601String(),
|
||||
'credit_warning_threshold' => $tenant->credit_warning_threshold,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the tenant's settings.
|
||||
*/
|
||||
@@ -98,7 +158,12 @@ class SettingsController extends Controller
|
||||
$domain = $request->input('domain');
|
||||
|
||||
if (! $domain) {
|
||||
return response()->json(['error' => 'Domain ist erforderlich.'], 400);
|
||||
return ApiError::response(
|
||||
'domain_missing',
|
||||
'Domain erforderlich',
|
||||
'Bitte gib eine Domain an.',
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
if (! $this->isValidDomain($domain)) {
|
||||
|
||||
@@ -6,20 +6,19 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Tenant\TaskStoreRequest;
|
||||
use App\Http\Requests\Tenant\TaskUpdateRequest;
|
||||
use App\Http\Resources\Tenant\TaskResource;
|
||||
use App\Models\Event;
|
||||
use App\Models\Task;
|
||||
use App\Models\TaskCollection;
|
||||
use App\Models\Event;
|
||||
use App\Support\ApiError;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class TaskController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the tenant's tasks.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return AnonymousResourceCollection
|
||||
*/
|
||||
public function index(Request $request): AnonymousResourceCollection
|
||||
{
|
||||
@@ -38,7 +37,7 @@ class TaskController extends Controller
|
||||
// Search and filters
|
||||
if ($search = $request->get('search')) {
|
||||
$query->where(function ($inner) use ($search) {
|
||||
$like = '%' . $search . '%';
|
||||
$like = '%'.$search.'%';
|
||||
$inner->where('title->de', 'like', $like)
|
||||
->orWhere('title->en', 'like', $like)
|
||||
->orWhere('description->de', 'like', $like)
|
||||
@@ -47,11 +46,11 @@ class TaskController extends Controller
|
||||
}
|
||||
|
||||
if ($collectionId = $request->get('collection_id')) {
|
||||
$query->whereHas('taskCollection', fn($q) => $q->where('id', $collectionId));
|
||||
$query->whereHas('taskCollection', fn ($q) => $q->where('id', $collectionId));
|
||||
}
|
||||
|
||||
if ($eventId = $request->get('event_id')) {
|
||||
$query->whereHas('assignedEvents', fn($q) => $q->where('id', $eventId));
|
||||
$query->whereHas('assignedEvents', fn ($q) => $q->where('id', $eventId));
|
||||
}
|
||||
|
||||
$perPage = $request->get('per_page', 15);
|
||||
@@ -62,9 +61,6 @@ class TaskController extends Controller
|
||||
|
||||
/**
|
||||
* Store a newly created task in storage.
|
||||
*
|
||||
* @param TaskStoreRequest $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function store(TaskStoreRequest $request): JsonResponse
|
||||
{
|
||||
@@ -91,10 +87,6 @@ class TaskController extends Controller
|
||||
|
||||
/**
|
||||
* Display the specified task.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Task $task
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function show(Request $request, Task $task): JsonResponse
|
||||
{
|
||||
@@ -109,10 +101,6 @@ class TaskController extends Controller
|
||||
|
||||
/**
|
||||
* Update the specified task in storage.
|
||||
*
|
||||
* @param TaskUpdateRequest $request
|
||||
* @param Task $task
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(TaskUpdateRequest $request, Task $task): JsonResponse
|
||||
{
|
||||
@@ -142,10 +130,6 @@ class TaskController extends Controller
|
||||
|
||||
/**
|
||||
* Remove the specified task from storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Task $task
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, Task $task): JsonResponse
|
||||
{
|
||||
@@ -162,11 +146,6 @@ class TaskController extends Controller
|
||||
|
||||
/**
|
||||
* Assign task to an event.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Task $task
|
||||
* @param Event $event
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function assignToEvent(Request $request, Task $task, Event $event): JsonResponse
|
||||
{
|
||||
@@ -187,10 +166,6 @@ class TaskController extends Controller
|
||||
|
||||
/**
|
||||
* Bulk assign tasks to an event.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Event $event
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function bulkAssignToEvent(Request $request, Event $event): JsonResponse
|
||||
{
|
||||
@@ -200,7 +175,12 @@ class TaskController extends Controller
|
||||
|
||||
$taskIds = $request->input('task_ids', []);
|
||||
if (empty($taskIds)) {
|
||||
return response()->json(['error' => 'Keine Task-IDs angegeben.'], 400);
|
||||
return ApiError::response(
|
||||
'task_ids_missing',
|
||||
'Keine Aufgaben angegeben',
|
||||
'Bitte wähle mindestens eine Aufgabe aus.',
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
$tasks = Task::whereIn('id', $taskIds)
|
||||
@@ -209,7 +189,7 @@ class TaskController extends Controller
|
||||
|
||||
$attached = 0;
|
||||
foreach ($tasks as $task) {
|
||||
if (!$task->assignedEvents()->where('event_id', $event->id)->exists()) {
|
||||
if (! $task->assignedEvents()->where('event_id', $event->id)->exists()) {
|
||||
$task->assignedEvents()->attach($event->id);
|
||||
$attached++;
|
||||
}
|
||||
@@ -222,10 +202,6 @@ class TaskController extends Controller
|
||||
|
||||
/**
|
||||
* Get tasks for a specific event.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Event $event
|
||||
* @return AnonymousResourceCollection
|
||||
*/
|
||||
public function forEvent(Request $request, Event $event): AnonymousResourceCollection
|
||||
{
|
||||
@@ -233,7 +209,7 @@ class TaskController extends Controller
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$tasks = Task::whereHas('assignedEvents', fn($q) => $q->where('event_id', $event->id))
|
||||
$tasks = Task::whereHas('assignedEvents', fn ($q) => $q->where('event_id', $event->id))
|
||||
->with(['taskCollection'])
|
||||
->orderBy('created_at', 'desc')
|
||||
->paginate($request->get('per_page', 15));
|
||||
@@ -243,10 +219,6 @@ class TaskController extends Controller
|
||||
|
||||
/**
|
||||
* Get tasks from a specific collection.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param TaskCollection $collection
|
||||
* @return AnonymousResourceCollection
|
||||
*/
|
||||
public function fromCollection(Request $request, TaskCollection $collection): AnonymousResourceCollection
|
||||
{
|
||||
@@ -321,9 +293,7 @@ class TaskController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @param array<string, string>|null $fallback
|
||||
*
|
||||
* @param array<string, string>|null $fallback
|
||||
* @return array<string, string>|null
|
||||
*/
|
||||
protected function normalizeTranslations(mixed $value, ?array $fallback = null, bool $allowNull = false): ?array
|
||||
|
||||
Reference in New Issue
Block a user