Squelette Symfony, entités Server et Action

This commit is contained in:
Yasser Boulayoune 2026-04-07 10:12:00 +02:00
commit 52ecb4204c
46 changed files with 4308 additions and 0 deletions

0
src/Repository/.gitignore vendored Normal file
View file

View file

@ -0,0 +1,66 @@
<?php
namespace App\Repository;
use App\Entity\ActionLog;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
/**
* @class ActionLogRepository
* @brief Repository pour les logs d'actions SSH avec filtres
*
* @extends ServiceEntityRepository<ActionLog>
*/
class ActionLogRepository extends ServiceEntityRepository
{
/**
* @brief Constructeur standard du repository Doctrine
* @param ManagerRegistry $registry
*/
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ActionLog::class);
}
/**
* @brief Construit une requete filtrée pour l'historique des actions
*
* Tout les filtres sont optionels, si aucun filtre n'est fourni
* on retourne tout les logs trié par date decroissante.
* Les jointures sur user et server sont faites en LEFT JOIN pour
* inclure les logs sans utilisateur (actions systeme).
*
* @param int|null $serverId Filtrer par serveur
* @param int|null $userId Filtrer par utilisateur
* @param string|null $dateFrom Date de debut (format Y-m-d)
* @param string|null $dateTo Date de fin (format Y-m-d), inclus jusqu'a 23:59:59
* @return QueryBuilder Le query builder pour la pagination
*/
public function findByFilters(?int $serverId, ?int $userId, ?string $dateFrom, ?string $dateTo): QueryBuilder
{
$qb = $this->createQueryBuilder('a')
->leftJoin('a.user', 'u')
->leftJoin('a.server', 's')
->addSelect('u', 's')
->orderBy('a.executedAt', 'DESC');
if ($serverId) {
$qb->andWhere('s.id = :serverId')->setParameter('serverId', $serverId);
}
if ($userId) {
$qb->andWhere('u.id = :userId')->setParameter('userId', $userId);
}
if ($dateFrom) {
$qb->andWhere('a.executedAt >= :dateFrom')
->setParameter('dateFrom', new \DateTimeImmutable($dateFrom));
}
if ($dateTo) {
$qb->andWhere('a.executedAt <= :dateTo')
->setParameter('dateTo', new \DateTimeImmutable($dateTo . ' 23:59:59'));
}
return $qb;
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace App\Repository;
use App\Entity\ServerAccess;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @class ServerAccessRepository
* @brief Repository pour la gestion des acces operateurs aux serveurs
*
* Utilise principalement findOneBy(['server' => ..., 'user' => ...])
* pour verifier si un acces existe deja avant d'en creer un nouveau.
*
* @extends ServiceEntityRepository<ServerAccess>
*/
class ServerAccessRepository extends ServiceEntityRepository
{
/**
* @brief Constructeur standard du repository Doctrine
* @param ManagerRegistry $registry
*/
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ServerAccess::class);
}
}

View file

