ldc-supportweb/app/Http/Controllers/TicketController.php
2022-03-29 16:57:54 +02:00

381 lines
13 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Enums\TicketStatus;
use App\Enums\TicketType;
use App\Events\NotifySubscriptions;
use App\Events\TicketStatusChanged;
use App\Http\Requests\ChangeTicketStatus;
use App\Http\Requests\CreateMessage;
use App\Http\Requests\SortTickets;
use App\Http\Requests\StoreTicket;
use App\Http\Requests\UpdateTicket;
use App\Mail\NewTicket;
use App\Models\Message;
use App\Models\Site;
use App\Models\Ticket;
use App\Models\User;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;
class TicketController extends Controller
{
public function __construct()
{
parent::__construct();
$this->authorizeResource(Ticket::class, 'ticket');
}
public function index(SortTickets $request)
{
// handle ajax
if ($request->ajax()) {
$tickets = Ticket::with('user');
if ($request->s) {
$tickets = $tickets->where('text', 'LIKE', "%$request->s%")
->orWhere('id', $request->s)
->orWhereHas('user', function ($q) use ($request) {
$q->where('name', 'LIKE', "%$request->s%");
});
}
/** @var \Illuminate/Pagination/LengthAwarePaginator $tickets */
$tickets = $tickets->paginate();
return \response()->json($tickets->getCollection()->map(function (Ticket $ticket) {
return [
'label' => sprintf(
'Ticket %d (%s): %s',
$ticket->id,
$ticket->user ? $ticket->user->name : trans('Utilisateur supprimé'),
Str::limit(\preg_replace('/[[:cntrl:]]+/', '', $ticket->text), 35)
),
'value' => $ticket->id
];
}));
}//end if
/** @var \App\Models\User */
$user = auth()->user();
$tickets = Ticket::with('site')->has('site');
if (!$user->isAdmin()) {
$tickets = $tickets->whereHas('site', function ($q) use ($user) {
$q->whereHas('users', function ($q) use ($user) {
$q->whereId($user->id);
});
});
$tickets = $tickets->where('is_internal', 0);
}
$tickets = $tickets->where('status', ($request->st == TicketStatus::archived()) ?
'=' : '<>', TicketStatus::archived());
if ($request->search) {
$tickets = $this->searchTicket($tickets, $request);
}
$tickets = $this->filterTickets($tickets, $request);
$tickets = $tickets->paginate();
$sites = Site::select('id', 'name')->orderBy('name')->get();
$status = TicketStatus::toArray();
return view('ticket.index', compact('tickets', 'sites', 'status'));
}
private function filterTickets(Builder $tickets, Request $request): Builder
{
if ($request->rst) {
Session::remove('tickets.st');
Session::remove('tickets.pr');
Session::remove('tickets.sort_col');
Session::remove('tickets.sort_way');
}
if ($request->prs) {
Session::remove('tickets.pr');
}
if ($request->sts) {
Session::remove('tickets.st');
}
if ($request->sort_col) {
Session::put('tickets.sort_col', $request->sort_col);
}
if ($request->sort_way) {
Session::put('tickets.sort_way', $request->sort_way);
}
if ($request->pr) {
Session::put('tickets.pr', $request->pr);
}
if ($request->st) {
Session::put('tickets.st', $request->st);
}
Session::save();
if (Session::has('tickets.pr')) {
$tickets = $tickets->where('site_id', Session::get('tickets.pr'));
}
if (Session::has('tickets.st')) {
$tickets = $tickets->where('status', Session::get('tickets.st'));
}
if (
Session::has('tickets.sort_col') and
Session::has('tickets.sort_way') and
in_array(Session::get('tickets.sort_col'), [
'id', 'site_id', 'created_at', 'created_by',
'type', 'status'
])
) {
$tickets = $tickets->orderBy(
Session::get('tickets.sort_col'),
Session::get('tickets.sort_way')
);
} else {
$tickets = $tickets->orderBy('id', 'DESC');
}
return $tickets;
}
private function searchTicket(Builder $tickets, Request $request): Builder
{
$words = explode(' ', $request->search);
return $tickets->where(function ($q) use ($words) {
foreach ($words as $word) {
if (!strlen($word)) {
continue;
}
$q = $q->where(function ($q) use ($word) {
$s = collect(TicketStatus::toArray())->filter(function (TicketStatus $t) use ($word) {
return strpos(strtolower($t->label), $word) !== false;
})->map(function (TicketStatus $ticket) {
return $ticket->value;
});
$t = collect(TicketType::toArray())->filter(function (TicketType $t) use ($word) {
return strpos(strtolower($t->label), $word) !== false;
})->map(function (TicketType $ticket) {
return $ticket->value;
});
$q->where('id', $word)
->orwhere('text', 'LIKE', "%$word%")
->orWhereIn('status', $s)
->orWhereIn('type', $t)
->orWhere('file', 'LIKE', "%$word%")
->orWhere('file2', 'LIKE', "%$word%")
->orWhereHas('user', function ($q) use ($word) {
$q->where('name', 'LIKE', "%$word%");
});
});
}//end foreach
});
}
public function show(Request $request, Ticket $ticket)
{
if ($request->ajax()) {
return \response()->json([
'label' => sprintf(
'Ticket %d (%s): %s',
$ticket->id,
$ticket->user ? $ticket->user->email : __('Utilisateur supprimé'),
Str::limit(\preg_replace('/[[:cntrl:]]+/', '', $ticket->text), 35)
),
'value' => $ticket->id
]);
}
$user = Auth::user();
if (!$user->can('update', $ticket)) {
abort(403);
}
if ($ticket->is_internal === 1 && !$user->can('changeInternalStatus', $ticket)) {
abort(403);
}
$messages = $ticket->messages()->orderBy('created_at', 'DESC')->get();
$isSubscribed = (bool)$ticket->subscriptions()->where('user_id', $user->id)->count();
return view('ticket.show', compact('ticket', 'messages', 'isSubscribed'));
}
public function create()
{
/** @var \App\Models\User */
$user = auth()->user();
if ($user->isAdmin()) {
$sites = Site::orderBy('name')->get();
} else {
$sites = $user->sites;
}
if (!count($sites)) {
return redirect()->route('sites.create')
->with('warning', 'Vous devez tout d\'abord créer un site pour y ajouter un ticket');
}
return view('ticket.create', compact('sites'));
}
public function store(StoreTicket $request)
{
$site = Site::findOrFail($request->site_id);
$ticket = new Ticket($request->validated());
if ($request->file_ticket) {
$ticket->file = Ticket::saveFile($site, $ticket, $ticket->type, $request->file_ticket);
}
if ($request->file_ticket2) {
$ticket->file2 = Ticket::saveFile($site, $ticket, $ticket->type, $request->file_ticket2);
}
if ($request->has('is_internal')) {
$ticket->is_internal = 1;
} else {
$ticket->is_internal = 0;
}
$ticket->user()->associate(auth()->user());
$ticket->saveOrFail();
/** @var \App\Models\User */
$user = auth()->user();
$user->subscriptions()->toggle($ticket->id);
if (config('mail.MAIL_ADMIN')) {
Mail::to(config('mail.MAIL_ADMIN'))->send(new NewTicket($ticket));
} else {
throw new Exception('Missing MAIL_ADMIN in .env');
}
return redirect()->route('ticket.show', $ticket)
->with('success', 'Ticket enregistré !');
}
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
public function edit(Ticket $ticket)
{
/** @var \App\Models\User */
$user = auth()->user();
if ($user->isAdmin()) {
$sites = Site::orderBy('name')->get();
} else {
$sites = $user->sites;
}
return view('ticket.edit', compact('ticket', 'sites'));
}
public function update(UpdateTicket $request, Ticket $ticket)
{
$site = Site::findOrFail($request->site_id);
$ticket->fill($request->validated());
if ($request->file_ticket) {
if (File::exists($ticket->file)) {
File::delete($ticket->file);
}
$ticket->file = Ticket::saveFile($site, $ticket, $ticket->type, $request->file_ticket);
}
if ($request->file_ticket2) {
if (File::exists($ticket->file2)) {
File::delete($ticket->file2);
}
$ticket->file2 = Ticket::saveFile($site, $ticket, $ticket->type, $request->file_ticket2);
}
if ($request->has('is_internal')) {
$ticket->is_internal = 1;
} else {
$ticket->is_internal = 0;
}
$ticket->save();
return redirect()->route('ticket.edit', $ticket->id)
->with('success', 'Modifications enregistrées !');
}
public function changeStatus(ChangeTicketStatus $request, Ticket $ticket)
{
$ticket->fill($request->validated());
$ticket->save();
return back()
->with('warning', trans('Le status à été modifié'));
}
public function createMessage(CreateMessage $request, Ticket $ticket)
{
$fileMessage = $request->file_message;
$message = new Message($request->validated());
$message->user()->associate(auth()->user());
$message->ticket()->associate($ticket);
/** @var \App\Models\User */
$user = auth()->user();
// Toggle auth user subscription
if ($request->subscribe) {
if (!$user->subscriptions()->find($ticket->id)) {
$user->subscriptions()->attach($ticket->id);
}
} elseif ($user->subscriptions()->find($ticket->id)) {
$user->subscriptions()->detach($ticket->id);
}
$message->saveOrFail();
// ici $message->id n'est pas connu lors de la création du message.
// on doit donc sauvegarder cette info après le create initial
if ($request->file_message) {
$siteSlug = Str::slug($ticket->site->name);
$fileMessage = $request->file_message;
$fileName = $siteSlug . '-ticket-' . $ticket->id .
'-message-' . $message->id . '.' . $fileMessage->extension();
$fileMessage->move(public_path('fichiers/' . $siteSlug . '/' . $ticket->id . '/'), $fileName);
$filePath = 'fichiers/' . $siteSlug . '/' . $ticket->id . '/' . $fileName;
$message->file = $filePath;
$message->saveOrFail();
}
return back()
->with('success', trans('Votre message à été ajouté'));
}
public function setToArchive(Ticket $ticket)
{
$ticket->status = TicketStatus::archived();
$ticket->saveOrFail();
return redirect()->route('ticket.index')
->with('warning', trans('Le ticket est archivé'));
}
public function subscribe(Ticket $ticket)
{
/** @var \App\Models\User */
$user = auth()->user();
User::find(Auth::user()->id)->subscriptions()->toggle($ticket->id);
$status = $user->subscriptions()->where('ticket_id', $ticket->id)->exists();
if ($status) {
return back()
->with('success', trans('Vous avez été inscrit'));
}
return back()->with('warning', trans('Vous avez été désinscrit'));
}
public function reopen(Ticket $ticket)
{
$message = "{$ticket->user->name} à réouvert le ticket n°{$ticket->id}";
$oldStatus = $ticket->status;
$ticket->status = TicketStatus::inprogress();
$ticket->saveQuietly();
event(new TicketStatusChanged($ticket, $oldStatus, null, $message));
event(new NotifySubscriptions($ticket, $message, collect($ticket->user)));
User::find(Auth::user()->id)->subscriptions()->toggle($ticket->id);
return back()->with('warning', trans('Votre ticket à été réouvert.'));
}
}