881 lines
30 KiB
PHP
881 lines
30 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Bo;
|
|
|
|
use App\Enums\Tickets\TicketStatusEnum;
|
|
use App\Enums\Tickets\TicketTypeEnum;
|
|
use App\Enums\Users\GitlabUsersEnum;
|
|
use App\Events\NotifySubscriptions;
|
|
use App\Events\TicketStatusChanged;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Bo\AssignTicketToUserRequest;
|
|
use App\Http\Requests\Bo\ChangeTicketStatus;
|
|
use App\Http\Requests\Bo\CreateMessage;
|
|
use App\Http\Requests\Bo\SortTickets;
|
|
use App\Http\Requests\Bo\StoreTicket;
|
|
use App\Http\Requests\Bo\UpdateChangeOrderRequest;
|
|
use App\Http\Requests\Bo\UpdateMessage;
|
|
use App\Http\Requests\Bo\UpdateTicket;
|
|
use App\Http\Requests\Bo\LinkTicket;
|
|
use App\Lib\Helpers\FileStorageHelper;
|
|
use App\Lib\Helpers\ToolboxHelper;
|
|
use App\Mail\NewTicket;
|
|
use App\Models\Message;
|
|
use App\Models\Site;
|
|
use App\Models\Ticket;
|
|
use App\Models\User;
|
|
use GrahamCampbell\GitLab\Facades\GitLab;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Illuminate\Support\Facades\Session;
|
|
use Illuminate\Support\Str;
|
|
|
|
class TicketController extends Controller
|
|
{
|
|
/**
|
|
* TicketController
|
|
*/
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
$this->authorizeResource(Ticket::class, 'ticket');
|
|
}
|
|
|
|
/**
|
|
* Tickets List
|
|
*
|
|
* @param SortTickets $request
|
|
* @return \Illuminate\Http\JsonResponse|\Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
|
*/
|
|
public function index(SortTickets $request)
|
|
{
|
|
// * Handle Ajax
|
|
if ($request->ajax()) {
|
|
$tickets = Ticket::with(['user', 'assignedUser']);
|
|
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', 'labels']);
|
|
if (!$user->isAdmin()) {
|
|
$tickets->whereHas('site', function ($q) use ($user) {
|
|
$q->whereHas('users', function ($q) use ($user) {
|
|
$q->whereId($user->id);
|
|
});
|
|
});
|
|
$tickets->where('is_internal', false);
|
|
} else {
|
|
$tickets->has('site');
|
|
}
|
|
|
|
$tickets->where(
|
|
'status',
|
|
($request->st == TicketStatusEnum::archived->value) ? '=' : '<>',
|
|
TicketStatusEnum::archived
|
|
);
|
|
|
|
if (!$user->isAdmin() && $user->sites->count() === 1) {
|
|
$request->merge([
|
|
'pr' => $user->sites->first()->id,
|
|
]);
|
|
}
|
|
|
|
$tickets = $this->filterTickets($tickets, $request);
|
|
$tickets = $this->searchTicket($tickets, $request);
|
|
|
|
/** Sort columns with a query */
|
|
$this->sortQuery($tickets);
|
|
|
|
/** Custom pagination */
|
|
$tickets = $this->customPaginate($tickets, $request->pagination);
|
|
|
|
$sites = Site::select('id', 'name')->orderBy('name')->get();
|
|
$status = Arr::sort(TicketStatusEnum::cases(), function (TicketStatusEnum $value) {
|
|
return $value->label();
|
|
});
|
|
$types = Arr::sort(TicketTypeEnum::cases(), function (TicketTypeEnum $value) {
|
|
return $value->label();
|
|
});
|
|
|
|
return view('bo.pages.tickets.index', compact('tickets', 'sites', 'status', 'types'));
|
|
}
|
|
|
|
/**
|
|
* Show Ticket
|
|
*
|
|
* @param Request $request
|
|
* @param Ticket $ticket
|
|
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
|
*/
|
|
public function show(Request $request, Ticket $ticket)
|
|
{
|
|
if ($request->ajax()) {
|
|
return \response()->json([
|
|
'label' => $ticket->formatName($ticket),
|
|
'value' => $ticket->id
|
|
]);
|
|
}
|
|
|
|
/** @var \App\Models\User */
|
|
$user = auth()->user();
|
|
|
|
if (!$user->can('update', $ticket)) {
|
|
abort(403);
|
|
}
|
|
|
|
if ($ticket->is_internal && !$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('bo.pages.tickets.show', [
|
|
'ticket' => $ticket,
|
|
'messages' => $messages,
|
|
'isSubscribed' => $isSubscribed
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Show create Form
|
|
*
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
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('bo.sites.create')
|
|
->with('warning', trans('Vous devez tout d\'abord créer un site pour y ajouter un ticket'));
|
|
}
|
|
return view('bo.pages.tickets.create', compact('sites'));
|
|
}
|
|
|
|
/**
|
|
* Create ticket
|
|
*
|
|
* @param StoreTicket $request
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function store(StoreTicket $request)
|
|
{
|
|
try {
|
|
return DB::transaction(function () use ($request) {
|
|
/** @var \App\Models\Site */
|
|
$site = Site::findOrFail($request->site_id);
|
|
|
|
/** @var \App\Models\User */
|
|
$user = auth()->user();
|
|
|
|
$ticket = new Ticket($request->validated());
|
|
|
|
/** @var array<\Illuminate\Http\UploadedFile> */
|
|
$fileTickets = $request->file_tickets ?? [];
|
|
if (count($fileTickets) > 0) {
|
|
foreach ($fileTickets as $key => $file) {
|
|
if ($key === 0) {
|
|
$ticket->file = FileStorageHelper::storeFile($ticket, $file);
|
|
} else {
|
|
$fileNumber = 'file' . $key + 1;
|
|
$ticket->$fileNumber = FileStorageHelper::storeFile($ticket, $file);
|
|
}
|
|
}
|
|
}
|
|
|
|
$ticket->user()->associate(auth()->user());
|
|
$ticket->site()->associate($site);
|
|
$ticket->saveOrFail();
|
|
|
|
if ($request->labels) {
|
|
$ticket->labels()->sync($request->labels);
|
|
}
|
|
|
|
$user->subscriptions()->toggle($ticket->id);
|
|
|
|
if (config('mail.MAIL_ADMIN')) {
|
|
Mail::to(config('mail.MAIL_ADMIN'))->send(new NewTicket($ticket));
|
|
} else {
|
|
throw new \ErrorException('Missing MAIL_ADMIN in .env');
|
|
}
|
|
|
|
return redirect()->route('bo.ticket.show', $ticket)
|
|
->with('success', trans('Ticket enregistré !'));
|
|
});
|
|
} catch (\ErrorException $e) {
|
|
report($e);
|
|
Session::flash('error', trans('Une erreur est survenue'));
|
|
} //end try
|
|
|
|
return \back();
|
|
}
|
|
|
|
/**
|
|
* Show update form
|
|
*
|
|
* @param Ticket $ticket
|
|
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
|
* @phpcs:disable 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('bo.pages.tickets.edit', compact('ticket', 'sites'));
|
|
}
|
|
|
|
/**
|
|
* Update Model
|
|
*
|
|
* @param UpdateTicket $request
|
|
* @param Ticket $ticket
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function update(UpdateTicket $request, Ticket $ticket)
|
|
{
|
|
$ticket->fill($request->validated());
|
|
|
|
try {
|
|
return DB::transaction(function () use ($request, $ticket) {
|
|
/** @var \App\Models\Site */
|
|
$site = Site::findOrFail($request->site_id);
|
|
|
|
/** @var null|array<\Illuminate\Http\UploadedFile> */
|
|
$fileTickets = $request->file_tickets;
|
|
if (isset($fileTickets) && count($fileTickets) > 0) {
|
|
foreach ($fileTickets as $key => $file) {
|
|
if ($key === 0) {
|
|
$ticket->file = FileStorageHelper::storeFile($ticket, $file);
|
|
} else {
|
|
$fileNumber = 'file' . $key + 1;
|
|
$ticket->$fileNumber = FileStorageHelper::storeFile($ticket, $file);
|
|
}
|
|
}
|
|
}
|
|
|
|
$ticket->labels()->sync($request->labels);
|
|
|
|
$ticket->site()->associate($site);
|
|
$ticket->saveOrFail();
|
|
|
|
return redirect()->route('bo.ticket.edit', $ticket->id)
|
|
->with('success', 'Modifications enregistrées !');
|
|
});
|
|
} catch (\ErrorException $e) {
|
|
report($e);
|
|
Session::flash('error', trans('Une erreur est survenue'));
|
|
} //end try
|
|
|
|
return \back();
|
|
}
|
|
|
|
/**
|
|
* Change ticket Status
|
|
*
|
|
* @param ChangeTicketStatus $request
|
|
* @param Ticket $ticket
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function changeStatus(ChangeTicketStatus $request, Ticket $ticket)
|
|
{
|
|
$ticket->fill($request->validated());
|
|
$ticket->saveOrFail();
|
|
|
|
return back()
|
|
->with('warning', trans('Le status à été modifié'));
|
|
}
|
|
|
|
/**
|
|
* Add a new Message to the Ticket
|
|
*
|
|
* @param CreateMessage $request
|
|
* @param Ticket $ticket
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function createMessage(CreateMessage $request, Ticket $ticket)
|
|
{
|
|
try {
|
|
return DB::transaction(function () use ($request, $ticket) {
|
|
/** @var \Illuminate\Http\UploadedFile|null */
|
|
$filesMessage = $request->file_messages;
|
|
$message = new Message($request->validated());
|
|
$message->user()->associate(auth()->user());
|
|
$message->ticket()->associate($ticket);
|
|
|
|
/** @var \App\Models\User */
|
|
$user = auth()->user();
|
|
// Subscribe to ticket.
|
|
if ($request->subscribe) {
|
|
$user->subscriptions()->syncWithoutDetaching([$ticket->id]);
|
|
} else {
|
|
$user->subscriptions()->detach($ticket->id);
|
|
}
|
|
|
|
// Store files if any.
|
|
if (isset($filesMessage) and $filesMessage) {
|
|
foreach ($filesMessage as $key => $singleFile) {
|
|
if ($key === 0) {
|
|
$message->file = FileStorageHelper::storeFile($message, $singleFile);
|
|
$message->saveOrFail();
|
|
} else {
|
|
$fileNumber = 'file' . $key + 1;
|
|
$message->$fileNumber = FileStorageHelper::storeFile($message, $singleFile);
|
|
$message->saveOrFail();
|
|
}
|
|
}
|
|
}
|
|
|
|
$message->saveOrFail();
|
|
|
|
return back()
|
|
->with('success', trans('Votre message à été ajouté'));
|
|
});
|
|
} catch (\ErrorException $e) {
|
|
report($e);
|
|
Session::flash('error', trans('Une erreur est survenue'));
|
|
} //end try
|
|
|
|
return back();
|
|
}
|
|
|
|
/**
|
|
* Update Message
|
|
*
|
|
* @param UpdateMessage $request
|
|
* @param Ticket $ticket
|
|
* @param Message $message
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
|
*/
|
|
public function updateMessage(UpdateMessage $request, Ticket $ticket, Message $message)
|
|
{
|
|
$message->message = $request->message;
|
|
$message->saveOrFail();
|
|
|
|
return back()
|
|
->with('success', trans('Votre message à bien été modifié'));
|
|
}
|
|
|
|
/**
|
|
* Change ticket status to archived
|
|
*
|
|
* @param Ticket $ticket
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function setToArchive(Ticket $ticket)
|
|
{
|
|
$ticket->status = TicketStatusEnum::archived;
|
|
$ticket->saveOrFail();
|
|
return redirect()->route('bo.ticket.index')
|
|
->with('warning', trans('Le ticket est archivé'));
|
|
}
|
|
|
|
/**
|
|
* Subscribe to ticket
|
|
*
|
|
* @param Ticket $ticket
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function subscribe(Ticket $ticket)
|
|
{
|
|
/** @var \App\Models\User */
|
|
$user = auth()->user();
|
|
$user->subscriptions()->toggle($ticket->id);
|
|
if ($user->subscriptions()->where('ticket_id', $ticket->id)->exists()) {
|
|
return back()
|
|
->with('success', trans('Vous avez été inscrit'));
|
|
}
|
|
return back()->with('warning', trans('Vous avez été désinscrit'));
|
|
}
|
|
|
|
/**
|
|
* Reopen ticket
|
|
*
|
|
* @param Ticket $ticket
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function reopen(Ticket $ticket)
|
|
{
|
|
$message = trans(':ticketName à réouvert le ticket n°:ticketNumber', [
|
|
'ticketName' => $ticket->user->name,
|
|
'ticketNumber' => $ticket->id,
|
|
]);
|
|
/** @var \App\Enums\Tickets\TicketStatusEnum */
|
|
$oldStatus = $ticket->status;
|
|
$ticket->status = TicketStatusEnum::new;
|
|
$ticket->saveQuietly();
|
|
event(new TicketStatusChanged($ticket, $oldStatus, null, $message, false, false));
|
|
event(new NotifySubscriptions($ticket, $message, collect([$ticket->user])));
|
|
|
|
/** @var \App\Models\User */
|
|
$user = auth()->user();
|
|
$user->subscriptions()->toggle($ticket->id);
|
|
|
|
return back()->with('warning', trans('Votre ticket à été réouvert.'));
|
|
}
|
|
|
|
/**
|
|
* Assign ticket to user ticket
|
|
*
|
|
* @param AssignTicketToUserRequest $request
|
|
* @param Ticket $ticket
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function assignTo(AssignTicketToUserRequest $request, Ticket $ticket)
|
|
{
|
|
/** @var \App\Models\User */
|
|
$user = auth()->user();
|
|
|
|
/** @var \App\Models\User|null */
|
|
if ($assignedUser = User::whereId($request->assign)->first()) {
|
|
$message = trans(':admin a assigné le ticket n°:ticketNumber à :assignedAdmin', [
|
|
'admin' => $user->name,
|
|
'ticketNumber' => $ticket->id,
|
|
'assignedAdmin' => $assignedUser->name,
|
|
]);
|
|
$ticket->assignedUser()->associate($assignedUser);
|
|
} else {
|
|
$message = trans(
|
|
':admin a modifié l\'assignation du ticket n°:ticketNumber, il n\'est plus assigné à quelqu\'un.',
|
|
[
|
|
'admin' => $user->name,
|
|
'ticketNumber' => $ticket->id,
|
|
]
|
|
);
|
|
$ticket->assignedUser()->dissociate();
|
|
}
|
|
$ticket->saveQuietly();
|
|
|
|
|
|
/** @var \App\Enums\Tickets\TicketStatusEnum */
|
|
$oldStatus = $ticket->status;
|
|
// * Notification systeme doit etre privée.
|
|
event(new TicketStatusChanged($ticket, $oldStatus, null, $message, true, false));
|
|
event(new NotifySubscriptions($ticket, $message, collect([$ticket->user])));
|
|
|
|
/** @var \App\Models\User */
|
|
$user = auth()->user();
|
|
$user->subscriptions()->toggle($ticket->id);
|
|
|
|
if ($assignedUser) {
|
|
return back()->with('info', trans('Le ticket à été assigné à :assignedUser', [
|
|
'assignedUser' => $assignedUser->name
|
|
]));
|
|
}
|
|
return back()->with('info', trans('Le ticket n\'est plus assigné à personne'));
|
|
}
|
|
|
|
|
|
/**
|
|
* Link two tickets.
|
|
*
|
|
* @param LinkTicket $request
|
|
* @param Ticket $ticket
|
|
*
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function linkTicket(LinkTicket $request, Ticket $ticket)
|
|
{
|
|
$linkedTicket = Ticket::findOrFail($request->validated())->first();
|
|
|
|
if ($ticket->site_id !== $linkedTicket->site_id) {
|
|
return back()->with('error', trans('Le ticket que vous avez renseigné ne fait pas partie du même site.'));
|
|
}
|
|
|
|
if (!$ticket->linkedTickets()->where('linked_ticket_id', $linkedTicket->id)->exists()) {
|
|
$ticket->linkedTickets()->attach($linkedTicket->id);
|
|
$linkedTicket->linkedTickets()->attach($ticket->id);
|
|
return back()->with('success', trans('Les tickets ont été liés avec succès.'));
|
|
}
|
|
|
|
return back()->with('error', trans('Les tickets sont déjà liés ensemble.'));
|
|
}
|
|
|
|
/**
|
|
* Unlink two tickets.
|
|
*
|
|
* @param Ticket $ticket
|
|
* @param Ticket $linkedTicket
|
|
*
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function unlinkTicket(Ticket $ticket, Ticket $linkedTicket)
|
|
{
|
|
$ticket->linkedTickets()->detach($linkedTicket->id);
|
|
$linkedTicket->linkedTickets()->detach($ticket->id);
|
|
|
|
return back()->with('warning', trans('Le lien entre les tickets à été supprimé.'));
|
|
}
|
|
|
|
// * PRIVATES
|
|
|
|
/**
|
|
* Filter Tickets request constructor
|
|
*
|
|
* @param Builder $tickets
|
|
* @param Request $request
|
|
* @return Builder
|
|
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
|
|
*/
|
|
private function filterTickets(Builder $tickets, Request $request): Builder
|
|
{
|
|
//phpcs:enable
|
|
if ($request->rst) {
|
|
Session::remove('tickets.ass');
|
|
Session::remove('tickets.st');
|
|
Session::remove('tickets.pr');
|
|
Session::remove('tickets.ty');
|
|
Session::remove('tickets.sort_col');
|
|
Session::remove('tickets.sort_way');
|
|
Session::remove('tickets.or');
|
|
Session::remove('tickets.search');
|
|
}
|
|
if ($request->assr) {
|
|
Session::remove('tickets.ass');
|
|
}
|
|
if ($request->prs) {
|
|
Session::remove('tickets.pr');
|
|
}
|
|
if ($request->sts) {
|
|
Session::remove('tickets.st');
|
|
}
|
|
if ($request->tys) {
|
|
Session::remove('tickets.ty');
|
|
}
|
|
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->ord) {
|
|
Session::remove('tickets.or');
|
|
}
|
|
if ($request->pr) {
|
|
Session::put('tickets.pr', $request->pr);
|
|
}
|
|
if ($request->st) {
|
|
Session::put('tickets.st', $request->st);
|
|
}
|
|
if ($request->ty) {
|
|
Session::put('tickets.ty', $request->ty);
|
|
}
|
|
if ($request->ass) {
|
|
Session::put('tickets.ass', $request->ass);
|
|
}
|
|
if (Session::has('tickets.or')) {
|
|
Session::remove('tickets.ass');
|
|
Session::remove('tickets.st');
|
|
Session::remove('tickets.ty');
|
|
Session::remove('tickets.sort_col');
|
|
Session::remove('tickets.sort_way');
|
|
Session::remove('tickets.search');
|
|
}
|
|
|
|
if ($request->or && Session::has('tickets.pr')) {
|
|
Session::put('tickets.or', $request->or);
|
|
}
|
|
|
|
Session::save();
|
|
|
|
if (Session::has('tickets.pr')) {
|
|
$tickets->where('site_id', Session::get('tickets.pr'));
|
|
}
|
|
|
|
if (Session::has('tickets.ass')) {
|
|
$tickets->whereHas('assignedUser', function ($q) {
|
|
$q->whereId(Session::get('tickets.ass'));
|
|
});
|
|
}
|
|
|
|
if (Session::has('tickets.st')) {
|
|
$tickets->where('status', Session::get('tickets.st'));
|
|
}
|
|
|
|
if (Session::has('tickets.ty')) {
|
|
$tickets->where('type', Session::get('tickets.ty'));
|
|
}
|
|
|
|
if (Session::has('tickets.or')) {
|
|
$tickets->orderBy('order', 'ASC');
|
|
}
|
|
|
|
if (
|
|
Session::has('tickets.sort_col') and
|
|
Session::has('tickets.sort_way') and
|
|
in_array(Session::get('tickets.sort_col'), [
|
|
'type',
|
|
'title',
|
|
'assigned_to',
|
|
'date_mep',
|
|
'created_at',
|
|
'created_by'
|
|
])
|
|
) {
|
|
$tickets->orderBy(
|
|
Session::get('tickets.sort_col'),
|
|
Session::get('tickets.sort_way')
|
|
);
|
|
} else {
|
|
$tickets->orderBy('last_activity', 'DESC');
|
|
}
|
|
|
|
return $tickets;
|
|
}
|
|
|
|
/**
|
|
* Search ticket sql request constructor
|
|
*
|
|
* @param Builder $tickets
|
|
* @param Request $request
|
|
* @return Builder
|
|
*/
|
|
private function searchTicket(Builder $tickets, Request $request): Builder
|
|
{
|
|
if ($request->exists('search')) {
|
|
if (empty($request->search)) {
|
|
Session::remove('tickets.search');
|
|
} else {
|
|
Session::put('tickets.search', $request->search);
|
|
}
|
|
}
|
|
|
|
if (!Session::has('tickets.search')) {
|
|
return $tickets;
|
|
}
|
|
|
|
return $this->searchQuery($tickets, Session::get('tickets.search'), function ($q) {
|
|
$words = explode(' ', Session::get('tickets.search'));
|
|
if (\is_array($words)) {
|
|
foreach ($words as $word) {
|
|
if (!strlen($word)) {
|
|
continue;
|
|
}
|
|
$s = collect(TicketStatusEnum::cases())->filter(function (TicketStatusEnum $t) use ($word) {
|
|
return Str::slug($t->label()) === Str::slug($word);
|
|
})->map(function (TicketStatusEnum $ticket) {
|
|
return $ticket->value;
|
|
});
|
|
$t = collect(TicketTypeEnum::cases())->filter(function (TicketTypeEnum $s) use ($word) {
|
|
return Str::slug($s->label()) === Str::slug($word);
|
|
})->map(function (TicketTypeEnum $ticket) {
|
|
return $ticket->value;
|
|
});
|
|
$q->orWhere('id', $word)
|
|
->orWhereIn('status', $s)
|
|
->orWhereIn('type', $t)
|
|
->orWhereHas('user', function ($q) use ($word) {
|
|
$q->where('name', 'LIKE', "%$word%");
|
|
});
|
|
} //end foreach
|
|
} //end if
|
|
}, 'text', 'title', 'file', 'file2', 'file3', 'file4', 'file5');
|
|
}
|
|
|
|
/**
|
|
* Get a paginate resource.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return Illuminate\Http\JsonResponse
|
|
*/
|
|
public function jsonPaginate(Request $request): \Illuminate\Http\JsonResponse
|
|
{
|
|
return DB::transaction(function () use ($request) {
|
|
$model = $request->targetModel;
|
|
$search = $request->search;
|
|
|
|
// * Handle Ajax
|
|
$tickets = $model::with(['user', 'assignedUser']);
|
|
if ($search) {
|
|
$tickets = $tickets->where('text', 'LIKE', "%$search%")
|
|
->orWhere('id', $search)
|
|
->orWhereHas('user', function ($q) use ($search) {
|
|
$q->where('name', 'LIKE', "%$search%");
|
|
})
|
|
->orderBy("id", "ASC");
|
|
}
|
|
|
|
return ToolboxHelper::jsonPaginate(
|
|
$this->customPaginate($tickets, $request->pagination),
|
|
'formatName'
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create a gitlab issue from a ticket.
|
|
*
|
|
* @param \App\Models\Ticket $ticket
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
*/
|
|
public function createGitlabIssue(Ticket $ticket)
|
|
{
|
|
$gitlabRepoId = $ticket->site->gitlab_project_id;
|
|
$description = \sprintf("%s<br>", $ticket->text);
|
|
$cLabel = match ($ticket->type) {
|
|
TicketTypeEnum::bug => 'c-bug',
|
|
TicketTypeEnum::evolution, TicketTypeEnum::newsletter => 'c-feature',
|
|
};
|
|
|
|
$assigneeId = match ($ticket->type) {
|
|
TicketTypeEnum::bug => GitlabUsersEnum::default->value,
|
|
TicketTypeEnum::evolution,
|
|
TicketTypeEnum::newsletter => $ticket->site->projectManager?->gitlab_id ?? GitlabUsersEnum::default->value
|
|
};
|
|
|
|
try {
|
|
foreach ($ticket->getFiles() as $key => $file) {
|
|
if (!\is_null($file)) {
|
|
$uploadedFile = GitLab::projects()->uploadFile($gitlabRepoId, $file);
|
|
$description .= $this->formatGitlabFiles($ticket, $uploadedFile, $key + 1);
|
|
}
|
|
}
|
|
|
|
$issue = GitLab::issues()->create($gitlabRepoId, [
|
|
'title' => sprintf(
|
|
'ts-%s : %s',
|
|
$ticket->id,
|
|
$ticket->title
|
|
),
|
|
'description' => $description,
|
|
'labels' => \implode(",", [
|
|
'c-support',
|
|
$cLabel
|
|
]),
|
|
'assignee_id' => $assigneeId,
|
|
]);
|
|
} catch (\Exception $e) {
|
|
\report($e);
|
|
return back()->with('error', \trans("Une erreur est survenue"));
|
|
} catch (\Throwable $e) {
|
|
\report($e);
|
|
return back()->with('error', \trans("Une erreur est survenue"));
|
|
} //end try
|
|
|
|
$ticket->gitlab_issue = $issue['web_url'];
|
|
$ticket->save();
|
|
|
|
return back()->with(
|
|
'success',
|
|
trans("L'issue a été créée sur Gitlab.")
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Format files for Gitlab issues
|
|
*
|
|
* @param \App\Models\Ticket $ticket
|
|
* @param array $uploadedFile
|
|
* @param integer $fileNb
|
|
* @return string
|
|
*/
|
|
private function formatGitlabFiles(Ticket $ticket, array $uploadedFile, int $fileNb)
|
|
{
|
|
if (Str::endsWith($ticket->file, ['jpg', 'png', 'jpeg', 'pptx', 'docx', 'xslx', 'csv', 'svg'])) {
|
|
$file = \sprintf(
|
|
"",
|
|
$fileNb,
|
|
$uploadedFile['url']
|
|
);
|
|
} else {
|
|
$file = \sprintf(
|
|
'<a href="%s" target="_blank">%s</a>',
|
|
$uploadedFile['url'],
|
|
__('Lien vers le fichier'),
|
|
);
|
|
}
|
|
return \sprintf("<br><br> Fichier %d : <br>%s<br>", $fileNb, $file);
|
|
}
|
|
|
|
/**
|
|
* Change order.
|
|
*
|
|
* @param \App\Http\Requests\Bo\UpdateChangeOrderRequest $request
|
|
* @param mixed ...$params
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
* @throws \RuntimeException Si le nom du parametre de la route ne correspond pas au params utilisé.
|
|
*/
|
|
public function changeOrder(UpdateChangeOrderRequest $request, mixed ...$params): \Illuminate\Http\RedirectResponse
|
|
{
|
|
$paramNames = collect(request()->route()->parameterNames);
|
|
$className = Str::of($paramNames->get($paramNames->count() - 2))->lower()->studly();
|
|
$className = "\\App\\Models\\{$className}";
|
|
$model = Arr::get($params, $paramNames->count() - 2);
|
|
|
|
if (!class_exists($className)) {
|
|
throw new \RuntimeException("The {$className} class doesn't exist.");
|
|
}
|
|
|
|
if (!\is_object($model)) {
|
|
throw new \RuntimeException("The second last param isn't an object.");
|
|
}
|
|
|
|
if (get_class($model) !== (string)Str::of($className)->replaceStart('\\', '')) {
|
|
throw new \RuntimeException("The {$className} doesn't match second last binded param.");
|
|
}
|
|
|
|
/** @var \Illuminate\Database\Eloquent\Model|null */
|
|
$model = $className::query()->where($model->getRouteKeyName(), $model->getRouteKey())->first();
|
|
|
|
if (!$model) {
|
|
return back()->with('error', trans('crud.messages.order_not_changed'));
|
|
}
|
|
|
|
return DB::transaction(function () use ($request, $className, $model) {
|
|
/** @var \Illuminate\Support\Collection $models */
|
|
$models = $className::query()
|
|
->orderBy('order', 'ASC')
|
|
->where('site_id', $model->site_id)
|
|
->where('status', '!=', TicketStatusEnum::archived)
|
|
->where('id', '!=', $model->getKey())
|
|
->where('order', $request->direction ? '<' : '>', $model->order)
|
|
->get();
|
|
/** @var \Illuminate\Database\Eloquent\Model|null $tmp */
|
|
$tmp = $request->direction ? $models->last() : $models->first();
|
|
|
|
if (!$tmp) {
|
|
return back()->with('error', trans('crud.messages.order_not_changed'));
|
|
}
|
|
|
|
$newOrder = $tmp->getOriginal('order');
|
|
$tmp->update(['order' => $model->getOriginal('order')]);
|
|
$model->update(['order' => $newOrder]);
|
|
|
|
return redirect()->back()->with('success', trans('crud.messages.order_changed'));
|
|
});
|
|
}
|
|
}
|