style: liens sans soulignement, zone illustration en haut des tuiles

This commit is contained in:
Cedric Abonnel
2026-05-08 13:47:04 +02:00
parent 87172baf68
commit debbfe37f8
11 changed files with 67 additions and 98 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
-65
View File
@@ -4,68 +4,3 @@ parameters:
message: "#^Unreachable statement \\- code above always terminates\\.$#" message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 1 count: 1
path: src/Repository/ProfileRepository.php path: src/Repository/ProfileRepository.php
-
message: "#^Call to method getCode\\(\\) on an unknown class App\\\\Repository\\\\PDOException\\.$#"
count: 1
path: src/Repository/UserRepository.php
-
message: "#^Caught class App\\\\Repository\\\\PDOException not found\\.$#"
count: 1
path: src/Repository/UserRepository.php
-
message: "#^Instantiated class App\\\\Repository\\\\InvalidArgumentException not found\\.$#"
count: 1
path: src/Repository/UserRepository.php
-
message: "#^Method App\\\\Repository\\\\UserRepository\\:\\:nullIfEmpty\\(\\) is unused\\.$#"
count: 1
path: src/Repository/UserRepository.php
-
message: "#^Throwing object of an unknown class App\\\\Repository\\\\InvalidArgumentException\\.$#"
count: 1
path: src/Repository/UserRepository.php
-
message: "#^Throwing object of an unknown class App\\\\Repository\\\\PDOException\\.$#"
count: 1
path: src/Repository/UserRepository.php
-
message: "#^Class App\\\\Repository\\\\UserRepository constructor invoked with 0 parameters, 1 required\\.$#"
count: 1
path: src/Service/AuthService.php
-
message: "#^Call to an undefined method App\\\\Infrastructure\\\\Database\\:\\:getConnection\\(\\)\\.$#"
count: 1
path: src/Service/MailQueue.php
-
message: "#^Call to an undefined method App\\\\Infrastructure\\\\Database\\:\\:getConnection\\(\\)\\.$#"
count: 1
path: src/Service/MailService.php
-
message: "#^Comparison operation \"\\>\" between 200 and 0 is always true\\.$#"
count: 1
path: src/Service/MailService.php
-
message: "#^Constant BASE_PATH not found\\.$#"
count: 1
path: src/auth.php
-
message: "#^Parameter \\#1 \\$scope of method Jumbojett\\\\OpenIDConnectClient\\:\\:addScope\\(\\) expects array, string given\\.$#"
count: 1
path: src/auth.php
-
message: "#^Constant BASE_PATH not found\\.$#"
count: 1
path: src/db.php
+5
View File
@@ -0,0 +1,5 @@
<?php
declare(strict_types=1);
define('BASE_PATH', __DIR__);
+2
View File
@@ -7,3 +7,5 @@ parameters:
- src - src
excludePaths: excludePaths:
- src/Parsedown.php - src/Parsedown.php
bootstrapFiles:
- phpstan-bootstrap.php
+26
View File
@@ -90,7 +90,24 @@ h2 {
letter-spacing: -0.3px; letter-spacing: -0.3px;
} }
/* ─── Liens globaux ─────────────────────── */
a {
color: var(--vl-accent);
text-decoration: none;
}
a:hover {
color: var(--vl-accent-dark);
}
/* ─── Cards ─────────────────────────────── */ /* ─── Cards ─────────────────────────────── */
.card-cover {
height: 120px;
border-radius: var(--vl-radius) var(--vl-radius) 0 0;
flex-shrink: 0;
}
.card { .card {
border: 1px solid var(--vl-border) !important; border: 1px solid var(--vl-border) !important;
border-radius: var(--vl-radius) !important; border-radius: var(--vl-radius) !important;
@@ -120,6 +137,15 @@ h2 {
color: var(--vl-text) !important; color: var(--vl-text) !important;
} }
.card-title a {
color: var(--vl-text);
transition: color 0.15s;
}
.card-title a:hover {
color: var(--vl-accent);
}
.card-text { .card-text {
color: var(--vl-muted); color: var(--vl-muted);
font-size: 0.9rem; font-size: 0.9rem;
+2 -8
View File
@@ -24,7 +24,7 @@ final class UserRepository
{ {
$email = strtolower(trim($email)); $email = strtolower(trim($email));
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) { if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Email OIDC invalide.'); throw new \InvalidArgumentException('Email OIDC invalide.');
} }
// 1) Existe déjà ? // 1) Existe déjà ?
@@ -53,7 +53,7 @@ SQL;
':hash' => $randomHash, ':hash' => $randomHash,
]); ]);
return (string)$st->fetchColumn(); return (string)$st->fetchColumn();
} catch (PDOException $e) { } catch (\PDOException $e) {
// Unique violation sur email (23505) → on relit lid (race condition) // Unique violation sur email (23505) → on relit lid (race condition)
if ($e->getCode() === '23505') { if ($e->getCode() === '23505') {
$st = $this->pdo->prepare('SELECT id FROM users WHERE email = :email LIMIT 1'); $st = $this->pdo->prepare('SELECT id FROM users WHERE email = :email LIMIT 1');
@@ -67,12 +67,6 @@ SQL;
} }
} }
private function nullIfEmpty(?string $v): ?string
{
$v = trim((string)$v);
return $v === '' ? null : $v;
}
public function findByEmail(string $email): ?User public function findByEmail(string $email): ?User
{ {
$sql = 'SELECT id, email, password_hash, is_active FROM users WHERE email = :email LIMIT 1'; $sql = 'SELECT id, email, password_hash, is_active FROM users WHERE email = :email LIMIT 1';
+1 -1
View File
@@ -76,7 +76,7 @@ final class AuthService
// Mettre à jour le hash // Mettre à jour le hash
$newHash = password_hash($newPassword, PASSWORD_ARGON2ID); $newHash = password_hash($newPassword, PASSWORD_ARGON2ID);
(new \App\Repository\UserRepository())->updatePassword($row['id'], $newHash); (new \App\Repository\UserRepository(\App\Infrastructure\Database::get()))->updatePassword($row['id'], $newHash);
// (Optionnel) rotation session // (Optionnel) rotation session
\App\Infrastructure\Session::regenerate(); \App\Infrastructure\Session::regenerate();
+2 -3
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Service; namespace App\Service;
use App\Infrastructure\Database;
use PDO; use PDO;
use Throwable; use Throwable;
use DateTimeImmutable; use DateTimeImmutable;
@@ -33,9 +32,9 @@ final class MailQueue
private PDO $pdo; private PDO $pdo;
private MailService $mailService; private MailService $mailService;
public function __construct(Database $db, MailService $mailService) public function __construct(\PDO $pdo, MailService $mailService)
{ {
$this->pdo = $db->getConnection(); $this->pdo = $pdo;
$this->mailService = $mailService; $this->mailService = $mailService;
} }
+4 -7
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\Service; namespace App\Service;
use App\Infrastructure\Database;
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception as MailException; use PHPMailer\PHPMailer\Exception as MailException;
use PDO; use PDO;
@@ -38,7 +37,7 @@ final class MailService
private array $smtpConfig; private array $smtpConfig;
/** /**
* @param Database $db Retourne un PDO connecté (PostgreSQL recommandé) * @param \PDO $pdo PDO connecté (PostgreSQL recommandé)
* @param array<string,mixed> $smtpConfig [ * @param array<string,mixed> $smtpConfig [
* 'host' => 'smtp.example.tld', * 'host' => 'smtp.example.tld',
* 'port' => 587, * 'port' => 587,
@@ -52,9 +51,9 @@ final class MailService
* 'smtp_options' => [...] (optionnel, cf. PHPMailer::SMTPOptions) * 'smtp_options' => [...] (optionnel, cf. PHPMailer::SMTPOptions)
* ] * ]
*/ */
public function __construct(Database $db, array $smtpConfig) public function __construct(\PDO $pdo, array $smtpConfig)
{ {
$this->pdo = $db->getConnection(); $this->pdo = $pdo;
$this->smtpConfig = $smtpConfig; $this->smtpConfig = $smtpConfig;
$this->mailer = new PHPMailer(true); $this->mailer = new PHPMailer(true);
@@ -204,8 +203,7 @@ final class MailService
return false; return false;
} }
// 3) Garde-fou global / heure (optionnel) // 3) Garde-fou global / heure
if (self::MAX_GLOBAL_PER_HOUR > 0) {
$sql3 = <<<SQL $sql3 = <<<SQL
SELECT COUNT(*)::int SELECT COUNT(*)::int
FROM journal_smtp FROM journal_smtp
@@ -217,7 +215,6 @@ final class MailService
if ($global1h >= self::MAX_GLOBAL_PER_HOUR) { if ($global1h >= self::MAX_GLOBAL_PER_HOUR) {
return false; return false;
} }
}
return true; return true;
} }
+1 -1
View File
@@ -23,6 +23,6 @@ function get_oidc_client(): OpenIDConnectClient
'varlog-client-secret' 'varlog-client-secret'
); );
$oidc->setRedirectURL('http://varlog.acegrp.lan/auth/callback.php'); $oidc->setRedirectURL('http://varlog.acegrp.lan/auth/callback.php');
$oidc->addScope('openid email profile'); $oidc->addScope(['openid', 'email', 'profile']);
return $oidc; return $oidc;
} }
+12 -1
View File
@@ -2,6 +2,15 @@
require_once BASE_PATH . '/src/Parsedown.php'; require_once BASE_PATH . '/src/Parsedown.php';
$Parsedown = new Parsedown(); $Parsedown = new Parsedown();
$coverGradients = [
'linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%)',
'linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%)',
'linear-gradient(135deg, #fce7f3 0%, #fbcfe8 100%)',
'linear-gradient(135deg, #fef3c7 0%, #fde68a 100%)',
'linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%)',
'linear-gradient(135deg, #ede9fe 0%, #ddd6fe 100%)',
];
ob_start(); ob_start();
?> ?>
@@ -9,10 +18,12 @@ ob_start();
<?php foreach ($posts as $post): ?> <?php foreach ($posts as $post): ?>
<?php <?php
$html = $Parsedown->text($post['content']); $html = $Parsedown->text($post['content']);
$preview = mb_strimwidth(strip_tags($html), 0, 160, '…'); $preview = mb_strimwidth(strip_tags($html), 0, 120, '…');
$gradient = $coverGradients[$post['id'] % count($coverGradients)];
?> ?>
<div class="col"> <div class="col">
<article class="card h-100"> <article class="card h-100">
<div class="card-cover" style="background: <?= $gradient ?>"></div>
<div class="card-body d-flex flex-column"> <div class="card-body d-flex flex-column">
<h2 class="card-title"> <h2 class="card-title">
<a href="route.php?action=view&id=<?= $post['id'] ?>"> <a href="route.php?action=view&id=<?= $post['id'] ?>">