feat/cnx_api #11
2
.env
2
.env
@@ -1,5 +1,5 @@
|
|||||||
APP_ENV=dev
|
APP_ENV=dev
|
||||||
APP_SECRET=
|
APP_SECRET=je_te_remplis_parce_que_tu_me_mets_des_messages_d_erreur
|
||||||
APP_SHARE_DIR=var/share
|
APP_SHARE_DIR=var/share
|
||||||
APP_VERSION=0.0.1
|
APP_VERSION=0.0.1
|
||||||
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
|
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -33,3 +33,8 @@ Thumbs.db
|
|||||||
npm-debug.log
|
npm-debug.log
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
###< symfony/webpack-encore-bundle ###
|
###< symfony/webpack-encore-bundle ###
|
||||||
|
|
||||||
|
###> symfony/asset-mapper ###
|
||||||
|
/public/assets/
|
||||||
|
/assets/vendor/
|
||||||
|
###< symfony/asset-mapper ###
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
"symfony/web-link": "8.0.*",
|
"symfony/web-link": "8.0.*",
|
||||||
"symfony/webpack-encore-bundle": "^2.4",
|
"symfony/webpack-encore-bundle": "^2.4",
|
||||||
"symfony/yaml": "8.0.*",
|
"symfony/yaml": "8.0.*",
|
||||||
|
"symfonycasts/tailwind-bundle": "^0.12.0",
|
||||||
"twig/extra-bundle": "^2.12|^3.0",
|
"twig/extra-bundle": "^2.12|^3.0",
|
||||||
"twig/twig": "^2.12|^3.0"
|
"twig/twig": "^2.12|^3.0"
|
||||||
},
|
},
|
||||||
@@ -80,7 +81,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"auto-scripts": {
|
"auto-scripts": {
|
||||||
"cache:clear": "symfony-cmd",
|
"cache:clear": "symfony-cmd",
|
||||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
"assets:install %PUBLIC_DIR%": "symfony-cmd",
|
||||||
|
"importmap:install": "symfony-cmd"
|
||||||
},
|
},
|
||||||
"post-install-cmd": [
|
"post-install-cmd": [
|
||||||
"@auto-scripts"
|
"@auto-scripts"
|
||||||
|
|||||||
228
composer.lock
generated
228
composer.lock
generated
@@ -4,8 +4,85 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "4597facec97a6ff342cba0371179ad02",
|
"content-hash": "b2f5377481dc83317c4b7c49f2dd183e",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "composer/semver",
|
||||||
|
"version": "3.4.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/composer/semver.git",
|
||||||
|
"reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
|
||||||
|
"reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.11",
|
||||||
|
"symfony/phpunit-bridge": "^3 || ^7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Composer\\Semver\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nils Adermann",
|
||||||
|
"email": "naderman@naderman.de",
|
||||||
|
"homepage": "http://www.naderman.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jordi Boggiano",
|
||||||
|
"email": "j.boggiano@seld.be",
|
||||||
|
"homepage": "http://seld.be"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rob Bast",
|
||||||
|
"email": "rob.bast@gmail.com",
|
||||||
|
"homepage": "http://robbast.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Semver library that offers utilities, version constraint parsing and validation.",
|
||||||
|
"keywords": [
|
||||||
|
"semantic",
|
||||||
|
"semver",
|
||||||
|
"validation",
|
||||||
|
"versioning"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||||
|
"issues": "https://github.com/composer/semver/issues",
|
||||||
|
"source": "https://github.com/composer/semver/tree/3.4.4"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://packagist.com",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/composer",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-08-20T19:15:30+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/collections",
|
"name": "doctrine/collections",
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
@@ -1950,6 +2027,87 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-01-13T13:06:50+00:00"
|
"time": "2026-01-13T13:06:50+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/asset-mapper",
|
||||||
|
"version": "v8.0.6",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/asset-mapper.git",
|
||||||
|
"reference": "80635c3722b9bb5481e0282497ae23796dcd3712"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/asset-mapper/zipball/80635c3722b9bb5481e0282497ae23796dcd3712",
|
||||||
|
"reference": "80635c3722b9bb5481e0282497ae23796dcd3712",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/semver": "^3.0",
|
||||||
|
"php": ">=8.4",
|
||||||
|
"symfony/filesystem": "^7.4|^8.0",
|
||||||
|
"symfony/http-client": "^7.4|^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/asset": "^7.4|^8.0",
|
||||||
|
"symfony/browser-kit": "^7.4|^8.0",
|
||||||
|
"symfony/console": "^7.4|^8.0",
|
||||||
|
"symfony/event-dispatcher-contracts": "^3.0",
|
||||||
|
"symfony/finder": "^7.4|^8.0",
|
||||||
|
"symfony/framework-bundle": "^7.4|^8.0",
|
||||||
|
"symfony/http-foundation": "^7.4|^8.0",
|
||||||
|
"symfony/http-kernel": "^7.4|^8.0",
|
||||||
|
"symfony/process": "^7.4|^8.0",
|
||||||
|
"symfony/runtime": "^7.4|^8.0",
|
||||||
|
"symfony/web-link": "^7.4|^8.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\AssetMapper\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Maps directories of assets & makes them available in a public directory with versioned filenames.",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/asset-mapper/tree/v8.0.6"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-02-17T13:07:04+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/cache",
|
"name": "symfony/cache",
|
||||||
"version": "v8.0.5",
|
"version": "v8.0.5",
|
||||||
@@ -3293,16 +3451,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/form",
|
"name": "symfony/form",
|
||||||
"version": "v8.0.4",
|
"version": "v8.0.7",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/form.git",
|
"url": "https://github.com/symfony/form.git",
|
||||||
"reference": "c34ec2c2648e2dfedab3ce7e3c6c86f8d89c3092"
|
"reference": "954e17b053dad9fb227ebd90260752e3a46bb06a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/form/zipball/c34ec2c2648e2dfedab3ce7e3c6c86f8d89c3092",
|
"url": "https://api.github.com/repos/symfony/form/zipball/954e17b053dad9fb227ebd90260752e3a46bb06a",
|
||||||
"reference": "c34ec2c2648e2dfedab3ce7e3c6c86f8d89c3092",
|
"reference": "954e17b053dad9fb227ebd90260752e3a46bb06a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -3364,7 +3522,7 @@
|
|||||||
"description": "Allows to easily create, process and reuse HTML forms",
|
"description": "Allows to easily create, process and reuse HTML forms",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/form/tree/v8.0.4"
|
"source": "https://github.com/symfony/form/tree/v8.0.7"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3384,7 +3542,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2026-01-23T11:07:10+00:00"
|
"time": "2026-03-06T13:17:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/framework-bundle",
|
"name": "symfony/framework-bundle",
|
||||||
@@ -7473,6 +7631,62 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-12-04T18:17:06+00:00"
|
"time": "2025-12-04T18:17:06+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfonycasts/tailwind-bundle",
|
||||||
|
"version": "v0.12.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/SymfonyCasts/tailwind-bundle.git",
|
||||||
|
"reference": "17c85e25d3ceb54b8599e8ca4c5b67c485f2a48a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/SymfonyCasts/tailwind-bundle/zipball/17c85e25d3ceb54b8599e8ca4c5b67c485f2a48a",
|
||||||
|
"reference": "17c85e25d3ceb54b8599e8ca4c5b67c485f2a48a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1",
|
||||||
|
"symfony/asset-mapper": "^6.3|^7.0|^8.0",
|
||||||
|
"symfony/cache": "^6.3|^7.0|^8.0",
|
||||||
|
"symfony/console": "^5.4|^6.3|^7.0|^8.0",
|
||||||
|
"symfony/deprecation-contracts": "^2.2|^3.0",
|
||||||
|
"symfony/http-client": "^5.4|^6.3|^7.0|^8.0",
|
||||||
|
"symfony/process": "^5.4|^6.3|^7.0|^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.6",
|
||||||
|
"symfony/filesystem": "^6.3|^7.0|^8.0",
|
||||||
|
"symfony/framework-bundle": "^6.3|^7.0|^8.0",
|
||||||
|
"symfony/phpunit-bridge": "^6.3.9|^7.0|^8.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfonycasts\\TailwindBundle\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ryan Weaver",
|
||||||
|
"homepage": "https://symfonycasts.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Delightful Tailwind Support for Symfony + AssetMapper",
|
||||||
|
"keywords": [
|
||||||
|
"asset-mapper",
|
||||||
|
"tailwind"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/SymfonyCasts/tailwind-bundle/issues",
|
||||||
|
"source": "https://github.com/SymfonyCasts/tailwind-bundle/tree/v0.12.0"
|
||||||
|
},
|
||||||
|
"time": "2025-11-24T10:14:04+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/extra-bundle",
|
"name": "twig/extra-bundle",
|
||||||
"version": "v3.23.0",
|
"version": "v3.23.0",
|
||||||
|
|||||||
@@ -15,4 +15,5 @@ return [
|
|||||||
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
|
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
|
||||||
Symfony\UX\Turbo\TurboBundle::class => ['all' => true],
|
Symfony\UX\Turbo\TurboBundle::class => ['all' => true],
|
||||||
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
||||||
|
Symfonycasts\TailwindBundle\SymfonycastsTailwindBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|||||||
11
config/packages/asset_mapper.yaml
Normal file
11
config/packages/asset_mapper.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
framework:
|
||||||
|
asset_mapper:
|
||||||
|
# The paths to make available to the asset mapper.
|
||||||
|
paths:
|
||||||
|
- assets/
|
||||||
|
missing_import_mode: strict
|
||||||
|
|
||||||
|
when@prod:
|
||||||
|
framework:
|
||||||
|
asset_mapper:
|
||||||
|
missing_import_mode: warn
|
||||||
@@ -32,7 +32,17 @@ security:
|
|||||||
check_path: app_login
|
check_path: app_login
|
||||||
enable_csrf: true
|
enable_csrf: true
|
||||||
logout:
|
logout:
|
||||||
|
# où rediriger après la déconnexion
|
||||||
path: app_logout
|
path: app_logout
|
||||||
|
# custom_authenticator: App\Security\AppCustomAuthenticator
|
||||||
|
|
||||||
|
remember_me:
|
||||||
|
secret: '%kernel.secret%'
|
||||||
|
lifetime: 604800
|
||||||
|
path: /
|
||||||
|
# by default, the feature is enabled by checking a checkbox in the
|
||||||
|
# login form, uncomment the following line to always enable it.
|
||||||
|
#always_remember_me: true
|
||||||
# where to redirect after logout
|
# where to redirect after logout
|
||||||
# target: app_any_route
|
# target: app_any_route
|
||||||
|
|
||||||
@@ -45,8 +55,8 @@ security:
|
|||||||
# Note: Only the *first* matching rule is applied
|
# Note: Only the *first* matching rule is applied
|
||||||
# autorisations
|
# autorisations
|
||||||
access_control:
|
access_control:
|
||||||
# - { path: ^/admin, roles: ROLE_ADMIN }
|
- { path: ^/admin, roles: ROLE_ADMIN }
|
||||||
# - { path: ^/profile, roles: ROLE_USER }
|
- { path: ^/user, roles: ROLE_USER }
|
||||||
|
|
||||||
when@test:
|
when@test:
|
||||||
security:
|
security:
|
||||||
|
|||||||
6
config/packages/symfonycasts_tailwind.yaml
Normal file
6
config/packages/symfonycasts_tailwind.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
symfonycasts_tailwind:
|
||||||
|
# Specify the EXACT version of Tailwind CSS you want to use
|
||||||
|
binary_version: 'v4.1.11'
|
||||||
|
|
||||||
|
# Alternatively, you can specify the path to the binary that you manage yourself
|
||||||
|
#binary: 'node_modules/.bin/tailwindcss'
|
||||||
@@ -280,7 +280,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* }>,
|
* }>,
|
||||||
* },
|
* },
|
||||||
* asset_mapper?: bool|array{ // Asset Mapper configuration
|
* asset_mapper?: bool|array{ // Asset Mapper configuration
|
||||||
* enabled?: bool|Param, // Default: false
|
* enabled?: bool|Param, // Default: true
|
||||||
* paths?: array<string, scalar|Param|null>,
|
* paths?: array<string, scalar|Param|null>,
|
||||||
* excluded_patterns?: list<scalar|Param|null>,
|
* excluded_patterns?: list<scalar|Param|null>,
|
||||||
* exclude_dotfiles?: bool|Param, // If true, any files starting with "." will be excluded from the asset mapper. // Default: true
|
* exclude_dotfiles?: bool|Param, // If true, any files starting with "." will be excluded from the asset mapper. // Default: true
|
||||||
@@ -1465,6 +1465,15 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* },
|
* },
|
||||||
* default_transport?: scalar|Param|null, // Default: "default"
|
* default_transport?: scalar|Param|null, // Default: "default"
|
||||||
* }
|
* }
|
||||||
|
* @psalm-type SymfonycastsTailwindConfig = array{
|
||||||
|
* input_css?: list<scalar|Param|null>,
|
||||||
|
* config_file?: scalar|Param|null, // Path to the tailwind.config.js file // Default: "%kernel.project_dir%/tailwind.config.js"
|
||||||
|
* binary?: scalar|Param|null, // The tailwind binary to use instead of downloading a new one // Default: null
|
||||||
|
* binary_version?: scalar|Param|null, // Tailwind CLI version to download - null means the latest version // Default: null
|
||||||
|
* binary_platform?: "auto"|"linux-arm64"|"linux-arm64-musl"|"linux-x64"|"linux-x64-musl"|"macos-arm64"|"macos-x64"|"windows-x64"|Param, // Tailwind CLI platform to download - "auto" will try to detect the platform automatically // Default: "auto"
|
||||||
|
* postcss_config_file?: scalar|Param|null, // Path to PostCSS config file which is passed to the Tailwind CLI // Default: null
|
||||||
|
* strict_mode?: bool|Param|null, // When enabled, an exception will be thrown if there are no built assets (default: false in `test` env, true otherwise) // Default: null
|
||||||
|
* }
|
||||||
* @psalm-type ConfigType = array{
|
* @psalm-type ConfigType = array{
|
||||||
* imports?: ImportsConfig,
|
* imports?: ImportsConfig,
|
||||||
* parameters?: ParametersConfig,
|
* parameters?: ParametersConfig,
|
||||||
@@ -1479,6 +1488,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* webpack_encore?: WebpackEncoreConfig,
|
* webpack_encore?: WebpackEncoreConfig,
|
||||||
* stimulus?: StimulusConfig,
|
* stimulus?: StimulusConfig,
|
||||||
* turbo?: TurboConfig,
|
* turbo?: TurboConfig,
|
||||||
|
* symfonycasts_tailwind?: SymfonycastsTailwindConfig,
|
||||||
* "when@dev"?: array{
|
* "when@dev"?: array{
|
||||||
* imports?: ImportsConfig,
|
* imports?: ImportsConfig,
|
||||||
* parameters?: ParametersConfig,
|
* parameters?: ParametersConfig,
|
||||||
@@ -1496,6 +1506,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* webpack_encore?: WebpackEncoreConfig,
|
* webpack_encore?: WebpackEncoreConfig,
|
||||||
* stimulus?: StimulusConfig,
|
* stimulus?: StimulusConfig,
|
||||||
* turbo?: TurboConfig,
|
* turbo?: TurboConfig,
|
||||||
|
* symfonycasts_tailwind?: SymfonycastsTailwindConfig,
|
||||||
* },
|
* },
|
||||||
* "when@prod"?: array{
|
* "when@prod"?: array{
|
||||||
* imports?: ImportsConfig,
|
* imports?: ImportsConfig,
|
||||||
@@ -1511,6 +1522,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* webpack_encore?: WebpackEncoreConfig,
|
* webpack_encore?: WebpackEncoreConfig,
|
||||||
* stimulus?: StimulusConfig,
|
* stimulus?: StimulusConfig,
|
||||||
* turbo?: TurboConfig,
|
* turbo?: TurboConfig,
|
||||||
|
* symfonycasts_tailwind?: SymfonycastsTailwindConfig,
|
||||||
* },
|
* },
|
||||||
* "when@test"?: array{
|
* "when@test"?: array{
|
||||||
* imports?: ImportsConfig,
|
* imports?: ImportsConfig,
|
||||||
@@ -1527,6 +1539,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* webpack_encore?: WebpackEncoreConfig,
|
* webpack_encore?: WebpackEncoreConfig,
|
||||||
* stimulus?: StimulusConfig,
|
* stimulus?: StimulusConfig,
|
||||||
* turbo?: TurboConfig,
|
* turbo?: TurboConfig,
|
||||||
|
* symfonycasts_tailwind?: SymfonycastsTailwindConfig,
|
||||||
* },
|
* },
|
||||||
* ...<string, ExtensionType|array{ // extra keys must follow the when@%env% pattern or match an extension alias
|
* ...<string, ExtensionType|array{ // extra keys must follow the when@%env% pattern or match an extension alias
|
||||||
* imports?: ImportsConfig,
|
* imports?: ImportsConfig,
|
||||||
|
|||||||
28
importmap.php
Normal file
28
importmap.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the importmap for this application.
|
||||||
|
*
|
||||||
|
* - "path" is a path inside the asset mapper system. Use the
|
||||||
|
* "debug:asset-map" command to see the full list of paths.
|
||||||
|
*
|
||||||
|
* - "entrypoint" (JavaScript only) set to true for any module that will
|
||||||
|
* be used as an "entrypoint" (and passed to the importmap() Twig function).
|
||||||
|
*
|
||||||
|
* The "importmap:require" command can be used to add new entries to this file.
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
'app' => [
|
||||||
|
'path' => './assets/app.js',
|
||||||
|
'entrypoint' => true,
|
||||||
|
],
|
||||||
|
'@hotwired/stimulus' => [
|
||||||
|
'version' => '3.2.2',
|
||||||
|
],
|
||||||
|
'@symfony/stimulus-bundle' => [
|
||||||
|
'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js',
|
||||||
|
],
|
||||||
|
'@hotwired/turbo' => [
|
||||||
|
'version' => '7.3.0',
|
||||||
|
],
|
||||||
|
];
|
||||||
@@ -2,38 +2,63 @@
|
|||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
use LogicException;
|
use App\Repository\UserRepository; // 👈 AJOUTE CETTE LIGNE ICI !
|
||||||
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; // 👈 ET CELLE-CI AUSSI !
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||||
|
|
||||||
class SecurityController extends AbstractController
|
class SecurityController extends AbstractController
|
||||||
{
|
{
|
||||||
#[Route(path: '/login', name: 'app_login', methods: ['GET','POST'])]
|
#[Route(path: '/test-password', name: 'test_password')]
|
||||||
public function login(AuthenticationUtils $authenticationUtils): Response
|
public function testPassword(UserRepository $userRepo, UserPasswordHasherInterface $hasher): Response
|
||||||
{
|
{
|
||||||
|
// 1. On va chercher ton admin directement en base
|
||||||
|
$admin = $userRepo->findOneBy(['email' => 'admin@kaz.fr']);
|
||||||
|
|
||||||
|
if (!$admin) {
|
||||||
|
dd("L'utilisateur n'existe pas dans la base lue par ce contrôleur !");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. On vérifie si "password" est bien le bon mot de passe
|
||||||
|
$isValid = $hasher->isPasswordValid($admin, 'password');
|
||||||
|
|
||||||
|
// 3. On affiche le résultat brut
|
||||||
|
dd([
|
||||||
|
'email' => $admin->getEmail(),
|
||||||
|
'mot_de_passe_hache' => $admin->getPassword(),
|
||||||
|
'est_ce_que_password_est_valide' => $isValid
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
#[Route(path: '/login', name: 'app_login')]
|
||||||
|
public function login(AuthenticationUtils $authenticationUtils, Request $request): Response // 👈 2. ON AJOUTE $request ICI
|
||||||
|
{
|
||||||
|
// 🚨 3. NOTRE CODE DE DÉTECTIVE POUR VOIR CE QUI EST ENVOYÉ :
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
dd($request->request->all());
|
||||||
|
}
|
||||||
|
// 🚨 FIN DU CODE DE DÉTECTIVE
|
||||||
|
|
||||||
// si on a un utilisateur déjà connecté, alors on le redirige sur la page d'accueil
|
|
||||||
if ($this->getUser()) {
|
if ($this->getUser()) {
|
||||||
return $this->redirectToRoute('app_home');
|
return $this->redirectToRoute('app_home');
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the login error if there is one
|
// Récupération de l'erreur de connexion (s'il y en a une)
|
||||||
$error = $authenticationUtils->getLastAuthenticationError();
|
$error = $authenticationUtils->getLastAuthenticationError();
|
||||||
|
// Récupération du dernier nom d'utilisateur saisi par l'adhérent
|
||||||
// last username entered by the user
|
|
||||||
$lastUsername = $authenticationUtils->getLastUsername();
|
$lastUsername = $authenticationUtils->getLastUsername();
|
||||||
|
|
||||||
return $this->render('security/login.html.twig', [
|
return $this->render('security/login.html.twig', [
|
||||||
'last_username' => $lastUsername,
|
'last_username' => $lastUsername,
|
||||||
'error' => $error,
|
'error' => $error
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route(path: '/logout', name: 'app_logout', methods: ['POST'])]
|
#[Route(path: '/logout', name: 'app_logout')]
|
||||||
public function logout(): void
|
public function logout(): void
|
||||||
{
|
{
|
||||||
throw new LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
|
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Form\ChangePasswordType;
|
||||||
use App\Service\KazApiService;
|
use App\Service\KazApiService;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\Form\FormError;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||||||
@@ -14,9 +19,6 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
|||||||
|
|
||||||
class UserController extends AbstractController
|
class UserController extends AbstractController
|
||||||
{
|
{
|
||||||
|
|
||||||
// TODO : UserPasswordHasherInterface
|
|
||||||
// voir : https://symfony.com/doc/current/security/passwords.html#hashing-the-password
|
|
||||||
/**
|
/**
|
||||||
* Permet de vérifier si un utilisateur existe dans le ldap.
|
* Permet de vérifier si un utilisateur existe dans le ldap.
|
||||||
*
|
*
|
||||||
@@ -30,6 +32,7 @@ class UserController extends AbstractController
|
|||||||
* @throws ServerExceptionInterface
|
* @throws ServerExceptionInterface
|
||||||
* @throws TransportExceptionInterface
|
* @throws TransportExceptionInterface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[Route('/user/{email}', name: 'app_user', methods: ['GET'])]
|
#[Route('/user/{email}', name: 'app_user', methods: ['GET'])]
|
||||||
public function index(string $email, KazApiService $apiClient): Response
|
public function index(string $email, KazApiService $apiClient): Response
|
||||||
{
|
{
|
||||||
@@ -39,4 +42,45 @@ class UserController extends AbstractController
|
|||||||
'exist' => $exist,
|
'exist' => $exist,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/user/mot-de-passe', name: 'app_user_edit_password', methods: ['GET', 'POST'])]
|
||||||
|
public function editPassword(Request $request, UserPasswordHasherInterface $hasher, EntityManagerInterface $entityManager): Response
|
||||||
|
{
|
||||||
|
# Récupération de l'adhérent actuellement connecté
|
||||||
|
$user = $this->getUser();
|
||||||
|
|
||||||
|
# Création du formulaire
|
||||||
|
$form = $this->createForm(ChangePasswordType::class);
|
||||||
|
|
||||||
|
# Liaison du formulaire à la requête HTTP
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
# Vérification du formulaire, s'il est bien soumis et valide
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
# Récupération des données du formulaire
|
||||||
|
$user = $this->getUser();
|
||||||
|
$plainOldPassword = $form->get('oldPassword')->getData();
|
||||||
|
$newPassword = $form->get('newPassword')->getData();
|
||||||
|
|
||||||
|
# Vérification de l'ancien mot de passe
|
||||||
|
if (!$hasher->isPasswordValid($user, $plainOldPassword)) {
|
||||||
|
$form->get('oldPassword')->addError(new FormError('L\'ancien mot de passe est incorrect.'));
|
||||||
|
} else {
|
||||||
|
# Si tout est OK : Hachage du mot de passe
|
||||||
|
$hashedPassword = $hasher->hashPassword($user, $newPassword);
|
||||||
|
$user->setPassword($hashedPassword);
|
||||||
|
|
||||||
|
# Sauvegarde en BDD
|
||||||
|
$entityManager->flush();
|
||||||
|
|
||||||
|
# Message de succès pour l'adhérent
|
||||||
|
$this->addFlash('success', 'Votre mot de passe a bien été mis à jour !');
|
||||||
|
|
||||||
|
return $this->redirectToRoute('app_user_edit_password');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->render('user/edit_password.html.twig', [
|
||||||
|
'form' => $form->createView(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -29,20 +29,15 @@ class AppFixtures extends Fixture
|
|||||||
for ($i = 0; $i < 10; $i++) {
|
for ($i = 0; $i < 10; $i++) {
|
||||||
# Instanciation d'un nouvel utilisateur (Adhérent)
|
# Instanciation d'un nouvel utilisateur (Adhérent)
|
||||||
$user = new User();
|
$user = new User();
|
||||||
|
|
||||||
# Attribution d'un email aléatoire et unique
|
# Attribution d'un email aléatoire et unique
|
||||||
$user->setEmail($faker->unique()->safeEmail());
|
$user->setEmail($faker->unique()->safeEmail());
|
||||||
|
|
||||||
# Définition des droits d'accès de l'utilisateur
|
# Définition des droits d'accès de l'utilisateur
|
||||||
$user->setRoles(['ROLE_USER']);
|
$user->setRoles(['ROLE_USER']);
|
||||||
|
|
||||||
# Hachage sécurisé du mot de passe "password"
|
# Hachage sécurisé du mot de passe "password"
|
||||||
$user->setPassword($this->hasher->hashPassword($user, 'password'));
|
$user->setPassword($this->hasher->hashPassword($user, 'password'));
|
||||||
|
|
||||||
# Définition d'un NOM et Prénom
|
# Définition d'un NOM et Prénom
|
||||||
$user->setFirstname($faker->firstName());
|
$user->setFirstname($faker->firstName());
|
||||||
$user->setLastname($faker->lastName());
|
$user->setLastname($faker->lastName());
|
||||||
|
|
||||||
# autres fixtures à modifier plus tard
|
# autres fixtures à modifier plus tard
|
||||||
$user->setNextcloudQuota($faker->numberBetween(1, 20) . 'G');
|
$user->setNextcloudQuota($faker->numberBetween(1, 20) . 'G');
|
||||||
$user->setQuota($faker->numberBetween(1, 10) . 'G');
|
$user->setQuota($faker->numberBetween(1, 10) . 'G');
|
||||||
@@ -52,10 +47,31 @@ class AppFixtures extends Fixture
|
|||||||
$user->setHasMobilizon($faker->boolean(50));
|
$user->setHasMobilizon($faker->boolean(50));
|
||||||
$user->setHasNextcloudAccess($faker->boolean(90));
|
$user->setHasNextcloudAccess($faker->boolean(90));
|
||||||
$user->setIdentifiantKaz($faker->uuid());
|
$user->setIdentifiantKaz($faker->uuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Création d'un compte de test fixe
|
||||||
|
$admin = new User();
|
||||||
|
$admin->setEmail('admin@kaz.bzh');
|
||||||
|
$admin->setRoles(['ROLE_USER', 'ROLE_ADMIN']);
|
||||||
|
$admin->setPassword($this->hasher->hashPassword($admin, 'password'));
|
||||||
|
$admin->setFirstName('Admin');
|
||||||
|
$admin->setLastName('KAZ');
|
||||||
|
|
||||||
|
// Remplissage des champs obligatoires restants pour éviter les erreurs SQL
|
||||||
|
$admin->setEmailDeSecours('secours@kaz.bzh');
|
||||||
|
$admin->setIdentifiantKaz('ADMIN-KAZ-001');
|
||||||
|
$admin->setQuota('5G');
|
||||||
|
$admin->setEmailQuota('1G');
|
||||||
|
$admin->setNextcloudQuota('10G');
|
||||||
|
$admin->setHasNextcloudAccess(true);
|
||||||
|
$admin->setHasMobilizon(true);
|
||||||
|
$admin->setHasAgoraAccess(true);
|
||||||
|
|
||||||
|
$manager->persist($admin);
|
||||||
|
|
||||||
# Préparation de l'enregistrement de l'objet en base de données
|
# Préparation de l'enregistrement de l'objet en base de données
|
||||||
$manager->persist($user);
|
$manager->persist($user);
|
||||||
}
|
|
||||||
# Exécution réelle des requêtes SQL (envoi vers la base), une fois la bouche finie
|
# Exécution réelle des requêtes SQL (envoi vers la base), une fois la bouche finie
|
||||||
$manager->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Entity;
|
|||||||
|
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
use Symfony\Component\Uid\Uuid;
|
use Symfony\Component\Uid\Uuid;
|
||||||
@@ -11,6 +12,7 @@ use Symfony\Component\Uid\Uuid;
|
|||||||
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||||
#[ORM\Table(name: '`user`')]
|
#[ORM\Table(name: '`user`')]
|
||||||
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
|
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
|
||||||
|
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
|
||||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||||
{
|
{
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
@@ -35,7 +37,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
|||||||
private ?string $password = null;
|
private ?string $password = null;
|
||||||
|
|
||||||
#[ORM\Column(length: 255)]
|
#[ORM\Column(length: 255)]
|
||||||
private ?string $emailQuota = null;
|
private ?string $emailQuota = '1G';
|
||||||
|
|
||||||
#[ORM\Column(length: 255)]
|
#[ORM\Column(length: 255)]
|
||||||
private ?string $emailDeSecours = null;
|
private ?string $emailDeSecours = null;
|
||||||
@@ -50,7 +52,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
|||||||
private ?bool $hasNextcloudAccess = null;
|
private ?bool $hasNextcloudAccess = null;
|
||||||
|
|
||||||
#[ORM\Column(length: 255)]
|
#[ORM\Column(length: 255)]
|
||||||
private ?string $nextcloudQuota = '1G';
|
private ?string $nextcloudQuota = null;
|
||||||
|
|
||||||
#[ORM\Column]
|
#[ORM\Column]
|
||||||
private ?bool $hasMobilizon = null;
|
private ?bool $hasMobilizon = null;
|
||||||
@@ -104,9 +106,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
|||||||
public function getRoles(): array
|
public function getRoles(): array
|
||||||
{
|
{
|
||||||
$roles = $this->roles;
|
$roles = $this->roles;
|
||||||
// guarantee every user at least has ROLE_USER
|
$roles[] = 'ROLE_USER'; // garantit qu'il a au moins ce rôle
|
||||||
$roles[] = 'ROLE_USER';
|
|
||||||
|
|
||||||
return array_unique($roles);
|
return array_unique($roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +120,16 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see UserInterface
|
||||||
|
* Ajout de cette fonction, car obligatoire pour faire fonctionner UserInterface correctement
|
||||||
|
*/
|
||||||
|
public function eraseCredentials(): void
|
||||||
|
{
|
||||||
|
// Si vous stockez des données temporaires sensibles sur l'utilisateur, nettoyez-les ici
|
||||||
|
// $this->plainPassword = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see PasswordAuthenticatedUserInterface
|
* @see PasswordAuthenticatedUserInterface
|
||||||
*/
|
*/
|
||||||
|
|||||||
27
symfony.lock
27
symfony.lock
@@ -62,6 +62,21 @@
|
|||||||
"bin/phpunit"
|
"bin/phpunit"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfony/asset-mapper": {
|
||||||
|
"version": "8.0",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "6.4",
|
||||||
|
"ref": "5ad1308aa756d58f999ffbe1540d1189f5d7d14a"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"assets/app.js",
|
||||||
|
"assets/styles/app.css",
|
||||||
|
"config/packages/asset_mapper.yaml",
|
||||||
|
"importmap.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
"symfony/console": {
|
"symfony/console": {
|
||||||
"version": "8.0",
|
"version": "8.0",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
@@ -341,6 +356,18 @@
|
|||||||
"webpack.config.js"
|
"webpack.config.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfonycasts/tailwind-bundle": {
|
||||||
|
"version": "0.12",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "0.8",
|
||||||
|
"ref": "d0bd0276f74de90adfaa4c6cd74cc0caacd77e0a"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/symfonycasts_tailwind.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
"twig/extra-bundle": {
|
"twig/extra-bundle": {
|
||||||
"version": "v3.23.0"
|
"version": "v3.23.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: [
|
content: [
|
||||||
"./templates/**/*.html.twig",
|
|
||||||
"./assets/**/*.js",
|
"./assets/**/*.js",
|
||||||
|
"./templates/**/*.html.twig",
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {
|
||||||
|
colors: {
|
||||||
|
'brand-teal': '#4DD5C8', // Boutons
|
||||||
|
'brand-gold': '#E6A638', // Accent
|
||||||
|
'brand-dark': '#000000', // Police
|
||||||
|
'bg-primary': '#F9FCF7', // Fond principal
|
||||||
|
'bg-secondary': '#23978B', // Fond secondaire
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
'sans': ['Sora', 'system-ui', 'sans-serif'],
|
||||||
|
'title': ['Caveat', 'cursive'],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
}
|
||||||
@@ -2,16 +2,30 @@
|
|||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
<title>{% block title %}Association KAZ{% endblock %}</title>
|
||||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||||
{% block stylesheets %}
|
{% block stylesheets %}
|
||||||
<link rel="stylesheet" href="/assets/styles/app.css">
|
<link rel="stylesheet" href="{{ asset('styles/app.css') }}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block javascripts %}
|
{% block javascripts %}
|
||||||
|
{% block importmap %}{{ importmap('app') }}{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<main class="container mx-auto mt-4 px-4">
|
||||||
|
{# Section des notifications #}
|
||||||
|
{% for label, messages in app.flashes %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="p-4 mb-4 rounded-lg shadow-md border-l-4 {{ label == 'success' ? 'bg-brand-teal text-brand-dark border-bg-secondary' : 'bg-brand-gold text-brand-dark border-red-700' }}">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% block body %}{% endblock %}
|
{% block body %}{% endblock %}
|
||||||
|
</main>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Accueil | Tableau de bord KAZ{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="mt-8 p-6 bg-white rounded-lg shadow-md border border-gray-200">
|
||||||
|
<h1 class="text-3xl font-bold mb-4">Bienvenue sur ton tableau de bord KAZ </h1>
|
||||||
|
|
||||||
|
{# Vérification si un utilisateur est connecté #}
|
||||||
|
{% if app.user %}
|
||||||
|
<div class="p-4 bg-green-100 text-green-800 rounded mb-4">
|
||||||
|
<p class="font-semibold">Succès ! Tu es connecté avec l'adresse :</p>
|
||||||
|
<p class="text-xl">{{ app.user.userIdentifier }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="mt-4">
|
||||||
|
<a href="{{ path('app_logout') }}" class="inline-block px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700">
|
||||||
|
Se déconnecter
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="mb-4">Tu n'es pas encore connecté à ton espace.</p>
|
||||||
|
<a href="{{ path('app_login') }}" class="inline-block px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
|
||||||
|
Aller à la page de connexion
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,35 +1,30 @@
|
|||||||
{% extends 'base.html.twig' %}
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
{% block title %}Log in!{% endblock %}
|
{% block title %}Se connecter | {{ parent() }}{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% if error %}
|
{% if error %}
|
||||||
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 border border-red-200">
|
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
||||||
Email ou mot de passe invalide.
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if app.user %}
|
{% if app.user %}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
You are logged in as {{ app.user.userIdentifier }}, <a href="{{ logout_path() }}">Se déconnecter</a>
|
You are logged in as {{ app.user.userIdentifier }}, <a href="{{ logout_path() }}">Logout</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h1 class="h3 mb-3 font-weight-normal">Se connecter à mon compte KAZ</h1>
|
<h1 class="h3 mb-3 font-weight-normal">Se connecter à mon tableau de bord KAZ</h1>
|
||||||
<label for="username">Email</label>
|
<label for="inputEmail">Email :</label>
|
||||||
<input type="email" value="{{ last_username }}" name="_username" id="username" class="form-control" autocomplete="email" required autofocus>
|
<input type="email" value="{{ last_username }}" name="_username" id="inputEmail" class="form-control" autocomplete="email" required autofocus>
|
||||||
<label for="password">Mot de passe</label>
|
<label for="inputPassword">Mot de passe : </label>
|
||||||
<input type="password" name="_password" id="password" class="form-control" autocomplete="current-password" required>
|
<input type="password" name="_password" id="inputPassword" class="form-control" autocomplete="current-password" required>
|
||||||
<input type="hidden" name="_csrf_token" data-controller="csrf-protection" value="{{ csrf_token('authenticate') }}">
|
<input type="hidden" name="_csrf_token" data-controller="csrf-protection" value="{{ csrf_token('authenticate') }}">
|
||||||
|
|
||||||
|
|
||||||
{# TODO : vérifier qu'il y a bien une option "Se souvenir de moi" dans mon firewall pour activer la fonctionnalité. #}
|
|
||||||
{# pour en savoir plus : https://symfony.com/doc/current/security/remember_me.html #}
|
|
||||||
|
|
||||||
<div class="checkbox mb-3">
|
<div class="checkbox mb-3">
|
||||||
<input type="checkbox" name="_remember_me" id="_remember_me">
|
<label>
|
||||||
<label for="_remember_me">Se souvenir de moi</label>
|
<input type="checkbox" name="_remember_me"> Se souvenir de moi
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-lg btn-primary" type="submit">
|
<button class="btn btn-lg btn-primary" type="submit">
|
||||||
|
|||||||
Reference in New Issue
Block a user