@ -0,0 +1,73 @@
<?php
/**
* @file ServerRepository.php
* @brief Repository Doctrine pour les requetes sur les serveurs
*
* @package App\Repository
* @author Yasser
*/
namespace App\Repository;
use App\Entity\Server;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
/**
* @class ServerRepository
* @brief Repository pour l'entité Server avec methodes de recherche personnalisées
*
* @extends ServiceEntityRepository<Server>
*/
class ServerRepository extends ServiceEntityRepository
{
/**
* @brief Constructeur standard du repository Doctrine
* @param ManagerRegistry $registry
*/
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Server::class);
}
/**
* @brief Construit une requete filtrée pour la liste des serveurs
*
* Filtre par nom/IP (recherche partielle), statut et utilisateur courant.
* Pour les opérateurs (non admin), filtre avec un JOIN sur ServerAccess
* pour n'afficher que les serveurs auxquels ils ont acces.
*
* @param string|null $search Terme de recherche sur le nom ou l'IP
* @param string|null $status Filtre sur le statut ('online', 'offline', 'unknown')
* @param User|null $currentUser L'utilisateur courant pour filtrer selon son role
* @return QueryBuilder Le query builder pret a etre paginé
*/
public function findByFilters(?string $search, ?string $status, ?User $currentUser = null): QueryBuilder
{
$qb = $this->createQueryBuilder('s')
->leftJoin('s.owner', 'o')
->addSelect('o')
->orderBy('s.createdAt', 'DESC');
if ($currentUser !== null && !$currentUser->isAdmin()) {
$qb->innerJoin('s.serverAccesses', 'sa')
->andWhere('sa.user = :currentUser')
->setParameter('currentUser', $currentUser);
}
if ($search) {
$qb->andWhere('s.name LIKE :search OR s.ipAddress LIKE :search')
->setParameter('search', '%' . $search . '%');
}
if ($status && in_array($status, ['online', 'offline', 'unknown'])) {
$qb->andWhere('s.lastStatus = :status')
->setParameter('status', $status);
}
return $qb;
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace App\Repository;
use App\Entity\Service;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @class ServiceRepository
* @brief Repository pour l'entité Service (services systemd)
*
* Pas de methodes personnalisées pour l'instant, on utilise les methodes
* de base de ServiceEntityRepository (findBy, findOneBy, etc).
*
* @extends ServiceEntityRepository<Service>
*/
class ServiceRepository extends ServiceEntityRepository
{
/**
* @brief Constructeur standard du repository Doctrine
* @param ManagerRegistry $registry
*/
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Service::class);
}
}

View file

@ -0,0 +1,100 @@
<?php
/**
* @file UserRepository.php
* @brief Repository Doctrine pour les requetes sur les utilisateurs
*
* @package App\Repository
* @author Yasser
*/
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
/**
* @class UserRepository
* @brief Repository pour l'entité User avec methodes de recherche personnalisées
*
* Implémente PasswordUpgraderInterface pour que Symfony puisse mettre a jour
* automatiquement le hash du mot de passe si l'algorithme change.
*
* @extends ServiceEntityRepository<User>
*/
class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface
{
/**
* @brief Constructeur standard du repository Doctrine
* @param ManagerRegistry $registry
*/
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
/**
* @brief Met a jour le hash du mot de passe d'un utilisateur
*
* Appelé automatiquement par Symfony si le hash du mot de passe
* doit etre mis a jour (ex: changement d'algorithme). Requis par
* l'interface PasswordUpgraderInterface.
*
* @param PasswordAuthenticatedUserInterface $user L'utilisateur dont on met a jour le mdp
* @param string $newHashedPassword Le nouveau hash a stocker
* @throws UnsupportedUserException Si l'utilisateur n'est pas une instance de User
*/
public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $user::class));
}
$user->setPassword($newHashedPassword);
$this->getEntityManager()->persist($user);
$this->getEntityManager()->flush();
}
/**
* @brief Retourne tout les utilisateurs avec un compte actif
*
* @return array Tableau d'objets User trié par date d'inscription (plus recent en premier)
*/
public function findAllActiveUsers(): array
{
return $this->createQueryBuilder('u')
->andWhere('u.isActive = true')
->orderBy('u.createdAt', 'DESC')
->getQuery()
->getResult();
}
/**
* @brief Retourne les operateurs actifs en excluant ceux deja assignés a un serveur
*
* Utilisé dans la page de detail d'un serveur pour afficher la liste
* des operateurs qui peuvent encore etre assignés (ceux pas encore dans
* ServerAccess pour ce serveur). Les admins sont aussi exclus.
*
* @param array $excludeIds Tableau des ids d'utilisateurs a exclure
* @return array Tableau d'objets User (operateurs uniquement, pas admins)
*/
public function findOperatorsExcluding(array $excludeIds): array
{
$qb = $this->createQueryBuilder('u')
->andWhere('u.isActive = true')
->orderBy('u.pseudo', 'ASC');
if (!empty($excludeIds)) {
$qb->andWhere('u.id NOT IN (:ids)')->setParameter('ids', $excludeIds);
}
return array_values(array_filter(
$qb->getQuery()->getResult(),
fn($u) => !$u->isAdmin()
));
}
}