Merge branch 'issue-77-linking' into 'develop'
feat: ✨ added the possibility of linking tickets !77 See merge request ldc-web/projets/support-web!96
This commit is contained in:
commit
99744045e9
10 changed files with 184 additions and 7 deletions
|
|
@ -16,6 +16,7 @@ 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;
|
||||
|
|
@ -139,10 +140,13 @@ class TicketController extends Controller
|
|||
abort(403);
|
||||
}
|
||||
|
||||
$linkedTicket = $ticket->linkedTicket()->get();
|
||||
|
||||
$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,
|
||||
'linkedTicket' => $linkedTicket,
|
||||
'messages' => $messages,
|
||||
'isSubscribed' => $isSubscribed
|
||||
]);
|
||||
|
|
@ -489,6 +493,48 @@ class TicketController extends Controller
|
|||
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->linkedTicket()->where('linked_ticket_id', $linkedTicket->id)->exists()) {
|
||||
$ticket->linkedTicket()->attach($linkedTicket->id);
|
||||
$linkedTicket->linkedTicket()->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->linkedTicket()->detach($linkedTicket->id);
|
||||
$linkedTicket->linkedTicket()->detach($ticket->id);
|
||||
|
||||
return back()->with('warning', trans('Le lien entre les tickets à été supprimé.'));
|
||||
}
|
||||
|
||||
// * PRIVATES
|
||||
|
||||
/**
|
||||
|
|
|
|||
36
app/Http/Requests/Bo/LinkTicket.php
Normal file
36
app/Http/Requests/Bo/LinkTicket.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class LinkTicket extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$ticket = $this->route('ticket');
|
||||
return [
|
||||
'linked_ticket_id' => [
|
||||
'required',
|
||||
'numeric',
|
||||
'exists:tickets,id',
|
||||
'not_in:' . $ticket->id,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -193,6 +193,16 @@ class Ticket extends Model
|
|||
return $this->belongsTo(TicketType::class, 'type', 'type');
|
||||
}
|
||||
|
||||
/**
|
||||
* BelongsToMany Linked Ticket
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function linkedTicket()
|
||||
{
|
||||
return $this->belongsToMany(Ticket::class, 'linked_tickets', 'ticket_id', 'linked_ticket_id');
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -68,12 +68,12 @@ class TicketPolicy
|
|||
}
|
||||
|
||||
/**
|
||||
* Determine if the user can change the order of a given ticket.
|
||||
* Determine if the user can link ticket .
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function changeOrder(User $user)
|
||||
public function linkTicket(User $user)
|
||||
{
|
||||
return $user->isAdmin();
|
||||
}
|
||||
|
|
|
|||
35
database/migrations/2025_03_13_151503_tickets_linking.php
Normal file
35
database/migrations/2025_03_13_151503_tickets_linking.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('linked_tickets', function (Blueprint $table) {
|
||||
$table->unsignedBigInteger('ticket_id')
|
||||
->constrained()->cascadeOnDelete();
|
||||
$table->unsignedBigInteger('linked_ticket_id')
|
||||
->constrained()->cascadeOnDelete();
|
||||
$table->foreign('ticket_id')->references('id')->on('tickets');
|
||||
$table->foreign('linked_ticket_id')->references('id')->on('tickets');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('linked_tickets');
|
||||
}
|
||||
};
|
||||
|
|
@ -89,5 +89,7 @@ return [
|
|||
'sort_delete' => 'Supprimer le tri',
|
||||
'sort_arrow' => 'Ici, les flèches sont utilisées pour trier et non pour filtrer',
|
||||
'right' => 'Vous n\'avez pas les droits',
|
||||
'view_linked_ticket' => 'voir le ticket :model',
|
||||
'unlink_ticket' => 'supprimer le lien avec le ticket :model'
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@ import {
|
|||
faUndoAlt,
|
||||
faUsers,
|
||||
faWandMagic,
|
||||
faXmark
|
||||
faXmark,
|
||||
faLinkSlash
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
config.autoReplaceSvg = false;
|
||||
|
|
@ -126,6 +127,7 @@ library.add(faCircleExclamation);
|
|||
library.add(faCircleInfo);
|
||||
library.add(faPaintRoller);
|
||||
library.add(faTicket);
|
||||
library.add(faLinkSlash);
|
||||
|
||||
// Front
|
||||
library.add(faChevronLeft);
|
||||
|
|
|
|||
|
|
@ -199,10 +199,10 @@
|
|||
$cols = array_merge($cols, [
|
||||
'tickets' => Str::ucfirst(__('validation.custom.tickets')),
|
||||
'assigned_to' => Str::ucfirst(__('validation.custom.assigned_to')),
|
||||
'date_mep' => Str::ucfirst(__('validation.custom.date_mep')),
|
||||
]);
|
||||
}
|
||||
$cols = array_merge($cols, [
|
||||
'date_mep' => Str::ucfirst(__('validation.custom.date_mep')),
|
||||
'created_at' => Str::ucfirst(__('validation.attributes.created_at')),
|
||||
]);
|
||||
@endphp
|
||||
|
|
@ -278,10 +278,10 @@
|
|||
{{-- assigned_to / date_mep --}}
|
||||
@if (Auth::user()->isAdmin())
|
||||
<td>{{ $ticket->assignedUser ? $ticket->assignedUser->name : __('Personne') }}</td>
|
||||
<td>
|
||||
{{ is_null($ticket->date_mep) ? Str::ucfirst(__("validation.custom.date_mep_empty")) : $ticket->date_mep->format('d/m/Y') }}
|
||||
</td>
|
||||
@endif
|
||||
<td class="text-center">
|
||||
{{ is_null($ticket->date_mep) ? Str::ucfirst(__("validation.custom.date_mep_empty")) : $ticket->date_mep->format('d/m/Y') }}
|
||||
</td>
|
||||
<td>{{ Carbon\Carbon::parse($ticket->created_at)->format('d/m/Y à H:i') }}</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
|
|
|
|||
|
|
@ -273,6 +273,46 @@
|
|||
</div>
|
||||
@endif
|
||||
<hr>
|
||||
<div class="flex-col">
|
||||
<div>
|
||||
<h4>{{ __('Tickets liés') }}</h4>
|
||||
</div>
|
||||
@can('linkTicket', $ticket)
|
||||
<div class="row">
|
||||
<form class="col" id="form_link_ticket" action="{{ route('bo.ticket.link', ['ticket' => $ticket]) }}" method="POST">
|
||||
@csrf
|
||||
<div class="input-group">
|
||||
<label class="input-group-text" for="link-ticket"><i class="fa-solid fa-ticket"></i></label>
|
||||
<input class="form-control" id="linked_ticket_id" name="linked_ticket_id" type="text" placeholder="Numéro du ticket">
|
||||
<button class="btn btn-sm btn-success float-end" type="submit">
|
||||
{{ __('Lier') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endcan
|
||||
<div class="row row-cols-auto gap-2">
|
||||
@foreach ($linkedTicket as $linked)
|
||||
<div class="col">
|
||||
@can('linkTicket', $ticket)
|
||||
<form id="form_unlink_ticket" action="{{ route('bo.ticket.unlink', ['ticket' => $ticket, 'linkedTicket' => $linked]) }}" method="POST">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<div class="input-group mt-2">
|
||||
@endcan
|
||||
<a class="btn btn-xl btn-outline-primary" href="{{ route('bo.ticket.show', $linked->id) }}" title="{{ Str::ucfirst(__('crud.other.view_linked_ticket', ['model' => $linked->id])) }}">
|
||||
TICKET - {{ $linked->id }}
|
||||
</a>
|
||||
@can('linkTicket', $ticket)
|
||||
<button class="btn btn-xl btn-outline-danger" type="submit" title="{{ Str::ucfirst(__('crud.other.unlink_ticket', ['model' => $linked->id])) }}"><i class="fa-solid fa-link-slash"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
@endcan
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
@can('createGitlabIssue', $ticket)
|
||||
<form class="col d-flex justify-content-end" id="form_issue" action="{{ route('bo.ticket.create-issue', $ticket) }}" method="POST">
|
||||
@csrf
|
||||
|
|
|
|||
|
|
@ -154,6 +154,12 @@ Route::middleware('admin-secure')
|
|||
Route::post('/{ticket}/subscribe', [TicketController::class, 'subscribe'])
|
||||
->middleware('can:suscribeToTicket,ticket')
|
||||
->name('subscribe');
|
||||
Route::post('/{ticket}/link', [TicketController::class, 'linkTicket'])
|
||||
->middleware('can:linkTicket,ticket')
|
||||
->name('link');
|
||||
Route::delete('/{ticket}/unlink/{linkedTicket}', [TicketController::class, 'unlinkTicket'])
|
||||
->middleware('can:linkTicket,ticket')
|
||||
->name('unlink');
|
||||
Route::put('/{ticket}/archive', [TicketController::class, 'setToArchive'])
|
||||
->middleware('can:changeStatus,ticket')
|
||||
->name('archive');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue