Files
2026-08-25 12:36:04 +01:00

91 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
namespace Modules\Helpdesk\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
use Modules\Helpdesk\Services\TicketService;
final class TicketStoreController extends Controller
{
/**
* Store a new helpdesk ticket using a normal HTTP form post.
*
* This avoids the Livewire update endpoint for ticket creation, which prevents
* proxy/hash update-route 404s from blocking ticket creation.
*/
public function __invoke(Request $request, TicketService $tickets): RedirectResponse
{
$validated = $request->validate([
'subject' => ['required', 'string', 'max:200'],
'body' => ['required', 'string', 'min:10'],
'priority_id' => ['required', 'integer', Rule::exists('helpdesk_priorities', 'id')],
'category_id' => ['nullable', 'integer', Rule::exists('helpdesk_categories', 'id')],
'project_id' => ['nullable', 'integer', Rule::exists('helpdesk_projects', 'id')],
'product_id' => ['nullable', 'integer', Rule::exists('helpdesk_products', 'id')],
'team_id' => ['nullable', 'integer', Rule::exists('helpdesk_teams', 'id')],
'due_at' => ['nullable', 'date'],
'attachments' => ['nullable', 'array'],
'attachments.*' => $this->attachmentFileRules(),
]);
$user = Auth::user();
abort_if($user === null, 403);
$uploadedFiles = $request->file('attachments', []);
$uploadedFiles = is_array($uploadedFiles) ? $uploadedFiles : [$uploadedFiles];
$ticket = $tickets->create($user, [
'subject' => $validated['subject'],
'body' => $validated['body'],
'priority_id' => $validated['priority_id'],
'category_id' => $validated['category_id'] ?? null,
'project_id' => $validated['project_id'] ?? null,
'product_id' => $validated['product_id'] ?? null,
'team_id' => $validated['team_id'] ?? null,
'due_at' => $validated['due_at'] ?? null,
], $uploadedFiles);
return redirect()
->route('helpdesk.tickets.index')
->with('success', 'Ticket '.$ticket->reference.' has been created.');
}
/**
* Return Helpdesk attachment validation rules without relying on a newly autoloaded support class.
*
* @param bool $required Whether at least one uploaded file is required.
* @return array<int, string>
*/
private function attachmentFileRules(bool $required = false): array
{
return array_values(array_filter([
$required ? 'required' : null,
'file',
'max:'.(int) config('helpdesk.max_upload_kb', 10240),
'extensions:'.implode(',', $this->allowedAttachmentExtensions()),
]));
}
/**
* Return lower-case Helpdesk attachment extensions.
*
* @return array<int, string>
*/
private function allowedAttachmentExtensions(): array
{
return collect(config('helpdesk.allowed_extensions', config('helpdesk.allowed_mimes', [])))
->filter(static fn (mixed $extension): bool => is_string($extension) && trim($extension) !== '')
->map(static fn (string $extension): string => strtolower(ltrim(trim($extension), '.')))
->unique()
->values()
->all();
}
}