Complete Rewrite
This commit is contained in:
parent
b078b03be1
commit
59b6b04f8a
38 changed files with 1005 additions and 473 deletions
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Project;
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class CreateUser extends Command
|
||||
|
|
@ -47,7 +49,16 @@ class CreateUser extends Command
|
|||
if ($this->confirm('Is the user an admin?')) {
|
||||
$admin = true;
|
||||
} else {
|
||||
$projectId = $this->ask("What's the id of the project (s)he's working on?");
|
||||
$project = null;
|
||||
try {
|
||||
$project = Project::where(
|
||||
'id',
|
||||
$this->ask("What's the id of the project (s)he's working on?")
|
||||
)->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
$this->error('The project does not exists');
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
$user = new User();
|
||||
|
|
@ -56,11 +67,12 @@ class CreateUser extends Command
|
|||
if ($admin) {
|
||||
$user->role = 1;
|
||||
} else {
|
||||
$user->project_id = $projectId;
|
||||
$user->project_id = $project->id;
|
||||
}
|
||||
$user->password = Hash::make($pwd);
|
||||
$user->save();
|
||||
|
||||
$this->info('User created.');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
34
app/Enums/TicketStatus.php
Normal file
34
app/Enums/TicketStatus.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self new()
|
||||
* @method static self inprogress()
|
||||
* @method static self processed()
|
||||
* @method static self archived()
|
||||
*/
|
||||
class TicketStatus extends BaseEnum
|
||||
{
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'new' => 1,
|
||||
'inprogress' => 2,
|
||||
'processed' => 3,
|
||||
'archived' => 4,
|
||||
];
|
||||
}
|
||||
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'new' => trans('Nouveau'),
|
||||
'inprogress' => trans('En cours'),
|
||||
'processed' => trans('Traité'),
|
||||
'archived' => trans('Archivé'),
|
||||
];
|
||||
}
|
||||
}
|
||||
28
app/Enums/TicketType.php
Normal file
28
app/Enums/TicketType.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnum;
|
||||
|
||||
/**
|
||||
* @method static self bug()
|
||||
* @method static self evolution()
|
||||
*/
|
||||
class TicketType extends BaseEnum
|
||||
{
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'bug' => 0,
|
||||
'evolution' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'bug' => trans('Bug'),
|
||||
'evolution' => trans('Évolution'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -2,22 +2,29 @@
|
|||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class NotifySubscriptions
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
use Dispatchable;
|
||||
use InteractsWithSockets;
|
||||
use SerializesModels;
|
||||
|
||||
public $ticket, $corpsMaj;
|
||||
/** @var Ticket */
|
||||
public $ticket;
|
||||
|
||||
/** @var string */
|
||||
public $corpsMaj;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($ticket, $corpsMaj)
|
||||
public function __construct(Ticket $ticket, string $corpsMaj)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
$this->corpsMaj = $corpsMaj;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ use App\Models\Ticket;
|
|||
|
||||
class ProjectController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(Project::class, 'project');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$projects = Project::all();
|
||||
|
|
|
|||
|
|
@ -2,234 +2,160 @@
|
|||
|
||||
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\Project;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class TicketController extends Controller
|
||||
{
|
||||
private $status = [1 => "Nouveau", 2 => "En cours", 3 => "Traité", 4 => "Archivé"];
|
||||
|
||||
public function index(Request $request)
|
||||
public function __construct()
|
||||
{
|
||||
if (Auth::check()) {
|
||||
$tickets = Ticket::where('status', '<>', 4);
|
||||
$this->authorizeResource(Ticket::class, 'ticket');
|
||||
}
|
||||
|
||||
$sortway = $request->sort_way == 'asc' ? 'asc' : null;
|
||||
$sortway = $request->sort_way == 'desc' ? 'desc' : null;
|
||||
public function index(SortTickets $request)
|
||||
{
|
||||
$tickets = Ticket::query();
|
||||
|
||||
if ($request->sort_col and $sortway) {
|
||||
switch ($request->sort_col) {
|
||||
case 'id':
|
||||
$tickets = $tickets->orderBy('id', $sortway);
|
||||
break;
|
||||
case 'project':
|
||||
$tickets = $tickets->orderBy('project_id', $sortway);
|
||||
break;
|
||||
case 'created_at':
|
||||
$tickets = $tickets->orderBy('created_at', $sortway);
|
||||
break;
|
||||
case 'created_by':
|
||||
$tickets = $tickets->orderBy('created_by', $sortway);
|
||||
break;
|
||||
case 'type':
|
||||
$tickets = $tickets->orderBy('type', $sortway);
|
||||
break;
|
||||
case 'status':
|
||||
$tickets = $tickets->orderBy('status', $sortway);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$tickets = $tickets->paginate();
|
||||
|
||||
$status = $this->status;
|
||||
return view('home', compact('tickets', 'status'));
|
||||
if ($request->status) {
|
||||
$tickets = $tickets->where('status', TicketStatus::archived());
|
||||
} else {
|
||||
return view('home');
|
||||
$tickets = $tickets->where('status', '<>', TicketStatus::archived());
|
||||
}
|
||||
|
||||
if ($request->sort_col and $request->sort_way) {
|
||||
switch ($request->sort_col) {
|
||||
case 'id':
|
||||
$tickets = $tickets->orderBy('id', $request->sort_way);
|
||||
break;
|
||||
case 'project':
|
||||
$tickets = $tickets->orderBy('project_id', $request->sort_way);
|
||||
break;
|
||||
case 'created_at':
|
||||
$tickets = $tickets->orderBy('created_at', $request->sort_way);
|
||||
break;
|
||||
case 'created_by':
|
||||
$tickets = $tickets->orderBy('created_by', $request->sort_way);
|
||||
break;
|
||||
case 'type':
|
||||
$tickets = $tickets->orderBy('type', $request->sort_way);
|
||||
break;
|
||||
case 'status':
|
||||
$tickets = $tickets->orderBy('status', $request->sort_way);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$tickets = $tickets->paginate();
|
||||
|
||||
return view('ticket.index', compact('tickets'));
|
||||
}
|
||||
|
||||
public function show($id) {
|
||||
$ticket = Ticket::find($id);
|
||||
$status = $this->status;
|
||||
public function show(Ticket $ticket)
|
||||
{
|
||||
$messages = $ticket->messages()->orderBy('created_at', 'DESC')->get();
|
||||
$isSubscribed = false;
|
||||
if (!$ticket)
|
||||
abort(404);
|
||||
if ($ticket->subscriptions()->where('user_id', Auth::user()->id)->count() !== 0)
|
||||
$isSubscribed = true;
|
||||
return view('ticket.show', compact('ticket', 'status', 'messages', 'isSubscribed'));
|
||||
$isSubscribed = (bool)$ticket->subscriptions()->where('user_id', Auth::user()->id)->count();
|
||||
return view('ticket.show', compact('ticket', 'messages', 'isSubscribed'));
|
||||
}
|
||||
|
||||
public function create() {
|
||||
public function create()
|
||||
{
|
||||
$projects = Project::all();
|
||||
if (!count($projects)) {
|
||||
return redirect()->route('project.create')
|
||||
->with('warning', 'Vous devez tout d\'abord créer un projet pour y ajouter un ticket');
|
||||
}
|
||||
return view('ticket.create', compact('projects'));
|
||||
}
|
||||
|
||||
public function store(Request $request) {
|
||||
$request->validate([
|
||||
'text' => 'required|string',
|
||||
'file_ticket' => 'mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
'file_ticket2' => 'mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
]);
|
||||
public function store(StoreTicket $request)
|
||||
{
|
||||
$project = Project::findOrFail($request->project_id);
|
||||
|
||||
if (Auth::user()->role === 1) {
|
||||
$projectId = $request->project_id;
|
||||
} else {
|
||||
$projectId = Auth::user()->project_id;
|
||||
$ticket = new Ticket($request->validated());
|
||||
|
||||
if ($request->file_ticket) {
|
||||
$ticket->file = Ticket::saveFile($project, $ticket, $ticket->type, $request->file_ticket);
|
||||
}
|
||||
if ($request->file_ticket2) {
|
||||
$ticket->file2 = Ticket::saveFile($project, $ticket, $ticket->type, $request->file_ticket2);
|
||||
}
|
||||
$type = $request->type;
|
||||
$text = $request->text;
|
||||
$fileTicket = $request->file_ticket;
|
||||
$fileTicket2 = $request->file_ticket2;
|
||||
|
||||
$ticket = new Ticket();
|
||||
$ticket->project_id = $projectId;
|
||||
$ticket->type = $type;
|
||||
$ticket->text = $text;
|
||||
$ticket->created_by = Auth::user()->id;
|
||||
$ticket->user()->associate(auth()->user());
|
||||
$ticket->save();
|
||||
|
||||
if ($fileTicket !== null) {
|
||||
$projectSlug = Str::slug(Project::find($projectId)->name);
|
||||
$fileName = $projectSlug . "-" . ($type === "0" ? "bug" : "evo") . "-" . $ticket->id . "." . $fileTicket->extension();
|
||||
$fileTicket->move(public_path('fichiers/' . $projectSlug . "/" . $ticket->id . "/"), $fileName);
|
||||
$filePath = 'fichiers/' . $projectSlug . "/" . $ticket->id . "/" . $fileName;
|
||||
if (config('mail.MAIL_ADMIN')) {
|
||||
Mail::to(config('mail.MAIL_ADMIN'))->send(new NewTicket($ticket));
|
||||
} else {
|
||||
throw new Exception('Missing MAIL_ADMIN in .env');
|
||||
}
|
||||
if ($fileTicket2 !== null) {
|
||||
$projectSlug = Str::slug(Project::find($projectId)->name);
|
||||
$fileName2 = $projectSlug . "-" . ($type === "0" ? "bug" : "evo") . "-" . $ticket->id . "-2." . $fileTicket2->extension();
|
||||
$fileTicket2->move(public_path('fichiers/' . $projectSlug . "/" . $ticket->id . "/"), $fileName2);
|
||||
$filePath2 = 'fichiers/' . $projectSlug . "/" . $ticket->id . "/" . $fileName2;
|
||||
}
|
||||
|
||||
|
||||
if ($fileTicket !== null)
|
||||
$ticket->file = $filePath;
|
||||
|
||||
if ($fileTicket2 !== null)
|
||||
$ticket->file2 = $filePath2;
|
||||
|
||||
if ($fileTicket !== null || $fileTicket2 !== null)
|
||||
$ticket->save();
|
||||
|
||||
|
||||
Mail::to(config('mail.MAIL_ADMIN'))->send(new NewTicket($ticket));
|
||||
|
||||
return redirect()->route('home')->with('success', 'Ticket enregistré !');
|
||||
}
|
||||
|
||||
public function edit($id) {
|
||||
$ticket = Ticket::findOrFail($id);
|
||||
if ($ticket->created_by === Auth::user()->id || Auth::user()->role === 1) {
|
||||
$projects = Project::all();
|
||||
$status = $this->status;
|
||||
return view('ticket.edit', compact('ticket', 'projects', 'status'));
|
||||
}
|
||||
return redirect()->back();
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
public function edit(Ticket $ticket)
|
||||
{
|
||||
$projects = Project::all();
|
||||
return view('ticket.edit', compact('ticket', 'projects'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id) {
|
||||
$request->validate([
|
||||
'text' => 'required|string',
|
||||
'file_ticket' => 'mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
'file_ticket2' => 'mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
]);
|
||||
public function update(UpdateTicket $request, Ticket $ticket)
|
||||
{
|
||||
$project = Project::findOrFail($request->project_id);
|
||||
$ticket->fill($request->validated());
|
||||
|
||||
if (Auth::user()->role === 1) {
|
||||
$projectId = $request->project_id;
|
||||
$status = $request->status;
|
||||
} else {
|
||||
$projectId = Auth::user()->project_id;
|
||||
if ($request->file_ticket) {
|
||||
if (File::exists($ticket->file)) {
|
||||
File::delete($ticket->file);
|
||||
}
|
||||
$ticket->file = Ticket::saveFile($project, $ticket, $ticket->type, $request->file_ticket);
|
||||
}
|
||||
$type = $request->type;
|
||||
$text = $request->text;
|
||||
$fileTicket = $request->file_ticket;
|
||||
$fileTicket2 = $request->file_ticket2;
|
||||
|
||||
$ticket = Ticket::findOrFail($id);
|
||||
|
||||
if ($fileTicket !== null) {
|
||||
if ($ticket->file !== null && file_exists(public_path() . $ticket->file))
|
||||
unlink(public_path() . $ticket->file);
|
||||
$projectSlug = Str::slug(Project::find($projectId)->name);
|
||||
$fileName = $projectSlug . "-" . ($type === "0" ? "bug" : "evo") . "-" . $ticket->id . "." . $fileTicket->extension();
|
||||
$fileTicket->move(public_path('fichiers/' . $projectSlug . "/" . $ticket->id . "/"), $fileName);
|
||||
$filePath = 'fichiers/' . $projectSlug . "/" . $ticket->id . "/" . $fileName;
|
||||
}
|
||||
if ($fileTicket2 !== null) {
|
||||
if ($ticket->file2 !== null && file_exists(public_path() . $ticket->file2))
|
||||
unlink(public_path() . $ticket->file2);
|
||||
$projectSlug = Str::slug(Project::find($projectId)->name);
|
||||
$fileName2 = $projectSlug . "-" . ($type === "0" ? "bug" : "evo") . "-" . $ticket->id . "." . $fileTicket2->extension();
|
||||
$fileTicket2->move(public_path('fichiers/' . $projectSlug . "/" . $ticket->id . "/"), $fileName2);
|
||||
$filePath2 = 'fichiers/' . $projectSlug . "/" . $ticket->id . "/" . $fileName2;
|
||||
}
|
||||
|
||||
$ticket->project_id = $projectId;
|
||||
$ticket->type = $type;
|
||||
$ticket->text = $text;
|
||||
if ($fileTicket !== null)
|
||||
$ticket->file = $filePath;
|
||||
if ($fileTicket2 !== null)
|
||||
$ticket->file2 = $filePath2;
|
||||
if (Auth::user()->role === 1) {
|
||||
$ticket->status = $status;
|
||||
event(new TicketStatusChanged($ticket, $this->status));
|
||||
if ($request->file_ticket2) {
|
||||
if (File::exists($ticket->file2)) {
|
||||
File::delete($ticket->file2);
|
||||
}
|
||||
$ticket->file2 = Ticket::saveFile($project, $ticket, $ticket->type, $request->file_ticket2);
|
||||
}
|
||||
|
||||
$ticket->save();
|
||||
|
||||
return redirect()->route('edit-ticket', $ticket->id)->with('success', 'Modifications enregistrées !');
|
||||
return redirect()->route('ticket.edit', $ticket->id)->with('success', 'Modifications enregistrées !');
|
||||
}
|
||||
|
||||
public function changeStatus(Request $request, $id) {
|
||||
$ticket = Ticket::find($id);
|
||||
if (!$ticket)
|
||||
abort(404);
|
||||
$ticket->status = $request->status;
|
||||
public function changeStatus(ChangeTicketStatus $request, Ticket $ticket)
|
||||
{
|
||||
$ticket->fill($request->validated());
|
||||
$ticket->save();
|
||||
event(new TicketStatusChanged($ticket, $this->status));
|
||||
event(new NotifySubscriptions($ticket, "Le ticket à changé de status : " . $this->status[$ticket->status]));
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
public function createMessage(Request $request) {
|
||||
$request->validate([
|
||||
'message' => 'required',
|
||||
]);
|
||||
|
||||
if ($request->file_message !== null) {
|
||||
$request->validate([
|
||||
'file_message' => 'mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
]);
|
||||
}
|
||||
|
||||
$ticketId = $request->ticket_id;
|
||||
public function createMessage(CreateMessage $request, Ticket $ticket)
|
||||
{
|
||||
$fileMessage = $request->file_message;
|
||||
|
||||
$ticket = Ticket::find($ticketId);
|
||||
|
||||
if (Auth::user()->role !== 1 && (!$ticket || Auth::user()->id !== $ticket->created_by))
|
||||
return back()->withErrors("Les données entrées sont incorrects.");
|
||||
|
||||
$message = new Message();
|
||||
$message->ticket_id = $ticketId;
|
||||
$message->user_id = Auth::user()->id;
|
||||
$message->message = $request->message;
|
||||
$message = new Message($request->validated());
|
||||
$message->user()->associate(auth()->user());
|
||||
$message->ticket()->associate($ticket);
|
||||
$message->save();
|
||||
|
||||
if ($request->file_message !== null) {
|
||||
if ($request->file_message) {
|
||||
$projectSlug = Str::slug($ticket->project->name);
|
||||
$fileMessage = $request->file_message;
|
||||
$fileName = $projectSlug . '-ticket-' . $ticket->id . '-message-' . $message->id . '.' . $fileMessage->extension();
|
||||
|
|
@ -239,13 +165,19 @@ class TicketController extends Controller
|
|||
$message->save();
|
||||
}
|
||||
|
||||
event(new NotifySubscriptions($ticket, "Nouvelle réponse de " . $message->user->name . " :<br>" . $message->message));
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
public function subscribe(Request $request, $id) {
|
||||
User::find(Auth::user()->id)->subscriptions()->toggle($id);
|
||||
public function setToArchive(Ticket $ticket)
|
||||
{
|
||||
$ticket->status = TicketStatus::archived();
|
||||
$ticket->saveOrFail();
|
||||
return redirect()->route('ticket.index');
|
||||
}
|
||||
|
||||
public function subscribe(Ticket $ticket)
|
||||
{
|
||||
User::find(Auth::user()->id)->subscriptions()->toggle($ticket->id);
|
||||
return back();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
31
app/Http/Requests/ChangeTicketStatus.php
Normal file
31
app/Http/Requests/ChangeTicketStatus.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Enums\TicketStatus;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ChangeTicketStatus extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'status' => [
|
||||
'required',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!in_array($value, TicketStatus::toValues())) {
|
||||
$fail(__('Veuillez choisir entre :values', [
|
||||
'value' => implode(',', TicketStatus::toLabels())
|
||||
]));
|
||||
}
|
||||
}
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
21
app/Http/Requests/CreateMessage.php
Normal file
21
app/Http/Requests/CreateMessage.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class CreateMessage extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'message' => 'required|min:10',
|
||||
'file_message' => 'sometimes|mimes:jpeg,jpg,png,pdf|max:2048'
|
||||
];
|
||||
}
|
||||
}
|
||||
42
app/Http/Requests/SortTickets.php
Normal file
42
app/Http/Requests/SortTickets.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Enums\TicketStatus;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class SortTickets extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'sort_way' => 'sometimes|in:asc,desc',
|
||||
'status' => [
|
||||
'sometimes',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!in_array($value, TicketStatus::toValues())) {
|
||||
$fail(__('Veuillez choisir entre :values', [
|
||||
'value' => implode(',', TicketStatus::toLabels())
|
||||
]));
|
||||
}
|
||||
}
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
63
app/Http/Requests/StoreTicket.php
Normal file
63
app/Http/Requests/StoreTicket.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Enums\TicketStatus;
|
||||
use App\Enums\TicketType;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreTicket extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
if (auth()->user()->project_id) {
|
||||
$this->merge([
|
||||
'project_id' => auth()->user()->project_id,
|
||||
'status' => TicketStatus::new()->value,
|
||||
]);
|
||||
}
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'project_id' => 'required|exists:projects,id',
|
||||
'type' => [
|
||||
'required',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!in_array($value, TicketType::toValues())) {
|
||||
$fail(__('Veuillez choisir entre :values', [
|
||||
'value' => implode(',', TicketType::toLabels())
|
||||
]));
|
||||
}
|
||||
}
|
||||
],
|
||||
'status' => [
|
||||
'required',
|
||||
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!in_array($value, TicketStatus::toValues())) {
|
||||
$fail(__('Veuillez choisir entre :values', [
|
||||
'value' => implode(',', TicketStatus::toLabels())
|
||||
]));
|
||||
}
|
||||
}
|
||||
],
|
||||
'text' => 'required|string|min:40',
|
||||
'file_ticket' => 'mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
'file_ticket2' => 'mimes:jpeg,jpg,png,pdf|max:2048',
|
||||
];
|
||||
}
|
||||
}
|
||||
21
app/Http/Requests/UpdateTicket.php
Normal file
21
app/Http/Requests/UpdateTicket.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Enums\TicketStatus;
|
||||
|
||||
class UpdateTicket extends StoreTicket
|
||||
{
|
||||
public function authorize()
|
||||
{
|
||||
if (auth()->user()->project_id) {
|
||||
$this->merge([
|
||||
'project_id' => auth()->user()->project_id,
|
||||
'status' => TicketStatus::new()->value,
|
||||
]);
|
||||
}
|
||||
return auth()->check() or
|
||||
auth()->user()->role === 1 or
|
||||
request()->route()->ticket->created_by === auth()->user()->id;
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ class AddStatusMessages
|
|||
{
|
||||
$message = new Message();
|
||||
$message->ticket_id = $event->ticket->id;
|
||||
$message->message = "Le status est passé à : " . $event->status[$event->ticket->status];
|
||||
$message->message = "Le status est passé à : " . $event->ticket->status->label;
|
||||
$message->save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,16 +12,6 @@ use Illuminate\Support\Facades\Mail;
|
|||
|
||||
class SendNotificationMail
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
|
|
@ -30,8 +20,10 @@ class SendNotificationMail
|
|||
*/
|
||||
public function handle(NotifySubscriptions $event)
|
||||
{
|
||||
foreach($event->ticket->subscriptions as $sub)
|
||||
if ($sub->email !== Auth::user()->email)
|
||||
foreach ($event->ticket->subscriptions as $sub) {
|
||||
if ($sub->email !== Auth::user()->email) {
|
||||
Mail::to($sub->email)->send(new TicketUpdate($event->ticket, $event->corpsMaj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,55 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\TicketType;
|
||||
use App\Events\NotifySubscriptions;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
|
||||
class Message extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public function ticket() {
|
||||
return $this->belongsTo('App\Models\Ticket', 'ticket_id');
|
||||
protected $fillable = [
|
||||
'message'
|
||||
];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::created(function (Message $message) {
|
||||
event(new NotifySubscriptions(
|
||||
$message->ticket,
|
||||
trans('Nouvelle réponse de :name :<br> :message', [
|
||||
'name' => $message->user->name,
|
||||
'message' => $message->message
|
||||
])
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
public function user() {
|
||||
return $this->belongsTo('App\Models\User', 'user_id');
|
||||
public function ticket()
|
||||
{
|
||||
return $this->belongsTo(Ticket::class, 'ticket_id');
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
public function saveFile(Project $project, Ticket $ticket, UploadedFile $file)
|
||||
{
|
||||
$projectAssetFullPath = Project::ticketAssetsFullPath($project->slug_name);
|
||||
$fileAssetPath = Project::ticketAssetsPath($project->slug_name);
|
||||
$fileName = sprintf(
|
||||
'%s-%s-%d-%d.%s',
|
||||
$project->slug_name,
|
||||
$ticket->id,
|
||||
rand(),
|
||||
$file->extension()
|
||||
);
|
||||
$file->move(sprintf('%s/messages/%d', $projectAssetFullPath, $ticket->id), $fileName);
|
||||
return sprintf('%s/%d/%s', $fileAssetPath, $ticket->id, $fileName);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,15 @@ class Project extends Model
|
|||
protected static function booted()
|
||||
{
|
||||
static::created(function (Project $project) {
|
||||
$path = Project::ticketAssetsPath($project->slug_name);
|
||||
$path = Project::ticketAssetsFullPath($project->slug_name);
|
||||
if (!File::exists($path)) {
|
||||
File::makeDirectory($path);
|
||||
}
|
||||
});
|
||||
static::updating(function (Project $project) {
|
||||
$oldName = Project::where('id', $project->id)->first()->name;
|
||||
$oldPath = Project::ticketAssetsPath($oldName);
|
||||
$newPath = Project::ticketAssetsPath($project->slug_name);
|
||||
$oldPath = Project::ticketAssetsFullPath($oldName);
|
||||
$newPath = Project::ticketAssetsFullPath($project->slug_name);
|
||||
if (File::exists($oldPath)) {
|
||||
File::move($oldPath, $newPath);
|
||||
} else {
|
||||
|
|
@ -32,7 +32,7 @@ class Project extends Model
|
|||
}
|
||||
});
|
||||
static::deleted(function (Project $project) {
|
||||
$path = Project::ticketAssetsPath($project->slug_name);
|
||||
$path = Project::ticketAssetsFullPath($project->slug_name);
|
||||
if (File::exists($path)) {
|
||||
File::deleteDirectory($path);
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ class Project extends Model
|
|||
|
||||
public function tickets()
|
||||
{
|
||||
return $this->hasMany('App\Models\Ticket', 'project_id');
|
||||
return $this->hasMany(Ticket::class, 'project_id');
|
||||
}
|
||||
|
||||
public function getSlugNameAttribute()
|
||||
|
|
@ -49,8 +49,13 @@ class Project extends Model
|
|||
return Str::slug($this->name);
|
||||
}
|
||||
|
||||
protected static function ticketAssetsPath(string $str)
|
||||
public static function ticketAssetsFullPath(string $str)
|
||||
{
|
||||
return public_path(sprintf('fichiers/%s', $str));
|
||||
return public_path(self::ticketAssetsPath($str));
|
||||
}
|
||||
|
||||
public static function ticketAssetsPath(string $str)
|
||||
{
|
||||
return sprintf('fichiers/%s', $str);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,26 +2,79 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\TicketStatus;
|
||||
use App\Enums\TicketType;
|
||||
use App\Events\NotifySubscriptions;
|
||||
use App\Events\TicketStatusChanged;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Kwaadpepper\Enum\Traits\CastsEnums;
|
||||
|
||||
class Ticket extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use CastsEnums;
|
||||
|
||||
public function project() {
|
||||
return $this->belongsTo('App\Models\Project', 'project_id');
|
||||
protected $enumCasts = [
|
||||
'type' => TicketType::class,
|
||||
'status' => TicketStatus::class
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'project_id',
|
||||
'type',
|
||||
'status',
|
||||
'text'
|
||||
];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::updating(function (Ticket $ticket) {
|
||||
$oldStatus = Ticket::where('id', $ticket->id)->first()->status;
|
||||
if (!$ticket->status->equals($oldStatus)) {
|
||||
event(new TicketStatusChanged($ticket, $oldStatus));
|
||||
event(new NotifySubscriptions($ticket, sprintf(
|
||||
'Le ticket à changé de status : %s',
|
||||
$ticket->status->label
|
||||
)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function user() {
|
||||
return $this->belongsTo('App\Models\User', 'created_by');
|
||||
public function project()
|
||||
{
|
||||
return $this->belongsTo(Project::class);
|
||||
}
|
||||
|
||||
public function messages() {
|
||||
return $this->hasMany('App\Models\Message', 'ticket_id');
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'created_by');
|
||||
}
|
||||
|
||||
public function subscriptions() {
|
||||
return $this->belongsToMany('App\Models\User', 'subscriptions');
|
||||
public function messages()
|
||||
{
|
||||
return $this->hasMany(Message::class, 'ticket_id');
|
||||
}
|
||||
|
||||
public function subscriptions()
|
||||
{
|
||||
return $this->belongsToMany(User::class, 'subscriptions');
|
||||
}
|
||||
|
||||
public static function saveFile(Project $project, Ticket $ticket, TicketType $type, UploadedFile $file)
|
||||
{
|
||||
$projectAssetFullPath = Project::ticketAssetsFullPath($project->slug_name);
|
||||
$fileAssetPath = Project::ticketAssetsPath($project->slug_name);
|
||||
$fileName = sprintf(
|
||||
'%s-%s-%d-%d.%s',
|
||||
$project->slug_name,
|
||||
$type->getDefinition(),
|
||||
$ticket->id,
|
||||
rand(),
|
||||
$file->extension()
|
||||
);
|
||||
$file->move(sprintf('%s/%d', $projectAssetFullPath, $ticket->id), $fileName);
|
||||
return sprintf('%s/%d/%s', $fileAssetPath, $ticket->id, $fileName);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasFactory, Notifiable;
|
||||
use HasFactory;
|
||||
use Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
|
@ -41,15 +41,23 @@ class User extends Authenticatable
|
|||
'email_verified_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function tickets() {
|
||||
return $this->hasMany("App\Models\Ticket", 'created_by');
|
||||
public function tickets()
|
||||
{
|
||||
return $this->hasMany(Ticket::class, 'created_by');
|
||||
}
|
||||
|
||||
public function messages() {
|
||||
return $this->hasMany('App\Models\Messages', 'user_id');
|
||||
public function messages()
|
||||
{
|
||||
return $this->hasMany(Messages::class, 'user_id');
|
||||
}
|
||||
|
||||
public function subscriptions() {
|
||||
return $this->belongsToMany('App\Models\Ticket', 'subscriptions');
|
||||
public function subscriptions()
|
||||
{
|
||||
return $this->belongsToMany(Ticket::class, 'subscriptions');
|
||||
}
|
||||
|
||||
public function project()
|
||||
{
|
||||
return $this->belongsTo(Project::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
99
app/Policies/ProjectPolicy.php
Normal file
99
app/Policies/ProjectPolicy.php
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Project;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class ProjectPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function viewAny(User $user)
|
||||
{
|
||||
return $user->role === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Project $project
|
||||
* @return mixed
|
||||
*/
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
public function view(User $user, Project $project)
|
||||
{
|
||||
return $user->role === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function create(User $user)
|
||||
{
|
||||
return $user->role === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Project $project
|
||||
* @return mixed
|
||||
*/
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
public function update(User $user, Project $project)
|
||||
{
|
||||
return $user->role === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Project $project
|
||||
* @return mixed
|
||||
*/
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
public function delete(User $user, Project $project)
|
||||
{
|
||||
return $user->role === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Project $project
|
||||
* @return mixed
|
||||
*/
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
public function restore(User $user, Project $project)
|
||||
{
|
||||
return $user->role === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Project $project
|
||||
* @return mixed
|
||||
*/
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
public function forceDelete(User $user, Project $project)
|
||||
{
|
||||
return $user->role === 1;
|
||||
}
|
||||
}
|
||||
123
app/Policies/TicketPolicy.php
Normal file
123
app/Policies/TicketPolicy.php
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Enums\TicketStatus;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class TicketPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
|
||||
public function viewAny(User $user)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
public function view(User $user, Ticket $ticket)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
|
||||
public function create(User $user)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function update(User $user, Ticket $ticket)
|
||||
{
|
||||
return Auth::user()->role === 1 or $ticket->created_by == $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
public function delete(User $user, Ticket $ticket)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function restore(User $user, Ticket $ticket)
|
||||
{
|
||||
return Auth::user()->role === 1 or $ticket->created_by == $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @param \App\Models\Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
|
||||
public function forceDelete(User $user, Ticket $ticket)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function changeStatus(User $user)
|
||||
{
|
||||
return $user->role === 1;
|
||||
}
|
||||
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
public function suscribeToTicket(User $user, Ticket $ticket)
|
||||
{
|
||||
return !$ticket->status->equals(TicketStatus::archived());
|
||||
}
|
||||
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
public function createMessage(User $user, Ticket $ticket)
|
||||
{
|
||||
if ($user->role !== 1 and $ticket->created_by !== $user->id) {
|
||||
return Response::deny(trans('Vous ne pouvez modifier un ticket qui ne vous appartient pas.'));
|
||||
}
|
||||
return $ticket->status->equals(TicketStatus::archived()) ?
|
||||
Response::deny(trans('Vous ne pouvez ajouter un message à un ticket qui est archivé')) : Response::allow();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,18 +2,22 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use App\Policies\ProjectPolicy;
|
||||
use App\Policies\TicketPolicy;
|
||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
||||
/**
|
||||
* The policy mappings for the application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $policies = [
|
||||
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
|
||||
Project::class => ProjectPolicy::class,
|
||||
Ticket::class => TicketPolicy::class
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -226,7 +226,8 @@ return [
|
|||
'URL' => Illuminate\Support\Facades\URL::class,
|
||||
'Validator' => Illuminate\Support\Facades\Validator::class,
|
||||
'View' => Illuminate\Support\Facades\View::class,
|
||||
|
||||
'TicketType' => App\Enums\TicketType::class,
|
||||
'TicketStatus' => App\Enums\TicketStatus::class
|
||||
],
|
||||
|
||||
];
|
||||
|
|
|
|||
0
resources/css/app.css
vendored
0
resources/css/app.css
vendored
10
resources/sass/app.scss
vendored
10
resources/sass/app.scss
vendored
|
|
@ -6,3 +6,13 @@
|
|||
|
||||
// Bootstrap
|
||||
@import '~bootstrap/scss/bootstrap';
|
||||
|
||||
a.col_sort {
|
||||
&:link,:visited,:hover,:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.container-xxl {
|
||||
max-width: 1340px !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,114 +1,8 @@
|
|||
@extends('layout.app')
|
||||
|
||||
@section('tickets', 'active')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
@auth
|
||||
<h2>Gestion des tickets<a href="{{ route('create-ticket') }}" class="float-right btn btn-sm btn-primary">Créer un ticket</a></h2>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<th scope="col">
|
||||
#
|
||||
@include('modules.sorter', ['colname' => 'id'])
|
||||
</th>
|
||||
<th scope="col">
|
||||
Projet
|
||||
@include('modules.sorter', ['colname' => 'project'])
|
||||
</th>
|
||||
<th scope="col">
|
||||
Type
|
||||
@include('modules.sorter', ['colname' => 'type'])</th>
|
||||
<th scope="col">Fichier</th>
|
||||
<th scope="col">Fichier 2</th>
|
||||
<th scope="col">
|
||||
Date de création
|
||||
@include('modules.sorter', ['colname' => 'created_at'])</th>
|
||||
<th scope="col">
|
||||
Créé par
|
||||
@include('modules.sorter', ['colname' => 'created_by'])</th>
|
||||
<th scope="col">
|
||||
Status
|
||||
@include('modules.sorter', ['colname' => 'status'])
|
||||
</th>
|
||||
<th scope="col">Contenu</th>
|
||||
@if (Auth::user()->role === 1)
|
||||
<th></th>
|
||||
@endif
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($tickets as $ticket)
|
||||
@if (Auth::user()->project_id === $ticket->project->id || Auth::user()->role === 1)
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<a href="{{ route('show-ticket', $ticket->id) }}" class="btn btn-sm btn-outline-secondary">{{ $ticket->id }}</a>
|
||||
</th>
|
||||
<td>{{ $ticket->project->name }}</td>
|
||||
<td>
|
||||
@if ($ticket->type === 0)
|
||||
<span class="badge badge-danger">Bug</span>
|
||||
@else
|
||||
<span class="badge badge-success">Évolution</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if ($ticket->file !== null)
|
||||
<a href="{{ asset($ticket->file) }}"
|
||||
class="btn btn-sm btn-outline-secondary" target="_blank">Fichier</a>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if ($ticket->file2 !== null)
|
||||
<a href="{{ asset($ticket->file2) }}"
|
||||
class="btn btn-sm btn-outline-secondary" target="_blank">Fichier 2</a>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ Carbon\Carbon::parse($ticket->created_at)->format('d/m/Y à H:i') }}</td>
|
||||
<td>{{ $ticket->user->name }}</td>
|
||||
<td>{{ $status[$ticket->status] }}</td>
|
||||
<td>
|
||||
{{-- Modal du ticket --}}
|
||||
<!-- Button trigger modal -->
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" data-toggle="modal" data-target="#ticket{{ $ticket->id }}Modal">
|
||||
Aperçu
|
||||
</button>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="ticket{{ $ticket->id }}Modal" tabindex="-1" aria-labelledby="ticket{{ $ticket->id }}ModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="ticket{{ $ticket->id }}ModalLabel">
|
||||
{{ $ticket->project->name }} - Ticket N°{{ $ticket->id }} - {{ $ticket->type === 0 ? "Bug" : "Évolution" }}
|
||||
</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{!! nl2br(e($ticket->text)) !!}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-sm btn-primary" data-dismiss="modal">Fermer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
@if (Auth::user()->role === 1)
|
||||
<a href="{{ route('edit-ticket', $ticket->id) }}" class="btn btn-sm btn-outline-primary">Modifier</a>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
{{ $tickets->withQueryString()->links() }}
|
||||
@else
|
||||
<h2>Bienvenue sur le support LDC WEB.</h2>
|
||||
<p>Pour consulter vos tickets, merci de vous connecter : <a href="{{ route('login') }}">Connexion</a></p>
|
||||
@endauth
|
||||
</div>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -12,14 +12,18 @@
|
|||
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ url('/') }}">
|
||||
@if(auth()->user()->project)
|
||||
Projet : <b class="text-primary">{{ ucwords(auth()->user()->project->name) }}</b>
|
||||
@else
|
||||
{{ config('app.name', 'Laravel') }}
|
||||
@endif
|
||||
</a>
|
||||
@auth
|
||||
@if (Auth::user()->role === 1)
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @yield('tickets')" href="{{ route('home') }}">Tickets</a>
|
||||
<a class="nav-link @yield('tickets')" href="{{ route('ticket.index') }}">Tickets</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @yield('project')" href="{{ route('project.index') }}">Projets</a>
|
||||
|
|
@ -50,8 +54,8 @@
|
|||
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
|
||||
<a class="dropdown-item" href="#"
|
||||
onclick="event.preventDefault();
|
||||
document.getElementById('logout-form').submit();">
|
||||
onclick="event.preventDefault();
|
||||
document.getElementById('logout-form').submit();">
|
||||
Déconnexion
|
||||
</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@
|
|||
Description :<br>
|
||||
{!! nl2br(e($ticket->text)) !!}
|
||||
</p>
|
||||
<p>Lien vers le ticket : <a href="{{ route('show-ticket', $ticket->id) }}" traget="_blank">Ouvrir dans un nouvel onglet</a></p>
|
||||
<p>Lien vers le ticket : <a href="{{ route('ticket.show', $ticket->id) }}" traget="_blank">Ouvrir dans un nouvel onglet</a></p>
|
||||
|
|
|
|||
|
|
@ -6,4 +6,4 @@
|
|||
<li>Créer par : {{ $ticket->user->name }}</li>
|
||||
</ul>
|
||||
<p>{!! $corpsMaj !!}</p>
|
||||
<p>Lien vers le ticket : <a href="{{ route('show-ticket', $ticket->id) }}" target="_blank">Ouvrir dans un nouvel onglet</a></p>
|
||||
<p>Lien vers le ticket : <a href="{{ route('ticket.show', $ticket->id) }}" target="_blank">Ouvrir dans un nouvel onglet</a></p>
|
||||
|
|
|
|||
|
|
@ -7,3 +7,8 @@
|
|||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
@if(session('warning'))
|
||||
<div class="alert alert-warning">
|
||||
{{ session('warning') }}
|
||||
</div>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@if(!request('sort_way') or request('sort_col') !== $colname or (request('sort_way') === 'desc' and request('sort_col') === $colname))
|
||||
<a class="col_sort asc" href="{{ route('home', ['sort_col' => $colname, 'sort_way' => 'asc']) }}">↓</a>
|
||||
<a class="col_sort text-secondary lead asc" href="{{ route('ticket.index', ['sort_col' => $colname, 'sort_way' => 'asc']) }}"> ↓ </a>
|
||||
@endif
|
||||
@if(!request('sort_way') or request('sort_col') !== $colname or (request('sort_way') === 'asc' and request('sort_col') === $colname))
|
||||
<a class="col_sort desc" href="{{ route('home', ['sort_col' => $colname, 'sort_way' => 'desc']) }}">↑</a>
|
||||
<a class="col_sort text-secondary lead desc" href="{{ route('ticket.index', ['sort_col' => $colname, 'sort_way' => 'desc']) }}"> ↑ </a>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -11,11 +11,8 @@
|
|||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('project.store') }}">
|
||||
@csrf
|
||||
@include('modules.error-messages')
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="name" placeholder="Nom du projet *" value="{{ old('name') }}">
|
||||
</div>
|
||||
@include('project.form-inputs')
|
||||
|
||||
<div class="form-group text-center">
|
||||
<input type="submit" class="btn btn-primary" value="Enregistrer">
|
||||
|
|
|
|||
|
|
@ -12,16 +12,13 @@
|
|||
<form method="POST" action="{{ route('project.update', $project->id) }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
@include('modules.error-messages')
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">
|
||||
{!! session('success') !!}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="name" placeholder="Nom du projet *" value="{{ $project->name }}">
|
||||
</div>
|
||||
@include('project.form-inputs')
|
||||
|
||||
<div class="form-group text-center">
|
||||
<input type="submit" class="btn btn-primary" value="Modifier">
|
||||
|
|
|
|||
4
resources/views/project/form-inputs.blade.php
Normal file
4
resources/views/project/form-inputs.blade.php
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
@include('modules.error-messages')
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="name" placeholder="Nom du projet *" value="{{ old('name') ?? $project->name }}">
|
||||
</div>
|
||||
|
|
@ -9,44 +9,10 @@
|
|||
<div class="card">
|
||||
<div class="card-header">Créer un ticket<a href="{{ route('home') }}" class="float-right btn btn-sm btn-primary">Retour</a></div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('store-ticket') }}" enctype="multipart/form-data">
|
||||
@method('PUT')
|
||||
<form method="POST" action="{{ route('ticket.store') }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@include('modules.error-messages')
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="project" class="col-form-label">Projet</label>
|
||||
<select class="custom-select" name="project_id" id="project" @if (Auth::user()->role !== 1) disabled @endif>
|
||||
@foreach($projects as $project)
|
||||
@if (Auth::user()->role === 1)
|
||||
<option value="{{ $project->id }}" @if (old('project_id') == $project->id)selected @endif>{{ $project->name }}</option>
|
||||
@elseif ($project->id === Auth::user()->project_id)
|
||||
<option value="{{ $project->id }}" selected>{{ $project->name }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="type" class="col-form-label">Type</label>
|
||||
<select class="custom-select" name="type" id="type">
|
||||
<option value="0" @if (old('type') == 0)selected @endif>Bug</option>
|
||||
<option value="1" @if (old('type') == 1)selected @endif>Évolution</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="text" class="col-form-label text-md-right">Description</label>
|
||||
<textarea class="form-control" name="text" id="text" placeholder="Description du ticket *">{{ old('text') }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="file" name="file_ticket" accept="image/png, image/jpeg, image/jpg, .pdf">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="file" name="file_ticket2" accept="image/png, image/jpeg, image/jpg, .pdf">
|
||||
</div>
|
||||
@include('ticket.form-inputs')
|
||||
|
||||
<div class="form-group text-center">
|
||||
<input type="submit" class="btn btn-primary" value="Enregistrer">
|
||||
|
|
|
|||
|
|
@ -9,73 +9,14 @@
|
|||
<div class="card">
|
||||
<div class="card-header">Modifier un ticket<a href="{{ route('home') }}" class="float-right btn btn-sm btn-primary">Retour</a></div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('update-ticket', $ticket->id) }}" enctype="multipart/form-data">
|
||||
<form method="POST" action="{{ route('ticket.update', $ticket->id) }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@include('modules.error-messages')
|
||||
@method('PUT')
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">{!! session('success') !!}</div>
|
||||
<div class="alert alert-success">{!! session('success') !!}</div>
|
||||
@endif
|
||||
<div class="form-row">
|
||||
<div class="form-group col">
|
||||
<label for="project" class="col-form-label">Projet</label>
|
||||
<select class="custom-select" name="project_id" id="project" @if (Auth::user()->role !== 1) disabled @endif>
|
||||
@foreach($projects as $project)
|
||||
@if (Auth::user()->role === 1)
|
||||
<option value="{{ $project->id }}" @if ($ticket->project->id == $project->id)selected @endif>{{ $project->name }}</option>
|
||||
@elseif ($project->id === Auth::user()->project_id)
|
||||
<option value="{{ $project->id }}" selected>{{ $project->name }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col">
|
||||
<label for="type" class="col-form-label">Type</label>
|
||||
<select class="custom-select" name="type" id="type">
|
||||
<option value="0" @if ($ticket->type == 0)selected @endif>Bug</option>
|
||||
<option value="1" @if ($ticket->type == 1)selected @endif>Évolution</option>
|
||||
</select>
|
||||
</div>
|
||||
@if (Auth::user()->role === 1)
|
||||
<div class="form-group col">
|
||||
<label for="status" class="col-form-label">Status</label>
|
||||
<select class="custom-select" name="status" id="status">
|
||||
@for ($i = 1; $i < count($status) + 1; $i++)
|
||||
<option value="{{ $i }}" @if ($ticket->status === $i) selected @endif>{{ $status[$i] }}</option>
|
||||
@endfor
|
||||
</select>
|
||||
</div>
|
||||
@else
|
||||
<div class="col">
|
||||
<p>Status</p>
|
||||
<p>{{ $status[$ticket->status] }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="text" class="col-form-label text-md-right">Description</label>
|
||||
<textarea class="form-control" name="text" id="text" placeholder="Description du ticket *">{{ $ticket->text }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="file" name="file_ticket" accept="image/png, image/jpeg, image/jpg, .pdf">
|
||||
@if ($ticket->file !== null)
|
||||
<hr>
|
||||
<div class="text-center">
|
||||
<img src="{{ asset($ticket->file) }}" style="max-width: 100%;">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="file" name="file_ticket2" accept="image/png, image/jpeg, image/jpg, .pdf">
|
||||
@if ($ticket->file2 !== null)
|
||||
<hr>
|
||||
<div class="text-center">
|
||||
<img src="{{ asset($ticket->file2) }}" style="max-width: 100%;">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@include('ticket.form-inputs')
|
||||
|
||||
<div class="form-group text-center">
|
||||
<input type="submit" class="btn btn-primary" value="Modifier">
|
||||
|
|
|
|||
60
resources/views/ticket/form-inputs.blade.php
Normal file
60
resources/views/ticket/form-inputs.blade.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
@include('modules.error-messages')
|
||||
<div class="form-row">
|
||||
@can('changeStatus')
|
||||
<div class="form-group col">
|
||||
<label for="project" class="col-form-label">{{ __('Projet') }}</label>
|
||||
<select class="custom-select" name="project_id" id="project" @if (Auth::user()->role !== 1) disabled @endif>
|
||||
@foreach($projects as $project)
|
||||
@if (Auth::user()->role === 1)
|
||||
<option value="{{ $project->id }}" @if ($project->id == old('project_id') or (isset($ticket) and $ticket->project->id == $project->id))selected @endif>{{ $project->name }}</option>
|
||||
@elseif ($project->id === Auth::user()->project_id)
|
||||
<option value="{{ $project->id }}" selected>{{ $project->name }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
@endcan
|
||||
<div class="form-group col">
|
||||
<label for="type" class="col-form-label">{{ __('Type') }}</label>
|
||||
<select class="custom-select" name="type" id="type">
|
||||
@foreach(TicketType::toArray() as $ticketType)
|
||||
<option value="{{ $ticketType->value }}" @if($ticketType->value == old('type') or (isset($ticket) and $ticketType->equals($ticket->type)))selected @endif>{{ $ticketType->label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
@can('changeStatus')
|
||||
<div class="form-group col">
|
||||
<label for="status" class="col-form-label">Status</label>
|
||||
<select class="custom-select" name="status" id="status">
|
||||
@foreach(TicketStatus::toArray() as $ticketStatus)
|
||||
<option value="{{ $ticketStatus->value }}" @if($ticketType->value == old('status') or (isset($ticket) and $ticketStatus->equals($ticket->status)))selected @endif>{{ $ticketStatus->label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
@endcan
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="text" class="col-form-label text-md-right">{{ __('Description') }}</label>
|
||||
<textarea class="form-control" name="text" id="text" placeholder="{{ __('Description du ticket') }} *">{{ old('text') ?? $ticket->text ?? ''}}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="file" name="file_ticket" accept="image/png, image/jpeg, image/jpg, .pdf">
|
||||
@if (isset($ticket) and $ticket->file !== null)
|
||||
<hr>
|
||||
<div class="text-center">
|
||||
<img src="{{ asset($ticket->file) }}" style="max-width: 100%;">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="file" name="file_ticket2" accept="image/png, image/jpeg, image/jpg, .pdf">
|
||||
@if (isset($ticket) and $ticket->file2 !== null)
|
||||
<hr>
|
||||
<div class="text-center">
|
||||
<img src="{{ asset($ticket->file2) }}" style="max-width: 100%;">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
125
resources/views/ticket/index.blade.php
Normal file
125
resources/views/ticket/index.blade.php
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
@extends('layout.app')
|
||||
|
||||
@section('tickets', 'active')
|
||||
|
||||
@section('content')
|
||||
<div class="container container-xxl">
|
||||
<h2>
|
||||
Gestion des tickets @if(request()->status) (Archivés) @endif
|
||||
<a href="{{ route('ticket.create') }}" class="float-right btn btn-sm btn-primary">Créer un ticket</a>
|
||||
@if(request()->status)
|
||||
<a href="{{ route('ticket.index') }}" class="float-right btn btn-sm btn-success mr-2">Tickets en cours</a>
|
||||
@else
|
||||
<a href="{{ route('ticket.index', ['status' => TicketStatus::archived()]) }}" class="float-right btn btn-sm btn-secondary mr-2">Tickets Archivés</a>
|
||||
@endif
|
||||
</h2>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<th scope="col">
|
||||
#
|
||||
@include('modules.sorter', ['colname' => 'id'])
|
||||
</th>
|
||||
<th scope="col">
|
||||
Projet
|
||||
@include('modules.sorter', ['colname' => 'project'])
|
||||
</th>
|
||||
<th scope="col">
|
||||
Type
|
||||
@include('modules.sorter', ['colname' => 'type'])</th>
|
||||
<th scope="col">Fichier</th>
|
||||
<th scope="col">Fichier 2</th>
|
||||
<th scope="col">
|
||||
Date de création
|
||||
@include('modules.sorter', ['colname' => 'created_at'])</th>
|
||||
<th scope="col">
|
||||
Créé par
|
||||
@include('modules.sorter', ['colname' => 'created_by'])</th>
|
||||
<th scope="col">
|
||||
Statut
|
||||
@include('modules.sorter', ['colname' => 'status'])
|
||||
</th>
|
||||
<th scope="col">Contenu</th>
|
||||
@if (Auth::user()->role === 1)
|
||||
<th>Actions</th>
|
||||
@endif
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($tickets as $ticket)
|
||||
<tr>
|
||||
<th scope="row">
|
||||
{{ $ticket->id }}
|
||||
</th>
|
||||
<td>{{ $ticket->project->name }}</td>
|
||||
<td>
|
||||
@if ($ticket->type->equals(TicketType::bug()))
|
||||
<span class="badge badge-danger">{{ $ticket->type->label }}</span>
|
||||
@else
|
||||
<span class="badge badge-success">{{ $ticket->type->label }}</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if ($ticket->file !== null)
|
||||
<a href="{{ asset($ticket->file) }}"
|
||||
class="btn btn-sm btn-outline-secondary" target="_blank">Fichier</a>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if ($ticket->file2 !== null)
|
||||
<a href="{{ asset($ticket->file2) }}"
|
||||
class="btn btn-sm btn-outline-secondary" target="_blank">Fichier 2</a>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ Carbon\Carbon::parse($ticket->created_at)->format('d/m/Y à H:i') }}</td>
|
||||
<td>{{ $ticket->user->name }}</td>
|
||||
<td>{{ $ticket->status->label }}</td>
|
||||
<td>
|
||||
{{-- Modal du ticket --}}
|
||||
<!-- Button trigger modal -->
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" data-toggle="modal" data-target="#ticket{{ $ticket->id }}Modal">
|
||||
Aperçu
|
||||
</button>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="ticket{{ $ticket->id }}Modal" tabindex="-1" aria-labelledby="ticket{{ $ticket->id }}ModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="ticket{{ $ticket->id }}ModalLabel">
|
||||
{{ $ticket->project->name }} - Ticket N°{{ $ticket->id }} - {{ $ticket->type === 0 ? "Bug" : "Évolution" }}
|
||||
</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{!! nl2br(e($ticket->text)) !!}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-sm btn-primary" data-dismiss="modal">Fermer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('ticket.show', $ticket->id) }}" class="btn btn-sm btn-outline-secondary">{{ __('Messages') }}</a>
|
||||
@can('update', $ticket)
|
||||
<a href="{{ route('ticket.edit', $ticket) }}" class="btn btn-sm btn-outline-primary">Modifier</a>
|
||||
@endcan
|
||||
@can('delete', $ticket)
|
||||
@if(!$ticket->status->equals(TicketStatus::archived()))
|
||||
<form method="POST" action="{{ route('ticket.archive', $ticket) }}">
|
||||
@method('PUT')
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('Êtes-vous sûr(e) ?')">Archiver</button>
|
||||
</form>
|
||||
@endif
|
||||
@endcan
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
{{ $tickets->withQueryString()->links() }}
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -3,30 +3,32 @@
|
|||
@section('content')
|
||||
<div class="container">
|
||||
<div class="form-row">
|
||||
<h2 class="@if (Auth::user()->role === 1)col-md-8 @else col-md-10 @endif">
|
||||
<h2 class="@can('suscribeToTicket', $ticket)col-md-8 @else col-md-10 @endcan">
|
||||
<a href="{{ route('home') }}" class="text-decoration-none">←</a>
|
||||
Ticket n°{{ $ticket->id }} : {{ $ticket->project->name }} - {{ $ticket->type === 0 ? "Bug" : "Évolution" }}
|
||||
@if (Auth::user()->role !== 1)
|
||||
<span class="badge badge-secondary">{{ $status[$ticket->status] }}</span>
|
||||
@endif
|
||||
Ticket n°{{ $ticket->id }} : {{ $ticket->project->name }} - {{ $ticket->type->label }}
|
||||
@cannot('createMessage', $ticket)
|
||||
<span class="badge badge-secondary">{{ $ticket->status->label }}</span>
|
||||
@endcan
|
||||
</h2>
|
||||
<form action="{{ route('subscribe-ticket', $ticket->id) }}" method="POST" id="form_abonnement" class="col-md-2">
|
||||
@can('suscribeToTicket', $ticket)
|
||||
<form action="{{ route('ticket.subscribe', $ticket->id) }}" method="POST" id="form_abonnement" class="col">
|
||||
@csrf
|
||||
<div class="custom-control custom-checkbox text-right p-2">
|
||||
<input type="checkbox" name="subscription" class="custom-control-input" id="subscription" @if ($isSubscribed)checked @endif onchange="$('#form_abonnement').submit()">
|
||||
<label class="custom-control-label" for="subscription">Suivre le ticket</label>
|
||||
</div>
|
||||
</form>
|
||||
@if (Auth::user()->role === 1)
|
||||
<form action="{{ route('change-status-ticket', $ticket->id) }}" method="POST" id="form_status" class="col-md-2">
|
||||
@endcan
|
||||
@can('changeStatus', $ticket)
|
||||
<form action="{{ route('ticket.changeStatus', $ticket->id) }}" method="POST" id="form_status" class="col">
|
||||
@csrf
|
||||
<select class="custom-select" name="status" id="status" onchange="$('#form_status').submit();">
|
||||
@for ($i = 1; $i < count($status) + 1; $i++)
|
||||
<option value="{{ $i }}" @if ($ticket->status === $i) selected @endif>{{ $status[$i] }}</option>
|
||||
@endfor
|
||||
@foreach(TicketStatus::toArray() as $ticketStatus)
|
||||
<option value="{{ $ticketStatus->value }}" @if($ticketStatus->equals($ticket->status))selected @endif>{{ $ticketStatus->label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</form>
|
||||
@endif
|
||||
@endcan
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
|
|
@ -41,16 +43,14 @@
|
|||
@endif
|
||||
<h4>
|
||||
Suivi
|
||||
@if (Auth::user()->id === $ticket->created_by || Auth::user()->role === 1)
|
||||
@can('createMessage', $ticket)
|
||||
<button type="button" class="btn btn-sm btn-primary float-right" data-toggle="modal" data-target="#messageModal">
|
||||
Répondre
|
||||
</button>
|
||||
|
||||
{{-- Modal --}}
|
||||
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<form action="{{ route('create-message') }}" method="POST" enctype="multipart/form-data">
|
||||
<form action="{{ route('ticket.message.create', $ticket) }}" method="POST" enctype="multipart/form-data">
|
||||
@method('PUT')
|
||||
@csrf
|
||||
<input type="hidden" name="ticket_id" value="{{ $ticket->id }}">
|
||||
|
|
@ -74,8 +74,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{-- Fin modal --}}
|
||||
@endif
|
||||
@endcan
|
||||
</h4>
|
||||
@foreach ($messages as $message)
|
||||
@if ($message->user_id === null)
|
||||
|
|
|
|||
|
|
@ -16,20 +16,32 @@ use Illuminate\Support\Facades\Route;
|
|||
|
|
||||
*/
|
||||
|
||||
Route::get('/', [TicketController::class, 'index'])->name("home");
|
||||
Route::get('/', function () {
|
||||
if (auth()->check()) {
|
||||
return redirect()->route('ticket.index');
|
||||
}
|
||||
return view('home');
|
||||
})->name("home");
|
||||
Route::get('/login', [LoginController::class, 'index'])->name('login');
|
||||
Route::post('/login', [LoginController::class, 'authenticate'])->name('authenticate');
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::post('/logout', [LoginController::class, 'logout'])->name('logout');
|
||||
// Ticket
|
||||
Route::get('/ticket/create', [TicketController::class, 'create'])->name('create-ticket');
|
||||
Route::put('/ticket/create', [TicketController::class, 'store'])->name('store-ticket');
|
||||
Route::get('/ticket/{id}/edit', [TicketController::class, 'edit'])->name('edit-ticket');
|
||||
Route::post('/ticket/{id}/edit', [TicketController::class, 'update'])->name('update-ticket');
|
||||
Route::get('/ticket/{id}', [TicketController::class, 'show'])->name('show-ticket');
|
||||
Route::post('/ticket/change-status/{id}', [TicketController::class, 'changeStatus'])->name('change-status-ticket');
|
||||
Route::put('/ticket/message/create', [TicketController::class, 'createMessage'])->name('create-message');
|
||||
Route::post('/ticket/subscribe/{id}', [TicketController::class, 'subscribe'])->name('subscribe-ticket');
|
||||
Route::resource('ticket', TicketController::class)->except(['destroy']);
|
||||
Route::prefix('/ticket')->name('ticket.')->group(function () {
|
||||
Route::post('/{ticket}/status', [TicketController::class, 'changeStatus'])
|
||||
->middleware('can:changeStatus,ticket')
|
||||
->name('changeStatus');
|
||||
Route::post('/{ticket}/subscribe', [TicketController::class, 'subscribe'])
|
||||
->middleware('can:suscribeToTicket,ticket')
|
||||
->name('subscribe');
|
||||
Route::put('/{ticket}/archive', [TicketController::class, 'setToArchive'])
|
||||
->middleware('can:changeStatus,ticket')
|
||||
->name('archive');
|
||||
Route::put('/{ticket}/message/create', [TicketController::class, 'createMessage'])
|
||||
->middleware('can:createMessage,ticket')
|
||||
->name('message.create');
|
||||
});
|
||||
// Projets
|
||||
Route::middleware(['is-admin'])->group(function () {
|
||||
Route::resource('project', ProjectController::class)->except('show');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue