7d52c1e440
CI - Intégration continue / quality-and-tests (pull_request) Successful in 3m27s
Le formulaire 'fire-and-forget' devient un vrai systeme de suivi : - table locale tickets (user <-> numero d'issue Gitea) - liste 'Mes tickets' avec etat (En cours / Resolu) et jalon - page de suivi : etat, labels, jalon, fil de discussion (commentaires) - reponse depuis le web (ajoute un commentaire sur l'issue Gitea) - controle d'acces : un utilisateur ne voit que ses propres tickets - GiteaIssueService etendu (getIssue, getComments, addComment) - remplace l'ancien SuggestionController ; 5 tests de bout en bout Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
132 lines
4.1 KiB
PHP
132 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Web;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Ticket;
|
|
use App\Models\User;
|
|
use App\Services\GiteaIssueService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class TicketController extends Controller
|
|
{
|
|
public function __construct(private GiteaIssueService $gitea) {}
|
|
|
|
/**
|
|
* Liste des tickets de l'utilisateur, avec leur état courant récupéré
|
|
* depuis Gitea (ouvert / résolu, jalon).
|
|
*/
|
|
public function index()
|
|
{
|
|
/** @var User $user */
|
|
$user = Auth::user();
|
|
|
|
$tickets = $user->tickets()->latest()->get()->map(function (Ticket $ticket) {
|
|
$issue = $this->gitea->getIssue($ticket->gitea_number);
|
|
$ticket->setAttribute('state', $issue['state'] ?? null);
|
|
$ticket->setAttribute('milestone', $issue['milestone']['title'] ?? null);
|
|
|
|
return $ticket;
|
|
});
|
|
|
|
return view('tickets.index', compact('tickets'));
|
|
}
|
|
|
|
// Formulaire de création
|
|
public function create()
|
|
{
|
|
return view('tickets.create');
|
|
}
|
|
|
|
// Création d'un ticket -> issue Gitea + enregistrement local
|
|
public function store(Request $request)
|
|
{
|
|
$data = $request->validate([
|
|
'type' => ['required', Rule::in(['Modification', 'Ajout', 'Correction'])],
|
|
'titre' => ['required', 'string', 'min:5', 'max:120'],
|
|
'description' => ['required', 'string', 'min:10', 'max:5000'],
|
|
]);
|
|
|
|
/** @var User $user */
|
|
$user = Auth::user();
|
|
$auteur = $user->name ?? 'Utilisateur';
|
|
|
|
$title = "[{$data['type']}] {$data['titre']}";
|
|
$body = "**Type de demande :** {$data['type']}\n"
|
|
."**Proposé par :** {$auteur} (via le site CESIZen)\n\n"
|
|
."### Description\n"
|
|
.$data['description']."\n\n"
|
|
."---\n"
|
|
.'_Ticket créé automatiquement depuis CESIZen._';
|
|
|
|
$issue = $this->gitea->createIssue($title, $body);
|
|
|
|
if (! $issue || ! isset($issue['number'])) {
|
|
return back()->withInput()->withErrors([
|
|
'gitea' => "L'envoi de votre demande a échoué. Merci de réessayer plus tard.",
|
|
]);
|
|
}
|
|
|
|
// On mémorise le lien utilisateur <-> issue pour le suivi.
|
|
$user->tickets()->create([
|
|
'gitea_number' => (int) $issue['number'],
|
|
'title' => $data['titre'],
|
|
'type' => $data['type'],
|
|
]);
|
|
|
|
return redirect()->route('tickets.show', $issue['number'])
|
|
->with('success', 'Votre demande a bien été transmise à l\'équipe.');
|
|
}
|
|
|
|
/**
|
|
* Détail d'un ticket : état, jalon, labels et fil de discussion.
|
|
*/
|
|
public function show(int $number)
|
|
{
|
|
$ticket = $this->findOwnedTicket($number);
|
|
|
|
$issue = $this->gitea->getIssue($number);
|
|
$comments = $this->gitea->getComments($number);
|
|
|
|
return view('tickets.show', compact('ticket', 'issue', 'comments'));
|
|
}
|
|
|
|
/**
|
|
* Réponse de l'utilisateur : ajoute un commentaire sur l'issue Gitea.
|
|
*/
|
|
public function reply(Request $request, int $number)
|
|
{
|
|
$this->findOwnedTicket($number);
|
|
|
|
$data = $request->validate([
|
|
'message' => ['required', 'string', 'min:2', 'max:5000'],
|
|
]);
|
|
|
|
/** @var User $user */
|
|
$user = Auth::user();
|
|
$auteur = $user->name ?? 'Utilisateur';
|
|
$body = "**{$auteur}** (via CESIZen) :\n\n".$data['message'];
|
|
|
|
if (! $this->gitea->addComment($number, $body)) {
|
|
return back()->withErrors(['gitea' => "L'envoi de votre réponse a échoué."]);
|
|
}
|
|
|
|
return redirect()->route('tickets.show', $number)
|
|
->with('success', 'Votre réponse a été ajoutée au ticket.');
|
|
}
|
|
|
|
/**
|
|
* Récupère le ticket s'il appartient bien à l'utilisateur connecté,
|
|
* sinon renvoie une 404 (empêche de consulter les tickets d'autrui).
|
|
*/
|
|
private function findOwnedTicket(int $number): Ticket
|
|
{
|
|
/** @var User $user */
|
|
$user = Auth::user();
|
|
|
|
return $user->tickets()->where('gitea_number', $number)->firstOrFail();
|
|
}
|
|
}
|