10 Commits

Author SHA1 Message Date
63398086b7 creation de l'entite User 2026-03-13 12:17:36 +01:00
1454b9bfc8 Merge pull request 'refactor(services): renommage du service KazApiClient en KazApiService dans services.yaml' (#6) from fix/kazapi_client into main
Reviewed-on: #6
2026-03-13 09:59:15 +01:00
MLeveque
e299eb59ad refactor(services): renommage du service KazApiClient en KazApiService dans services.yaml 2026-03-13 09:55:51 +01:00
b6b82e1631 Merge pull request 'fix(compose): Correction du mapping de port pour exposer PostgreSQL sur 5432:5432.' (#5) from fix/docker_compose into main
Reviewed-on: #5
2026-03-12 12:16:24 +01:00
MLeveque
a8bcc7ae43 fix(compose): Correction du mapping de port pour exposer PostgreSQL sur 5432:5432. 2026-03-12 12:10:41 +01:00
f2365c08e9 Merge pull request 'docs: enrichissement du README.md' (#3) from docs/maj_documentation into main
Reviewed-on: #3
2026-03-01 18:10:31 +01:00
MLeveque
7a9dfa52db docs: enrichissement du README.md
- Ajout d'une section pour la procédure Git Flow (features, fixes, maintenance, documentation).
- Ajout du git clone dans les étapes de démarrage du projet.
2026-03-01 18:10:09 +01:00
ba83f4a075 Merge pull request 'refactor: suppression des fichiers, templates et configurations inutilisés' (#2) from feat/structure_fichiers_twig into main
Reviewed-on: #2
2026-03-01 18:00:19 +01:00
MLeveque
a515be554f refactor: suppression des fichiers, templates et configurations inutilisés 2026-03-01 17:59:32 +01:00
ec4919230b Merge pull request 'feat(api): implémentation du service KazApiService et intégration dans le UserController' (#1) from feat/ajout_client_kazapi into main
Reviewed-on: #1
2026-03-01 17:57:03 +01:00
16 changed files with 311 additions and 127 deletions

1
.env
View File

@@ -3,6 +3,7 @@ APP_SECRET=
APP_SHARE_DIR=var/share
APP_VERSION=0.0.1
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
MESSENGER_TRANSPORT_DSN="doctrine://default"
MAILER_DSN="smtp://localhost:1025"
DEFAULT_URI="http://localhost:8000"
KAZ_API_USER=

View File

@@ -18,7 +18,7 @@ Cette application web permet aux adhérents de l'association KAZ de gérer leur
Cette base est conçue pour évoluer et intégrer de nouveaux outils et fonctionnalités à l'avenir.
## Prérequis
- **PHP** 8.4 ou supérieur
- **PHP** 8.4
- **[Composer](https://getcomposer.org/download/)** : (Gestionnaire de dépendances PHP)
- **[Symfony CLI](https://getcomposer.org/download/)** (Interface en ligne de commande Symfony)
- **Docker** Permet de lancer les services lié: postgres (base de données), mailpit (serveur de messagerie pour le dev)
@@ -31,34 +31,77 @@ Le projet suit les standards de développement suivants :
- **[Git Flow](https://git-flow.readthedocs.io/fr/latest/presentation.html)** : Modèle de gestion de branches.
- **[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)** : Norme pour les messages de commit.
### Procédure de contribution (Git Flow)
Toutes les modifications doivent passer par une branche dédiée avant d'être fusionnées dans la branche principal `main` via une Pull Request (Demande d'ajout).
#### Exemple d'ajout d'une fonctionnalité (feature)
1. **Mise à jour de l'environnement local** :
```bash
git checkout main
git pull origin main
```
2. **Création de la branche de fonctionnalité** (préfixe `feat/`) :
```bash
git checkout -b feat/nom-de-ma-feature
```
3. **Développement et commit** (respectant les Conventional Commits) :
```bash
git add .
git commit -m "feat: ajout de la nouvelle fonctionnalité"
```
4. **Publication de la branche** :
```bash
git push origin feat/nom-de-ma-feature
```
5. **Création de la Pull Request** : Rendez-vous sur Gitea pour ouvrir une PR de `feat/nom-de-ma-feature` vers `main`. Une fois revue et validée, elle sera fusionnée via l'interface.
#### Exemple de correction de bug (fix)
La procédure est identique, mais utilisez le préfixe `fix/` :
```bash
git checkout -b fix/nom-du-bug
# ... corrections ...
git commit -m "fix: résolution du problème"
git push origin fix/nom-du-bug
```
Pour les tâches de maintenance ou documentation, utilisez respectivement les préfixes `chore/` ou `docs/`.
## Quick start
### 1. Installation des dépendances
Clonez le projet et installez les dépendances avec Composer :
### 1. Clonage du projet
Clonez le projet en utilisant SSH :
```bash
git clone ssh://git@git.kaz.bzh:2202/melvin-leveque/interface-kaznautes.git
cd interface-kaznautes
```
### 2. Installation des dépendances
Installez les dépendances avec Composer :
```bash
composer install
```
### 2. Configuration de l'environnement
### 3. Configuration de l'environnement
Copiez le fichier `.env` en `.env.local` et configurez vos accès à la base de données et à l'API :
```bash
cp .env .env.local
```
### 3. Base de données
### 4. Base de données
Créez la base de données et exécutez les migrations :
```bash
php bin/console doctrine:database:create
php bin/console doctrine:migrations:migrate
```
### 4. Installation des assets
### 5. Installation des assets
Le projet utilise AssetMapper. Installez les dépendances JS :
```bash
php bin/console importmap:install
```
### 5. Lancement du serveur
### 6. Lancement du serveur
Utilisez le serveur Symfony pour lancer le projet localement :
```bash
symfony serve -d

View File

@@ -1,81 +0,0 @@
const nameCheck = /^[-_a-zA-Z0-9]{4,22}$/;
const tokenCheck = /^[-_/+a-zA-Z0-9]{24,}$/;
// Generate and double-submit a CSRF token in a form field and a cookie, as defined by Symfony's SameOriginCsrfTokenManager
// Use `form.requestSubmit()` to ensure that the submit event is triggered. Using `form.submit()` will not trigger the event
// and thus this event-listener will not be executed.
document.addEventListener('submit', function (event) {
generateCsrfToken(event.target);
}, true);
// When @hotwired/turbo handles form submissions, send the CSRF token in a header in addition to a cookie
// The `framework.csrf_protection.check_header` config option needs to be enabled for the header to be checked
document.addEventListener('turbo:submit-start', function (event) {
const h = generateCsrfHeaders(event.detail.formSubmission.formElement);
Object.keys(h).map(function (k) {
event.detail.formSubmission.fetchRequest.headers[k] = h[k];
});
});
// When @hotwired/turbo handles form submissions, remove the CSRF cookie once a form has been submitted
document.addEventListener('turbo:submit-end', function (event) {
removeCsrfToken(event.detail.formSubmission.formElement);
});
export function generateCsrfToken (formElement) {
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
if (!csrfField) {
return;
}
let csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
let csrfToken = csrfField.value;
if (!csrfCookie && nameCheck.test(csrfToken)) {
csrfField.setAttribute('data-csrf-protection-cookie-value', csrfCookie = csrfToken);
csrfField.defaultValue = csrfToken = btoa(String.fromCharCode.apply(null, (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(18))));
}
csrfField.dispatchEvent(new Event('change', { bubbles: true }));
if (csrfCookie && tokenCheck.test(csrfToken)) {
const cookie = csrfCookie + '_' + csrfToken + '=' + csrfCookie + '; path=/; samesite=strict';
document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie;
}
}
export function generateCsrfHeaders (formElement) {
const headers = {};
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
if (!csrfField) {
return headers;
}
const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) {
headers[csrfCookie] = csrfField.value;
}
return headers;
}
export function removeCsrfToken (formElement) {
const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]');
if (!csrfField) {
return;
}
const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value');
if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) {
const cookie = csrfCookie + '_' + csrfField.value + '=0; path=/; samesite=strict; max-age=0';
document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie;
}
}
/* stimulusFetch: 'lazy' */
export default 'csrf-protection-controller';

View File

@@ -1,16 +0,0 @@
import { Controller } from '@hotwired/stimulus';
/*
* This is an example Stimulus controller!
*
* Any element with a data-controller="hello" attribute will cause
* this controller to be executed. The name "hello" comes from the filename:
* hello_controller.js -> "hello"
*
* Delete this file or adapt it for your use!
*/
export default class extends Controller {
connect() {
this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js';
}
}

View File

@@ -1,18 +0,0 @@
services:
###> doctrine/doctrine-bundle ###
database:
ports:
- "5432"
###< doctrine/doctrine-bundle ###
###> symfony/mailer ###
mailer:
image: axllent/mailpit
ports:
- "1025"
- "8025"
environment:
MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1
###< symfony/mailer ###

View File

@@ -3,7 +3,7 @@ services:
database:
image: postgres:${POSTGRES_VERSION:-16}-alpine
ports:
- "5432"
- "5432:5432"
environment:
POSTGRES_DB: ${POSTGRES_DB:-app}
# You should definitely change the password in production

View File

@@ -7,7 +7,7 @@ services:
App\:
resource: '../src/'
App\Service\KazApiClient:
App\Service\KazApiService:
arguments:
$kazApiClient: '@kaz_api.client'
$apiUser: '%env(KAZ_API_USER)%'

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260313104837 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE "user" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, role VARCHAR(255) NOT NULL, mail VARCHAR(255) NOT NULL, mail_quota VARCHAR(255) NOT NULL, mail_de_secours VARCHAR(255) NOT NULL, identifiant_kaz VARCHAR(255) NOT NULL, quota VARCHAR(255) NOT NULL, has_nextcloud_access BOOLEAN NOT NULL, nextcloud_quota VARCHAR(255) NOT NULL, has_mobilizon BOOLEAN NOT NULL, has_agora_access BOOLEAN NOT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE TABLE messenger_messages (id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL, body TEXT NOT NULL, headers TEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, available_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, delivered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 ON messenger_messages (queue_name, available_at, delivered_at, id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE "user"');
$this->addSql('DROP TABLE messenger_messages');
}
}

View File

@@ -11,7 +11,7 @@ class HomeController extends AbstractController
#[Route('/hello')]
public function hello(): Response
{
return $this->render('hello.html.twig', [
return $this->render('home/hello.html.twig', [
'name' => 'Melvin'
]);
}

179
src/Entity/User.php Normal file
View File

@@ -0,0 +1,179 @@
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints\Uuid;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
class User
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?Uuid $id ;
#[ORM\Column(length: 255)]
private ?string $role = null;
#[ORM\Column(length: 255)]
private ?string $mail = null;
#[ORM\Column(length: 255)]
private ?string $mailQuota = null;
#[ORM\Column(length: 255)]
private ?string $mailDeSecours = null;
#[ORM\Column(length: 255)]
private ?string $identifiantKaz = null;
#[ORM\Column(length: 255)]
private ?string $quota = null;
#[ORM\Column]
private ?bool $hasNextcloudAccess = null;
#[ORM\Column(length: 255)]
private ?string $nextcloudQuota = null;
#[ORM\Column]
private ?bool $hasMobilizon = null;
#[ORM\Column]
private ?bool $hasAgoraAccess = null;
public function getId(): ?Uuid
{
return $this->id;
}
public function setId(Uuid $id): static
{
$this->id = $id;
return $this;
}
public function getRole(): ?string
{
return $this->role;
}
public function setRole(string $role): static
{
$this->role = $role;
return $this;
}
public function getMail(): ?string
{
return $this->mail;
}
public function setMail(string $mail): static
{
$this->mail = $mail;
return $this;
}
public function getMailQuota(): ?string
{
return $this->mailQuota;
}
public function setMailQuota(string $mailQuota): static
{
$this->mailQuota = $mailQuota;
return $this;
}
public function getMailDeSecours(): ?string
{
return $this->mailDeSecours;
}
public function setMailDeSecours(string $mailDeSecours): static
{
$this->mailDeSecours = $mailDeSecours;
return $this;
}
public function getIdentifiantKaz(): ?string
{
return $this->identifiantKaz;
}
public function setIdentifiantKaz(string $identifiantKaz): static
{
$this->identifiantKaz = $identifiantKaz;
return $this;
}
public function getQuota(): ?string
{
return $this->quota;
}
public function setQuota(string $quota): static
{
$this->quota = $quota;
return $this;
}
public function hasNextcloudAccess(): ?bool
{
return $this->hasNextcloudAccess;
}
public function setHasNextcloudAccess(bool $hasNextcloudAccess): static
{
$this->hasNextcloudAccess = $hasNextcloudAccess;
return $this;
}
public function getNextcloudQuota(): ?string
{
return $this->nextcloudQuota;
}
public function setNextcloudQuota(string $nextcloudQuota): static
{
$this->nextcloudQuota = $nextcloudQuota;
return $this;
}
public function hasMobilizon(): ?bool
{
return $this->hasMobilizon;
}
public function setHasMobilizon(bool $hasMobilizon): static
{
$this->hasMobilizon = $hasMobilizon;
return $this;
}
public function hasAgoraAccess(): ?bool
{
return $this->hasAgoraAccess;
}
public function setHasAgoraAccess(bool $hasAgoraAccess): static
{
$this->hasAgoraAccess = $hasAgoraAccess;
return $this;
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<User>
*/
class UserRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
// /**
// * @return User[] Returns an array of User objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('u.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?User
// {
// return $this->createQueryBuilder('u')
// ->andWhere('u.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@@ -0,0 +1 @@
error404.html.twig

View File

@@ -1,2 +0,0 @@
{# templates/hellp.html.twig #}
<h1>Hello ! {{ name }}</h1>

View File