feat: ajout du provisionnement des comptes Gitea pour les utilisateurs lors de la soumission de suggestions
This commit is contained in:
@@ -75,6 +75,10 @@ AWS_USE_PATH_STYLE_ENDPOINT=false
|
|||||||
GITEA_URL=https://gitea.sam-coffre.duckdns.org
|
GITEA_URL=https://gitea.sam-coffre.duckdns.org
|
||||||
GITEA_TOKEN=
|
GITEA_TOKEN=
|
||||||
GITEA_REPO=Groupe1/Ressources-relationnel
|
GITEA_REPO=Groupe1/Ressources-relationnel
|
||||||
|
# Token d'un ADMIN Gitea (scopes "write:admin" + "write:issue") : sert à créer un
|
||||||
|
# compte Gitea à chaque utilisateur (au 1er envoi) et à ouvrir les tickets en leur
|
||||||
|
# nom (en-tête Sudo). Laisser vide pour retomber sur GITEA_TOKEN / compte de service.
|
||||||
|
GITEA_ADMIN_TOKEN=
|
||||||
|
|
||||||
# --- Applications mobiles (page /telecharger) ---
|
# --- Applications mobiles (page /telecharger) ---
|
||||||
# Laisser vide pour servir les fichiers de public/downloads/ (.apk / .ipa),
|
# Laisser vide pour servir les fichiers de public/downloads/ (.apk / .ipa),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Models\Utilisateur;
|
use App\Models\Utilisateur;
|
||||||
use App\Services\GiteaIssueService;
|
use App\Services\GiteaIssueService;
|
||||||
|
use App\Services\GiteaUserService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
@@ -17,7 +18,7 @@ class SuggestionController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Traiter la suggestion et créer un ticket dans Gitea
|
// Traiter la suggestion et créer un ticket dans Gitea
|
||||||
public function store(Request $request, GiteaIssueService $gitea)
|
public function store(Request $request, GiteaIssueService $gitea, GiteaUserService $giteaUsers)
|
||||||
{
|
{
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'type' => ['required', Rule::in(['Modification', 'Ajout', 'Correction'])],
|
'type' => ['required', Rule::in(['Modification', 'Ajout', 'Correction'])],
|
||||||
@@ -37,6 +38,10 @@ class SuggestionController extends Controller
|
|||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$auteur = $user->Pseudo ?? 'Utilisateur';
|
$auteur = $user->Pseudo ?? 'Utilisateur';
|
||||||
|
|
||||||
|
// Compte Gitea de l'utilisateur (créé au premier envoi) pour que le
|
||||||
|
// ticket soit ouvert en son nom et qu'il puisse le suivre.
|
||||||
|
$compte = $giteaUsers->assurerCompte($user);
|
||||||
|
|
||||||
$title = "[{$data['type']}] {$data['titre']}";
|
$title = "[{$data['type']}] {$data['titre']}";
|
||||||
|
|
||||||
$body = "**Type de demande :** {$data['type']}\n"
|
$body = "**Type de demande :** {$data['type']}\n"
|
||||||
@@ -46,9 +51,20 @@ class SuggestionController extends Controller
|
|||||||
."---\n"
|
."---\n"
|
||||||
.'_Ticket créé automatiquement depuis le formulaire de suggestions du site._';
|
.'_Ticket créé automatiquement depuis le formulaire de suggestions du site._';
|
||||||
|
|
||||||
if ($gitea->createIssue($title, $body)) {
|
if ($gitea->createIssue($title, $body, $compte['username'] ?? null)) {
|
||||||
return redirect()->route('suggestions.create')
|
$redirect = redirect()->route('suggestions.create')
|
||||||
->with('success', 'Merci ! Votre suggestion a bien été transmise à l\'équipe.');
|
->with('success', 'Merci ! Votre suggestion a bien été transmise à l\'équipe.');
|
||||||
|
|
||||||
|
// Identifiants affichés UNE seule fois, uniquement si le compte vient d'être créé.
|
||||||
|
if ($compte !== null && $compte['motDePasseInitial'] !== null) {
|
||||||
|
$redirect->with('gitea_compte', [
|
||||||
|
'url' => rtrim((string) config('services.gitea.url'), '/'),
|
||||||
|
'username' => $compte['username'],
|
||||||
|
'mot_de_passe' => $compte['motDePasseInitial'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
return back()->withInput()->withErrors([
|
return back()->withInput()->withErrors([
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Illuminate\Support\Carbon;
|
|||||||
* @property string $Email
|
* @property string $Email
|
||||||
* @property string $MotDePasse
|
* @property string $MotDePasse
|
||||||
* @property string $Pseudo
|
* @property string $Pseudo
|
||||||
|
* @property string|null $GiteaUsername
|
||||||
* @property string $Statut
|
* @property string $Statut
|
||||||
* @property int $ID_Role
|
* @property int $ID_Role
|
||||||
* @property Carbon $DateInscription
|
* @property Carbon $DateInscription
|
||||||
@@ -37,6 +38,7 @@ class Utilisateur extends Authenticatable
|
|||||||
'Email',
|
'Email',
|
||||||
'MotDePasse',
|
'MotDePasse',
|
||||||
'Pseudo',
|
'Pseudo',
|
||||||
|
'GiteaUsername',
|
||||||
'Statut',
|
'Statut',
|
||||||
'ID_Role',
|
'ID_Role',
|
||||||
'DateInscription',
|
'DateInscription',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Illuminate\Http\Client\Response;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
@@ -10,9 +11,13 @@ class GiteaIssueService
|
|||||||
/**
|
/**
|
||||||
* Crée un ticket (issue) dans le dépôt Gitea configuré.
|
* Crée un ticket (issue) dans le dépôt Gitea configuré.
|
||||||
*
|
*
|
||||||
|
* Si $sudo est fourni (username Gitea de l'utilisateur), le ticket est
|
||||||
|
* créé en son nom via l'en-tête "Sudo" (nécessite un token admin). En cas
|
||||||
|
* de refus, on retombe sur une création avec le compte de service.
|
||||||
|
*
|
||||||
* @return bool true si le ticket a bien été créé, false sinon.
|
* @return bool true si le ticket a bien été créé, false sinon.
|
||||||
*/
|
*/
|
||||||
public function createIssue(string $title, string $body): bool
|
public function createIssue(string $title, string $body, ?string $sudo = null): bool
|
||||||
{
|
{
|
||||||
$url = rtrim((string) config('services.gitea.url'), '/');
|
$url = rtrim((string) config('services.gitea.url'), '/');
|
||||||
$repo = trim((string) config('services.gitea.repo'), '/');
|
$repo = trim((string) config('services.gitea.repo'), '/');
|
||||||
@@ -25,14 +30,15 @@ class GiteaIssueService
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Gitea attend l'en-tête "Authorization: token <TOKEN>".
|
$response = $this->postIssue($url, $repo, $token, $title, $body, $sudo);
|
||||||
$response = Http::withToken($token, 'token')
|
|
||||||
->acceptJson()
|
if ($sudo !== null && $response->failed()) {
|
||||||
->timeout(10)
|
Log::warning('Création du ticket au nom de l\'utilisateur refusée, repli sur le compte de service.', [
|
||||||
->post("{$url}/api/v1/repos/{$repo}/issues", [
|
'sudo' => $sudo,
|
||||||
'title' => $title,
|
'status' => $response->status(),
|
||||||
'body' => $body,
|
|
||||||
]);
|
]);
|
||||||
|
$response = $this->postIssue($url, $repo, $token, $title, $body, null);
|
||||||
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::error('Appel API Gitea impossible : '.$e->getMessage());
|
Log::error('Appel API Gitea impossible : '.$e->getMessage());
|
||||||
|
|
||||||
@@ -50,4 +56,27 @@ class GiteaIssueService
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function postIssue(
|
||||||
|
string $url,
|
||||||
|
string $repo,
|
||||||
|
string $token,
|
||||||
|
string $title,
|
||||||
|
string $body,
|
||||||
|
?string $sudo,
|
||||||
|
): Response {
|
||||||
|
// Gitea attend l'en-tête "Authorization: token <TOKEN>".
|
||||||
|
$request = Http::withToken($token, 'token')
|
||||||
|
->acceptJson()
|
||||||
|
->timeout(10);
|
||||||
|
|
||||||
|
if ($sudo !== null) {
|
||||||
|
$request = $request->withHeaders(['Sudo' => $sudo]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $request->post("{$url}/api/v1/repos/{$repo}/issues", [
|
||||||
|
'title' => $title,
|
||||||
|
'body' => $body,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Utilisateur;
|
||||||
|
use Illuminate\Http\Client\PendingRequest;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provisionnement des comptes Gitea des utilisateurs du site.
|
||||||
|
*
|
||||||
|
* Au premier envoi de suggestion, un compte Gitea est créé pour
|
||||||
|
* l'utilisateur (API admin) afin qu'il puisse suivre, commenter et
|
||||||
|
* créer ses propres tickets. Le mot de passe initial n'est renvoyé
|
||||||
|
* qu'une seule fois et n'est jamais stocké côté application.
|
||||||
|
*/
|
||||||
|
class GiteaUserService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Garantit que l'utilisateur possède un compte Gitea.
|
||||||
|
*
|
||||||
|
* @return array{username: string, motDePasseInitial: string|null}|null
|
||||||
|
* null si Gitea n'est pas configuré ou si la création a échoué
|
||||||
|
* (le ticket sera alors créé avec le compte de service).
|
||||||
|
*/
|
||||||
|
public function assurerCompte(Utilisateur $utilisateur): ?array
|
||||||
|
{
|
||||||
|
if ($utilisateur->GiteaUsername) {
|
||||||
|
return ['username' => $utilisateur->GiteaUsername, 'motDePasseInitial' => null];
|
||||||
|
}
|
||||||
|
|
||||||
|
$client = $this->client();
|
||||||
|
|
||||||
|
if ($client === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Un compte existe peut-être déjà avec cet email (créé hors du site) : on le réutilise.
|
||||||
|
if ($existant = $this->chercherParEmail($client, $utilisateur->Email)) {
|
||||||
|
$utilisateur->GiteaUsername = $existant;
|
||||||
|
$utilisateur->save();
|
||||||
|
|
||||||
|
return ['username' => $existant, 'motDePasseInitial' => null];
|
||||||
|
}
|
||||||
|
|
||||||
|
$username = $this->genererUsername($utilisateur);
|
||||||
|
$motDePasse = Str::password(16);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $client->post('/api/v1/admin/users', [
|
||||||
|
'username' => $username,
|
||||||
|
'email' => $utilisateur->Email,
|
||||||
|
'password' => $motDePasse,
|
||||||
|
'full_name' => $utilisateur->Pseudo ?? $username,
|
||||||
|
'must_change_password' => true,
|
||||||
|
'send_notify' => false,
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Log::error('Appel API Gitea (création utilisateur) impossible : '.$e->getMessage());
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->failed()) {
|
||||||
|
Log::warning('Création du compte Gitea échouée (token admin requis ?)', [
|
||||||
|
'status' => $response->status(),
|
||||||
|
'body' => $response->body(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$utilisateur->GiteaUsername = $username;
|
||||||
|
$utilisateur->save();
|
||||||
|
|
||||||
|
return ['username' => $username, 'motDePasseInitial' => $motDePasse];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function client(): ?PendingRequest
|
||||||
|
{
|
||||||
|
$url = rtrim((string) config('services.gitea.url'), '/');
|
||||||
|
$token = (string) (config('services.gitea.admin_token') ?: config('services.gitea.token'));
|
||||||
|
|
||||||
|
if ($url === '' || $token === '') {
|
||||||
|
Log::warning('Gitea non configuré (URL / token manquant) : compte utilisateur non créé.');
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Http::baseUrl($url)
|
||||||
|
->withToken($token, 'token')
|
||||||
|
->acceptJson()
|
||||||
|
->timeout(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function chercherParEmail(PendingRequest $client, string $email): ?string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$response = $client->get('/api/v1/admin/emails/search', ['q' => $email]);
|
||||||
|
} catch (\Throwable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->failed()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($response->json() ?? [] as $entree) {
|
||||||
|
if (strcasecmp($entree['email'] ?? '', $email) === 0) {
|
||||||
|
return $entree['username'] ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Username déterministe et unique : pseudo en slug, suffixé de l'ID interne.
|
||||||
|
*/
|
||||||
|
private function genererUsername(Utilisateur $utilisateur): string
|
||||||
|
{
|
||||||
|
$base = Str::slug((string) ($utilisateur->Pseudo ?? ''));
|
||||||
|
|
||||||
|
if ($base === '') {
|
||||||
|
$base = 'utilisateur';
|
||||||
|
}
|
||||||
|
|
||||||
|
return Str::limit($base, 30, '').'-'.$utilisateur->ID_Utilisateur;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,9 +37,13 @@ return [
|
|||||||
|
|
||||||
// Gitea : création automatique de tickets (issues) depuis le formulaire
|
// Gitea : création automatique de tickets (issues) depuis le formulaire
|
||||||
// de suggestions du site. Le token doit avoir le scope "write:issue".
|
// de suggestions du site. Le token doit avoir le scope "write:issue".
|
||||||
|
// Le token admin (scopes write:admin + write:issue) sert à créer les
|
||||||
|
// comptes Gitea des utilisateurs et à ouvrir les tickets en leur nom ;
|
||||||
|
// à défaut, le token de service est utilisé.
|
||||||
'gitea' => [
|
'gitea' => [
|
||||||
'url' => env('GITEA_URL', 'https://gitea.sam-coffre.duckdns.org'),
|
'url' => env('GITEA_URL', 'https://gitea.sam-coffre.duckdns.org'),
|
||||||
'token' => env('GITEA_TOKEN'),
|
'token' => env('GITEA_TOKEN'),
|
||||||
|
'admin_token' => env('GITEA_ADMIN_TOKEN'),
|
||||||
'repo' => env('GITEA_REPO', 'Groupe1/Ressources-relationnel'),
|
'repo' => env('GITEA_REPO', 'Groupe1/Ressources-relationnel'),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('utilisateurs', function (Blueprint $table) {
|
||||||
|
// Compte Gitea provisionné au premier envoi de suggestion,
|
||||||
|
// pour que l'utilisateur puisse suivre et créer ses tickets.
|
||||||
|
$table->string('GiteaUsername', 100)->nullable()->after('Pseudo');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('utilisateurs', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('GiteaUsername');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -21,6 +21,26 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
<!-- Compte Gitea créé (identifiants affichés une seule fois) -->
|
||||||
|
@if (session('gitea_compte'))
|
||||||
|
@php($compte = session('gitea_compte'))
|
||||||
|
<div class="mb-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
||||||
|
<p class="text-blue-800 font-semibold mb-2">🎉 Un compte Gitea a été créé pour vous !</p>
|
||||||
|
<p class="text-blue-700 text-sm mb-2">
|
||||||
|
Vous pouvez maintenant suivre, commenter et créer vos tickets directement sur
|
||||||
|
<a href="{{ $compte['url'] }}" target="_blank" rel="noopener" class="underline font-semibold">{{ $compte['url'] }}</a>.
|
||||||
|
</p>
|
||||||
|
<p class="text-blue-800 text-sm">
|
||||||
|
Identifiant : <strong>{{ $compte['username'] }}</strong><br>
|
||||||
|
Mot de passe temporaire : <strong>{{ $compte['mot_de_passe'] }}</strong>
|
||||||
|
</p>
|
||||||
|
<p class="text-blue-700 text-xs mt-2">
|
||||||
|
⚠️ Notez ce mot de passe dès maintenant : il ne sera plus jamais affiché.
|
||||||
|
Il vous sera demandé de le changer à votre première connexion.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<!-- Erreurs -->
|
<!-- Erreurs -->
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
<div class="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
||||||
|
|||||||
@@ -31,10 +31,25 @@ class SuggestionTest extends TestCase
|
|||||||
config([
|
config([
|
||||||
'services.gitea.url' => 'https://gitea.test',
|
'services.gitea.url' => 'https://gitea.test',
|
||||||
'services.gitea.token' => 'fake-token',
|
'services.gitea.token' => 'fake-token',
|
||||||
|
'services.gitea.admin_token' => 'fake-admin-token',
|
||||||
'services.gitea.repo' => 'Groupe1/Ressources-relationnel',
|
'services.gitea.repo' => 'Groupe1/Ressources-relationnel',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fakes par défaut : aucun compte existant, création de compte et de ticket OK.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $overrides
|
||||||
|
*/
|
||||||
|
private function fakesGitea(array $overrides = []): void
|
||||||
|
{
|
||||||
|
Http::fake($overrides + [
|
||||||
|
'gitea.test/api/v1/admin/emails/search*' => Http::response([]),
|
||||||
|
'gitea.test/api/v1/admin/users' => Http::response(['id' => 42], 201),
|
||||||
|
'gitea.test/api/v1/repos/*/issues' => Http::response(['number' => 42], 201),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_le_formulaire_de_suggestion_exige_une_authentification(): void
|
public function test_le_formulaire_de_suggestion_exige_une_authentification(): void
|
||||||
{
|
{
|
||||||
$this->get('/suggestions/nouveau')->assertRedirect('/login');
|
$this->get('/suggestions/nouveau')->assertRedirect('/login');
|
||||||
@@ -43,9 +58,7 @@ class SuggestionTest extends TestCase
|
|||||||
public function test_une_suggestion_valide_cree_un_ticket_gitea(): void
|
public function test_une_suggestion_valide_cree_un_ticket_gitea(): void
|
||||||
{
|
{
|
||||||
$this->configurerGitea();
|
$this->configurerGitea();
|
||||||
Http::fake([
|
$this->fakesGitea();
|
||||||
'*/api/v1/repos/*/issues' => Http::response(['number' => 42], 201),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$response = $this->actingAs($this->utilisateur())->post('/suggestions', [
|
$response = $this->actingAs($this->utilisateur())->post('/suggestions', [
|
||||||
'type' => 'Correction',
|
'type' => 'Correction',
|
||||||
@@ -63,6 +76,110 @@ class SuggestionTest extends TestCase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_le_premier_envoi_cree_un_compte_gitea_pour_l_utilisateur(): void
|
||||||
|
{
|
||||||
|
$this->configurerGitea();
|
||||||
|
$this->fakesGitea();
|
||||||
|
|
||||||
|
$utilisateur = $this->utilisateur();
|
||||||
|
|
||||||
|
$response = $this->actingAs($utilisateur)->post('/suggestions', [
|
||||||
|
'type' => 'Ajout',
|
||||||
|
'titre' => 'Une nouvelle fonctionnalité',
|
||||||
|
'description' => 'Description suffisamment longue de la fonctionnalité.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$usernameAttendu = 'jeantest-'.$utilisateur->ID_Utilisateur;
|
||||||
|
|
||||||
|
$response->assertSessionHas('success');
|
||||||
|
// Les identifiants sont flashés une seule fois pour affichage
|
||||||
|
$response->assertSessionHas('gitea_compte', fn ($compte) => $compte['username'] === $usernameAttendu
|
||||||
|
&& $compte['mot_de_passe'] !== null);
|
||||||
|
|
||||||
|
$this->assertSame($usernameAttendu, $utilisateur->fresh()->GiteaUsername);
|
||||||
|
|
||||||
|
// Le compte a été créé via l'API admin…
|
||||||
|
Http::assertSent(fn ($request) => str_contains($request->url(), '/api/v1/admin/users')
|
||||||
|
&& $request['username'] === $usernameAttendu
|
||||||
|
&& $request['email'] === 'jean.test@example.com'
|
||||||
|
&& $request['must_change_password'] === true);
|
||||||
|
|
||||||
|
// …et le ticket est ouvert au nom de l'utilisateur (en-tête Sudo)
|
||||||
|
Http::assertSent(fn ($request) => str_contains($request->url(), '/issues')
|
||||||
|
&& $request->header('Sudo') === [$usernameAttendu]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_un_compte_gitea_existant_est_reutilise(): void
|
||||||
|
{
|
||||||
|
$this->configurerGitea();
|
||||||
|
$this->fakesGitea();
|
||||||
|
|
||||||
|
$utilisateur = $this->utilisateur();
|
||||||
|
$utilisateur->GiteaUsername = 'jean-deja-la';
|
||||||
|
$utilisateur->save();
|
||||||
|
|
||||||
|
$response = $this->actingAs($utilisateur)->post('/suggestions', [
|
||||||
|
'type' => 'Modification',
|
||||||
|
'titre' => 'Changer un contenu',
|
||||||
|
'description' => 'Description suffisamment longue de la modification.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertSessionHas('success');
|
||||||
|
$response->assertSessionMissing('gitea_compte');
|
||||||
|
|
||||||
|
// Aucune création de compte ne doit être tentée
|
||||||
|
Http::assertNotSent(fn ($request) => str_contains($request->url(), '/api/v1/admin/users'));
|
||||||
|
|
||||||
|
Http::assertSent(fn ($request) => str_contains($request->url(), '/issues')
|
||||||
|
&& $request->header('Sudo') === ['jean-deja-la']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_le_ticket_est_cree_meme_si_la_creation_du_compte_echoue(): void
|
||||||
|
{
|
||||||
|
$this->configurerGitea();
|
||||||
|
// Token sans droits admin : la création de compte est refusée
|
||||||
|
$this->fakesGitea([
|
||||||
|
'gitea.test/api/v1/admin/emails/search*' => Http::response('Forbidden', 403),
|
||||||
|
'gitea.test/api/v1/admin/users' => Http::response('Forbidden', 403),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($this->utilisateur())->post('/suggestions', [
|
||||||
|
'type' => 'Correction',
|
||||||
|
'titre' => 'Un bug à corriger',
|
||||||
|
'description' => 'Description suffisamment longue du bug rencontré.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Repli : ticket créé avec le compte de service, sans en-tête Sudo
|
||||||
|
$response->assertSessionHas('success');
|
||||||
|
$response->assertSessionMissing('gitea_compte');
|
||||||
|
|
||||||
|
Http::assertSent(fn ($request) => str_contains($request->url(), '/issues')
|
||||||
|
&& $request->header('Sudo') === []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_un_sudo_refuse_retombe_sur_le_compte_de_service(): void
|
||||||
|
{
|
||||||
|
$this->configurerGitea();
|
||||||
|
$this->fakesGitea([
|
||||||
|
// 1er appel (Sudo) refusé, 2e appel (compte de service) accepté
|
||||||
|
'gitea.test/api/v1/repos/*/issues' => Http::sequence()
|
||||||
|
->push('Not Found', 404)
|
||||||
|
->push(['number' => 43], 201),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$utilisateur = $this->utilisateur();
|
||||||
|
$utilisateur->GiteaUsername = 'jean-deja-la';
|
||||||
|
$utilisateur->save();
|
||||||
|
|
||||||
|
$response = $this->actingAs($utilisateur)->post('/suggestions', [
|
||||||
|
'type' => 'Ajout',
|
||||||
|
'titre' => 'Encore une idée géniale',
|
||||||
|
'description' => 'Description suffisamment longue de cette idée géniale.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->assertSessionHas('success');
|
||||||
|
}
|
||||||
|
|
||||||
public function test_une_suggestion_invalide_est_rejetee(): void
|
public function test_une_suggestion_invalide_est_rejetee(): void
|
||||||
{
|
{
|
||||||
Http::fake();
|
Http::fake();
|
||||||
@@ -80,8 +197,8 @@ class SuggestionTest extends TestCase
|
|||||||
public function test_un_echec_gitea_affiche_une_erreur(): void
|
public function test_un_echec_gitea_affiche_une_erreur(): void
|
||||||
{
|
{
|
||||||
$this->configurerGitea();
|
$this->configurerGitea();
|
||||||
Http::fake([
|
$this->fakesGitea([
|
||||||
'*/api/v1/repos/*/issues' => Http::response(['message' => 'nope'], 500),
|
'gitea.test/api/v1/repos/*/issues' => Http::response(['message' => 'nope'], 500),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = $this->actingAs($this->utilisateur())->post('/suggestions', [
|
$response = $this->actingAs($this->utilisateur())->post('/suggestions', [
|
||||||
|
|||||||
Reference in New Issue
Block a user