Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 66274e239b | |||
| f93a867dd4 | |||
| 744d8a4088 | |||
| cf693c0304 | |||
| 44bff2a4e5 | |||
| 6c1f14ae4d | |||
| 6f2218d2c9 | |||
| 9596d94617 | |||
| f99e5cd386 | |||
| 8f5730c3f6 | |||
| 42fafc5d39 | |||
| cc83242883 | |||
| 2d3ce2ca43 | |||
| 94ea49587a | |||
| 4a77449a41 | |||
| 9fb0fc12b8 | |||
| 14960d5e87 | |||
| ecb6f25159 | |||
| 566e7f132a | |||
| a2d20dafb1 | |||
| 6fc72d180a | |||
| c082224c7d | |||
| 74a0120883 | |||
| b0f4004d11 | |||
| c759194b83 | |||
| 5f0703811f | |||
| 8ea211835f |
17
.editorconfig
Normal file
17
.editorconfig
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# editorconfig.org
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[{compose.yaml,compose.*.yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
22
.env
Normal file
22
.env
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
APP_ENV=
|
||||||
|
APP_DEBUG=
|
||||||
|
APP_SECRET=
|
||||||
|
|
||||||
|
DEFAULT_URI=
|
||||||
|
|
||||||
|
###> nelmio/cors-bundle ###
|
||||||
|
CORS_ALLOW_ORIGIN=
|
||||||
|
###< nelmio/cors-bundle ###
|
||||||
|
|
||||||
|
###> lexik/jwt-authentication-bundle ###
|
||||||
|
JWT_SECRET_KEY=
|
||||||
|
JWT_PUBLIC_KEY=
|
||||||
|
JWT_PASSPHRASE=
|
||||||
|
COOKIE_SECURE=
|
||||||
|
###< lexik/jwt-authentication-bundle ###
|
||||||
|
|
||||||
|
# ADAPTER avec la vraie BDD (pas de variables docker)
|
||||||
|
DATABASE_URL=
|
||||||
|
|
||||||
|
PONT_BASCULE_BYPASS=
|
||||||
|
PONT_BASCULE_URL=
|
||||||
3
.env.test
Normal file
3
.env.test
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# define your env variables for the test env here
|
||||||
|
KERNEL_CLASS='App\Kernel'
|
||||||
|
APP_SECRET='$ecretf0rt3st'
|
||||||
20
.gitattributes
vendored
Normal file
20
.gitattributes
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Force LF in repo
|
||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
# (optionnel) scripts
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.bash text eol=lf
|
||||||
|
|
||||||
|
# (optionnel) configs
|
||||||
|
*.yml text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.env text eol=lf
|
||||||
|
Dockerfile text eol=lf
|
||||||
|
|
||||||
|
# (optionnel) frontend
|
||||||
|
*.ts text eol=lf
|
||||||
|
*.tsx text eol=lf
|
||||||
|
*.js text eol=lf
|
||||||
|
*.vue text eol=lf
|
||||||
|
*.css text eol=lf
|
||||||
|
*.scss text eol=lf
|
||||||
23
.gitea/PULL_REQUEST_TEMPLATE.md
Normal file
23
.gitea/PULL_REQUEST_TEMPLATE.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
name: "Merge Request"
|
||||||
|
about: "Template de MR"
|
||||||
|
title: "[#NUMERO_TICKET] TITRE TICKET"
|
||||||
|
ref: "main"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
| Numéro du ticket | Titre du ticket |
|
||||||
|
|------------------|-----------------|
|
||||||
|
| | |
|
||||||
|
|
||||||
|
## Description de la PR
|
||||||
|
|
||||||
|
## Modification du .env
|
||||||
|
|
||||||
|
## Check list
|
||||||
|
|
||||||
|
- [ ] Pas de régression
|
||||||
|
- [ ] TU/TI/TF rédigée
|
||||||
|
- [ ] TU/TI/TF OK
|
||||||
|
- [ ] CHANGELOG modifié
|
||||||
45
.gitea/workflows/auto-tag-develop.yml
Normal file
45
.gitea/workflows/auto-tag-develop.yml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
name: Auto Tag Develop
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tag:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
persist-credentials: true
|
||||||
|
|
||||||
|
- name: Create next tag v0.0.X
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Skip if current commit already has a v0.0.* tag
|
||||||
|
if git tag --points-at HEAD | grep -qE '^v0\.0\.'; then
|
||||||
|
echo "Tag already exists on this commit. Skipping."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
last_tag="$(git tag -l 'v0.0.*' --sort=-v:refname | head -n1 || true)"
|
||||||
|
if [ -z "$last_tag" ]; then
|
||||||
|
next_tag="v0.0.1"
|
||||||
|
else
|
||||||
|
patch="${last_tag##v0.0.}"
|
||||||
|
if ! [[ "$patch" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "Unexpected tag format: $last_tag" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
next_tag="v0.0.$((patch + 1))"
|
||||||
|
fi
|
||||||
|
|
||||||
|
git config user.name "gitea-actions"
|
||||||
|
git config user.email "gitea-actions@local"
|
||||||
|
git tag "$next_tag"
|
||||||
|
git push origin "$next_tag"
|
||||||
64
.gitea/workflows/release-artefact.yml
Normal file
64
.gitea/workflows/release-artefact.yml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
name: Build Release Artefact
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v0.0.*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "8.4"
|
||||||
|
extensions: mbstring, intl, pdo_pgsql, xml, curl, zip, gd
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "lts/*"
|
||||||
|
|
||||||
|
- name: Install backend deps (prod)
|
||||||
|
env:
|
||||||
|
APP_ENV: prod
|
||||||
|
APP_DEBUG: "0"
|
||||||
|
run: composer install --no-dev --optimize-autoloader --no-interaction --no-scripts
|
||||||
|
|
||||||
|
- name: Build frontend (static)
|
||||||
|
run: |
|
||||||
|
cd frontend
|
||||||
|
npm ci
|
||||||
|
NUXT_PUBLIC_API_BASE=/api NUXT_PUBLIC_APP_BASE=/ npm run generate
|
||||||
|
|
||||||
|
- name: Build artefact
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
mkdir -p release
|
||||||
|
tar -czf "release/ferme-${GITHUB_REF_NAME}.tar.gz" \
|
||||||
|
bin \
|
||||||
|
config \
|
||||||
|
migrations \
|
||||||
|
public \
|
||||||
|
src \
|
||||||
|
templates \
|
||||||
|
vendor \
|
||||||
|
composer.json \
|
||||||
|
composer.lock \
|
||||||
|
symfony.lock \
|
||||||
|
frontend/.output/public
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: release/ferme-${{ github.ref_name }}.tar.gz
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
###> symfony/framework-bundle ###
|
||||||
|
/.env.local
|
||||||
|
/.env.prod
|
||||||
|
/.env.local.php
|
||||||
|
/.env.*.local
|
||||||
|
/config/secrets/prod/prod.decrypt.private.php
|
||||||
|
/public/bundles/
|
||||||
|
/var/
|
||||||
|
/vendor/
|
||||||
|
/LOG/
|
||||||
|
/config/jwt/*.pem
|
||||||
|
###< symfony/framework-bundle ###
|
||||||
|
|
||||||
|
###> friendsofphp/php-cs-fixer ###
|
||||||
|
/.php-cs-fixer.php
|
||||||
|
/.php-cs-fixer.cache
|
||||||
|
###< friendsofphp/php-cs-fixer ###
|
||||||
|
|
||||||
|
###> phpunit/phpunit ###
|
||||||
|
/phpunit.xml
|
||||||
|
/.phpunit.cache/
|
||||||
|
###< phpunit/phpunit ###
|
||||||
|
|
||||||
|
###> docker ###
|
||||||
|
docker/.env.docker.local
|
||||||
|
###< docker ###
|
||||||
|
|
||||||
|
###> lexik/jwt-authentication-bundle ###
|
||||||
|
/config/jwt/*.pem
|
||||||
|
###< lexik/jwt-authentication-bundle ###
|
||||||
9
.idea/.gitignore
generated
vendored
Normal file
9
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
# Ignored default folder with query files
|
||||||
|
/queries/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
19
.idea/dataSources.xml
generated
Normal file
19
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="ferme" uuid="f407a514-c6b4-4b26-9555-445a85892502">
|
||||||
|
<driver-ref>postgresql</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:postgresql://localhost:5432/ferme</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="Ferme recette" uuid="ae622167-c834-4e7b-87a5-c1721036f5dc">
|
||||||
|
<driver-ref>postgresql</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:postgresql://localhost:5432/postgres</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
7
.idea/data_source_mapping.xml
generated
Normal file
7
.idea/data_source_mapping.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourcePerFileMappings">
|
||||||
|
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/ae622167-c834-4e7b-87a5-c1721036f5dc/console.sql" value="ae622167-c834-4e7b-87a5-c1721036f5dc" />
|
||||||
|
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f407a514-c6b4-4b26-9555-445a85892502/console.sql" value="f407a514-c6b4-4b26-9555-445a85892502" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/db-forest-config.xml
generated
Normal file
6
.idea/db-forest-config.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="db-tree-configuration">
|
||||||
|
<option name="data" value="---------------------------------------- 1:0:f407a514-c6b4-4b26-9555-445a85892502 2:0:ae622167-c834-4e7b-87a5-c1721036f5dc " />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
155
.idea/ferme.iml
generated
Normal file
155
.idea/ferme.iml
generated
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="App\" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="App\Tests\" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/public/bundles" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/var" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/doctrine-common" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/doctrine-orm" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/documentation" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/http-cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/hydra" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/json-schema" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/jsonld" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/metadata" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/openapi" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/serializer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/state" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/symfony" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/api-platform/validator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/clue/ndjson-react" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/collections" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/common" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/dbal" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/deprecations" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/event-manager" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/inflector" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/lexer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/migrations" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/orm" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/persistence" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/sql-formatter" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/evenement/evenement" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/fidry/cpu-core-counter" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/nelmio/cors-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpstan/phpdoc-parser" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/clock" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/event-dispatcher" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/link" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/child-process" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/dns" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/event-loop" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/promise" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/socket" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/react/stream" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/diff" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/asset" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/cache-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/clock" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/config" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dependency-injection" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/doctrine-bridge" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dotenv" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/error-handler" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/expression-language" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/filesystem" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/finder" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/flex" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/framework-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-foundation" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-kernel" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/options-resolver" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/password-hasher" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php85" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-uuid" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-access" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/property-info" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/routing" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/runtime" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-core" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-csrf" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/security-http" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/serializer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/stopwatch" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bridge" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/twig-bundle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/type-info" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/uid" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/validator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-exporter" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/web-link" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/yaml" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/twig/twig" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/webmozart/assert" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/willdurand/negotiation" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/manifest" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/version" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-code-coverage" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-file-iterator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-invoker" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-text-template" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-timer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/phpunit" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/cli-parser" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/comparator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/complexity" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/environment" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/exporter" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/global-state" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/lines-of-code" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-enumerator" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-reflector" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/recursion-context" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/type" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/version" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/staabm/side-effects-detector" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/browser-kit" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/css-selector" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dom-crawler" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-client" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-client-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/dompdf/dompdf" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/dompdf/php-font-lib" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/dompdf/php-svg-lib" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/masterminds/html5" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/sabberworm/php-css-parser" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/thecodingmachine/safe" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/lcobucci/jwt" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/lexik/jwt-authentication-bundle" />
|
||||||
|
<excludePattern pattern="reference.php" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
8
.idea/laravel-idea.xml
generated
Normal file
8
.idea/laravel-idea.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="InertiaPackage">
|
||||||
|
<option name="directoryPaths">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
12
.idea/material_theme_project_new.xml
generated
Normal file
12
.idea/material_theme_project_new.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MaterialThemeProjectNewConfig">
|
||||||
|
<option name="metadata">
|
||||||
|
<MTProjectMetadataState>
|
||||||
|
<option name="migrated" value="true" />
|
||||||
|
<option name="pristineConfig" value="false" />
|
||||||
|
<option name="userId" value="-70fca0d0:19b8da49b68:-7ffe" />
|
||||||
|
</MTProjectMetadataState>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/ferme.iml" filepath="$PROJECT_DIR$/.idea/ferme.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
170
.idea/php.xml
generated
Normal file
170
.idea/php.xml
generated
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MessDetectorOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PHPCSFixerOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||||
|
<option name="highlightLevel" value="WARNING" />
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PhpIncludePathManager">
|
||||||
|
<include_path>
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/uid" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/asset" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-bridge" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/migrations" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/common" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/jsonld" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/hydra" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/willdurand/negotiation" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/http-cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/serializer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-orm" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/validator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/state" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/metadata" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/symfony" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/openapi" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/documentation" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/json-schema" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-common" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/link" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/clock" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/child-process" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/nelmio/cors-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/flex" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/web-link" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/serializer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/browser-kit" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/expression-language" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/thecodingmachine/safe" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/dompdf/dompdf" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/dompdf/php-svg-lib" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sabberworm/php-css-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/dompdf/php-font-lib" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/lexik/jwt-authentication-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/lcobucci/jwt" />
|
||||||
|
</include_path>
|
||||||
|
</component>
|
||||||
|
<component name="PhpProjectSharedConfiguration" php_language_level="8.4" />
|
||||||
|
<component name="PhpStanOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PhpUnit">
|
||||||
|
<phpunit_settings>
|
||||||
|
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
|
||||||
|
</phpunit_settings>
|
||||||
|
</component>
|
||||||
|
<component name="PsalmOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/symfony2.xml
generated
Normal file
6
.idea/symfony2.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Symfony2PluginSettings">
|
||||||
|
<option name="pluginEnabled" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
496
.idea/workspace.xml
generated
Normal file
496
.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,496 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AutoImportSettings">
|
||||||
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
|
</component>
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="7c107abe-5995-4428-8429-b146aaca8386" name="Changes" comment="ci : fix release artefact">
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
|
</list>
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="ComposerSettings" synchronizationState="SYNCHRONIZE">
|
||||||
|
<pharConfigPath>$PROJECT_DIR$/composer.json</pharConfigPath>
|
||||||
|
<execution />
|
||||||
|
</component>
|
||||||
|
<component name="EmbeddingIndexingInfo">
|
||||||
|
<option name="cachedIndexableFilesCount" value="151" />
|
||||||
|
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="FileTemplateManagerImpl">
|
||||||
|
<option name="RECENT_TEMPLATES">
|
||||||
|
<list>
|
||||||
|
<option value="TypeScript File" />
|
||||||
|
<option value="Vue Composition API Component" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||||
|
<map>
|
||||||
|
<entry key="$PROJECT_DIR$" value="feat/202-connexion-utilisateur" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="McpProjectServerCommands">
|
||||||
|
<commands />
|
||||||
|
<urls />
|
||||||
|
</component>
|
||||||
|
<component name="PhpServers">
|
||||||
|
<servers>
|
||||||
|
<server host="localhost" id="36c0c232-9151-4654-a36c-e0f5fd99da91" name="ferme-docker" port="8080" use_path_mappings="true">
|
||||||
|
<path_mappings>
|
||||||
|
<mapping local-root="$PROJECT_DIR$" remote-root="/var/www/html" />
|
||||||
|
</path_mappings>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
</component>
|
||||||
|
<component name="PhpWorkspaceProjectConfiguration">
|
||||||
|
<include_path>
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/uid" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/asset" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-bridge" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/migrations" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/common" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/jsonld" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/hydra" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/willdurand/negotiation" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/http-cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/serializer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-orm" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/validator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/state" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/metadata" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/symfony" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/openapi" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/documentation" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/json-schema" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-common" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/link" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/clock" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/child-process" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/nelmio/cors-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/flex" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/web-link" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/serializer" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/browser-kit" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/expression-language" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/thecodingmachine/safe" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/dompdf/dompdf" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/dompdf/php-svg-lib" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/sabberworm/php-css-parser" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/dompdf/php-font-lib" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/lexik/jwt-authentication-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/lcobucci/jwt" />
|
||||||
|
</include_path>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectColorInfo">{
|
||||||
|
"customColor": "",
|
||||||
|
"associatedIndex": 5
|
||||||
|
}</component>
|
||||||
|
<component name="ProjectId" id="381AhnCm9yPeOiWgMObKHhtgv2C" />
|
||||||
|
<component name="ProjectViewState">
|
||||||
|
<option name="autoscrollFromSource" value="true" />
|
||||||
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
|
<option name="showLibraryContents" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
|
"keyToString": {
|
||||||
|
"RunOnceActivity.MCP Project settings loaded": "true",
|
||||||
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
|
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||||
|
"RunOnceActivity.git.unshallow": "true",
|
||||||
|
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||||
|
"git-widget-placeholder": "develop",
|
||||||
|
"node.js.detected.package.eslint": "true",
|
||||||
|
"node.js.detected.package.tslint": "true",
|
||||||
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
|
"nodejs_package_manager_path": "npm",
|
||||||
|
"settings.editor.selected.configurable": "preferences.keymap",
|
||||||
|
"vue.rearranger.settings.migration": "true"
|
||||||
|
},
|
||||||
|
"keyToStringList": {
|
||||||
|
"DatabaseDriversLRU": [
|
||||||
|
"postgresql"
|
||||||
|
],
|
||||||
|
"com.intellij.ide.scratch.ScratchImplUtil$2/New Scratch File": [
|
||||||
|
"TEXT"
|
||||||
|
],
|
||||||
|
"vue.recent.templates": [
|
||||||
|
"Vue Composition API Component"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}]]></component>
|
||||||
|
<component name="RecentsManager">
|
||||||
|
<key name="MoveFile.RECENT_KEYS">
|
||||||
|
<recent name="\\wsl.localhost\Ubuntu-24.04\home\tristan\workspace\ferme\templates" />
|
||||||
|
<recent name="C:\Users\autin\AppData\Roaming\JetBrains\PhpStorm2025.3\scratches" />
|
||||||
|
<recent name="C:\Users\autin\AppData\Roaming\JetBrains\PhpStorm2025.3\scratches\Ferme_MCD\MCD_DOC" />
|
||||||
|
<recent name="\\wsl.localhost\Ubuntu-24.04\home\tristan\workspace\ferme\frontend\pages\reception" />
|
||||||
|
<recent name="\\wsl.localhost\Ubuntu-24.04\home\tristan\workspace\ferme\frontend\pages" />
|
||||||
|
</key>
|
||||||
|
</component>
|
||||||
|
<component name="SharedIndexes">
|
||||||
|
<attachedChunks>
|
||||||
|
<set>
|
||||||
|
<option value="bundled-php-predefined-a98d8de5180a-0e0d91225499-com.jetbrains.php.sharedIndexes-PS-253.29346.257" />
|
||||||
|
</set>
|
||||||
|
</attachedChunks>
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="7c107abe-5995-4428-8429-b146aaca8386" name="Changes" comment="" />
|
||||||
|
<created>1767956826164</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1767956826164</updated>
|
||||||
|
<workItem from="1767956827666" duration="7866000" />
|
||||||
|
<workItem from="1768201706520" duration="13383000" />
|
||||||
|
<workItem from="1768287908317" duration="28058000" />
|
||||||
|
<workItem from="1768374298711" duration="12403000" />
|
||||||
|
<workItem from="1768460547451" duration="26946000" />
|
||||||
|
<workItem from="1768547023783" duration="11371000" />
|
||||||
|
<workItem from="1768894030675" duration="33744000" />
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00001" summary="feat : Ajout de pinia, création de la table weight et reception mise en place du système de step pour les receptions (WIP)">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768237763998</created>
|
||||||
|
<option name="number" value="00001" />
|
||||||
|
<option name="presentableId" value="LOCAL-00001" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768237763998</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00002" summary="feat : Ajout de zod, création d'un composant de chargement loading-dots.vue et finalisation du flow d'une reception">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768316052474</created>
|
||||||
|
<option name="number" value="00002" />
|
||||||
|
<option name="presentableId" value="LOCAL-00002" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768316052474</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00003" summary="feat : Ajout d'un composable pour la pesée qui sera réutilisable pour l'expédition, ajout de contrainte sur les entity de reception et weight pour plus de robustesse et correction de la class active des liens dans la nav">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768316835575</created>
|
||||||
|
<option name="number" value="00003" />
|
||||||
|
<option name="presentableId" value="LOCAL-00003" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768316835575</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00004" summary="feat : update du fichier AGENTS.md">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768316965511</created>
|
||||||
|
<option name="number" value="00004" />
|
||||||
|
<option name="presentableId" value="LOCAL-00004" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768316965511</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00005" summary="feat : update du fichier README.md et CHANGELOG.md">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768317786187</created>
|
||||||
|
<option name="number" value="00005" />
|
||||||
|
<option name="presentableId" value="LOCAL-00005" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768317786187</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00006" summary="fix : correction du useApi pour qu'il n'y ait plus de retry lors d'une erreur 500 par exemple">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768318875533</created>
|
||||||
|
<option name="number" value="00006" />
|
||||||
|
<option name="presentableId" value="LOCAL-00006" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768318875533</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00007" summary="test : ajout de TU sur les services et providers">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768318921478</created>
|
||||||
|
<option name="number" value="00007" />
|
||||||
|
<option name="presentableId" value="LOCAL-00007" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768318921478</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00008" summary="feat : ajout de la génération du bon de reception, correction de la base du formulaire multi-etape de reception et ajout d'une gestion d'erreur global">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768498751836</created>
|
||||||
|
<option name="number" value="00008" />
|
||||||
|
<option name="presentableId" value="LOCAL-00008" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768498751836</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00009" summary="feat : ajout d'une gestion d'erreur au global côté front avec la lib toaster et I18n pour centraliser les messages d'erreur">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768555180530</created>
|
||||||
|
<option name="number" value="00009" />
|
||||||
|
<option name="presentableId" value="LOCAL-00009" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768555180530</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00010" summary="feat : ajout de l'authentification avec lexik">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768832208350</created>
|
||||||
|
<option name="number" value="00010" />
|
||||||
|
<option name="presentableId" value="LOCAL-00010" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768832208350</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00011" summary="feat : update du CHANGELOG.md">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768832516587</created>
|
||||||
|
<option name="number" value="00011" />
|
||||||
|
<option name="presentableId" value="LOCAL-00011" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768832516587</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00012" summary="fix : correction de l'accès au swagger en mode dev qui n'était plus accessible">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768940104944</created>
|
||||||
|
<option name="number" value="00012" />
|
||||||
|
<option name="presentableId" value="LOCAL-00012" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768940104944</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00013" summary="feat : ajout de la conf pour le déploiement en recette">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1769005220331</created>
|
||||||
|
<option name="number" value="00013" />
|
||||||
|
<option name="presentableId" value="LOCAL-00013" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1769005220331</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00014" summary="fix : fix de la conf pour le déploiement en recette">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1769008700008</created>
|
||||||
|
<option name="number" value="00014" />
|
||||||
|
<option name="presentableId" value="LOCAL-00014" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1769008700008</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00015" summary="fix : fix de la conf pour le déploiement en recette">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1769014602062</created>
|
||||||
|
<option name="number" value="00015" />
|
||||||
|
<option name="presentableId" value="LOCAL-00015" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1769014602062</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00016" summary="fix : migration apache vers nginx pour un déploiement plus simple">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1769019284586</created>
|
||||||
|
<option name="number" value="00016" />
|
||||||
|
<option name="presentableId" value="LOCAL-00016" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1769019284586</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00017" summary="fix : dernière modification pour le déploiement en recette et le changement de conf vers nginx">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1769021756823</created>
|
||||||
|
<option name="number" value="00017" />
|
||||||
|
<option name="presentableId" value="LOCAL-00017" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1769021756823</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00018" summary="ci : auto tag + release artefact">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1769021818384</created>
|
||||||
|
<option name="number" value="00018" />
|
||||||
|
<option name="presentableId" value="LOCAL-00018" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1769021818384</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00019" summary="ci : fix release artefact">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1769022071620</created>
|
||||||
|
<option name="number" value="00019" />
|
||||||
|
<option name="presentableId" value="LOCAL-00019" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1769022071620</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="20" />
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
|
<component name="Vcs.Log.Tabs.Properties">
|
||||||
|
<option name="RECENT_FILTERS">
|
||||||
|
<map>
|
||||||
|
<entry key="Branch">
|
||||||
|
<value>
|
||||||
|
<list>
|
||||||
|
<RecentGroup>
|
||||||
|
<option name="FILTER_VALUES">
|
||||||
|
<option value="HEAD" />
|
||||||
|
</option>
|
||||||
|
</RecentGroup>
|
||||||
|
<RecentGroup>
|
||||||
|
<option name="FILTER_VALUES">
|
||||||
|
<option value="develop" />
|
||||||
|
</option>
|
||||||
|
</RecentGroup>
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="TAB_STATES">
|
||||||
|
<map>
|
||||||
|
<entry key="MAIN">
|
||||||
|
<value>
|
||||||
|
<State>
|
||||||
|
<option name="FILTERS">
|
||||||
|
<map>
|
||||||
|
<entry key="branch">
|
||||||
|
<value>
|
||||||
|
<list>
|
||||||
|
<option value="HEAD" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</State>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="VcsManagerConfiguration">
|
||||||
|
<MESSAGE value="Feat : (WIP) Ajout de pinia, création de la table weight et reception mise en place du système de step pour les receptions" />
|
||||||
|
<MESSAGE value="Feat : Ajout de pinia, création de la table weight et reception mise en place du système de step pour les receptions (WIP)" />
|
||||||
|
<MESSAGE value="feat : Ajout de pinia, création de la table weight et reception mise en place du système de step pour les receptions (WIP)" />
|
||||||
|
<MESSAGE value="feat : Ajout de zod, création d'un composant de chargement loading-dots.vue et finalisation du flow d'une reception" />
|
||||||
|
<MESSAGE value="feat : Ajout d'un composable pour la pesée qui sera réutilisable pour l'expédition, ajout de contrainte sur les entity de reception et weight pour plus de robustesse et correction de la class active des liens dans la nav" />
|
||||||
|
<MESSAGE value="feat : update du fichier AGENTS.md" />
|
||||||
|
<MESSAGE value="feat : update du fichier README.md et CHANGELOG.md" />
|
||||||
|
<MESSAGE value="fix : correction du useApi pour qu'il n'y ait plus de retry lors d'une erreur 500 par exemple" />
|
||||||
|
<MESSAGE value="test : ajout de TU sur les services et providers" />
|
||||||
|
<MESSAGE value="feat : ajout de la génération du bon de reception, correction de la base du formulaire multi-etape de reception et ajout d'une gestion d'erreur global" />
|
||||||
|
<MESSAGE value="feat : ajout d'une gestion d'erreur au global côté front avec la lib toaster et I18n pour centraliser les messages d'erreur" />
|
||||||
|
<MESSAGE value="feat : ajout de l'authentification avec lexik" />
|
||||||
|
<MESSAGE value="feat : update du CHANGELOG.md" />
|
||||||
|
<MESSAGE value="fix : correction de l'accès au swagger en mode dev qui n'était plus accessible" />
|
||||||
|
<MESSAGE value="feat : ajout de la conf pour le déploiement en recette" />
|
||||||
|
<MESSAGE value="fix : fix de la conf pour le déploiement en recette" />
|
||||||
|
<MESSAGE value="fix : migration apache vers nginx pour un déploiement plus simple" />
|
||||||
|
<MESSAGE value="fix : dernière modification pour le déploiement en recette et le changement de conf vers nginx" />
|
||||||
|
<MESSAGE value="ci: auto tag + release artefact" />
|
||||||
|
<MESSAGE value="ci : auto tag + release artefact" />
|
||||||
|
<MESSAGE value="ci : fix release artefact" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="ci : fix release artefact" />
|
||||||
|
</component>
|
||||||
|
<component name="XSLT-Support.FileAssociations.UIState">
|
||||||
|
<expand />
|
||||||
|
<select />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
56
.php-cs-fixer.dist.php
Normal file
56
.php-cs-fixer.dist.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use PhpCsFixer\Config;
|
||||||
|
use PhpCsFixer\Finder;
|
||||||
|
|
||||||
|
$finder = Finder::create()
|
||||||
|
->in('src')
|
||||||
|
->notName('Kernel.php')
|
||||||
|
;
|
||||||
|
|
||||||
|
$rules = [
|
||||||
|
'@Symfony' => true,
|
||||||
|
'@PSR12' => true,
|
||||||
|
'@PHP84Migration' => true,
|
||||||
|
'@PER-CS' => true,
|
||||||
|
'@PhpCsFixer' => true,
|
||||||
|
'strict_param' => true,
|
||||||
|
'strict_comparison' => true,
|
||||||
|
'no_useless_else' => true,
|
||||||
|
'no_useless_return' => true,
|
||||||
|
'binary_operator_spaces' => [
|
||||||
|
'operators' => [
|
||||||
|
'=' => 'align_single_space_minimal',
|
||||||
|
'||' => 'align_single_space_minimal',
|
||||||
|
'=>' => 'align_single_space_minimal',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'global_namespace_import' => [
|
||||||
|
'import_classes' => true,
|
||||||
|
'import_constants' => true,
|
||||||
|
'import_functions' => true,
|
||||||
|
],
|
||||||
|
'modernize_strpos' => true, // needs PHP 8+ or polyfill
|
||||||
|
'no_superfluous_phpdoc_tags' => true,
|
||||||
|
'echo_tag_syntax' => true,
|
||||||
|
'semicolon_after_instruction' => true,
|
||||||
|
'combine_consecutive_unsets' => true,
|
||||||
|
'ternary_to_null_coalescing' => true,
|
||||||
|
'declare_strict_types' => true,
|
||||||
|
'operator_linebreak' => [
|
||||||
|
'position' => 'beginning',
|
||||||
|
],
|
||||||
|
'no_unused_imports' => true,
|
||||||
|
'single_line_throw' => false,
|
||||||
|
'php_unit_test_class_requires_covers' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
$config = new Config();
|
||||||
|
|
||||||
|
return $config
|
||||||
|
->setRiskyAllowed(true)
|
||||||
|
->setRules($rules)
|
||||||
|
->setFinder($finder)
|
||||||
|
;
|
||||||
46
AGENTS.md
Normal file
46
AGENTS.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
Project overview
|
||||||
|
- Symfony 8 + API Platform 4 backend, Nuxt 3 frontend in `frontend/`.
|
||||||
|
- Apache vhost serves API under `/api` and frontend from `frontend/dist`.
|
||||||
|
- API base URL on frontend uses `NUXT_PUBLIC_API_BASE` (see `frontend/.env`).
|
||||||
|
|
||||||
|
Backend conventions
|
||||||
|
- Use English for code identifiers/messages; keep “pont-bascule” as domain term.
|
||||||
|
- API Platform operations are defined on Doctrine entities.
|
||||||
|
- Reception entity is in `src/Entity/Reception.php`, with custom weigh endpoint `/receptions/weigh`.
|
||||||
|
- Reception fields: `date_reception`, `license_plate`, `current_step` (default 0), `is_valid` (default false).
|
||||||
|
- `date_reception` is set by the UI, stored as `DateTimeImmutable`, serialized as `Y-m-d`.
|
||||||
|
- Weight entity (`src/Entity/Weight.php`) is 1–N with Reception, each row stores `type` (`gross` or `tare`), `dsd`, `weight`, `weighed_at` (all nullable except `type`).
|
||||||
|
- Weigh endpoint `/receptions/weigh` returns `PontBasculeReading` with `dsd`, `weight`, `weighedAt` (formatted `Y-m-d`).
|
||||||
|
- Custom exception: `App\Exception\PontBasculeException` with French messages, mapped to 500 in provider.
|
||||||
|
- Parsing of pont-bascule payload is in `src/Service/PontBasculePayloadDecoder.php`.
|
||||||
|
- `config/reference.php` is auto-generated; keep it.
|
||||||
|
|
||||||
|
Frontend conventions
|
||||||
|
- Nuxt SSR disabled; Tailwind used.
|
||||||
|
- Layout in `frontend/layouts/default.vue`: max width `1050px`, header full width.
|
||||||
|
- Tailwind custom color palette is `primary` (e.g. `bg-primary-500`).
|
||||||
|
- API composable in `frontend/composables/useApi.ts` with `get/post/put/patch/delete` and default JSON/PATCH content types.
|
||||||
|
- API errors/success toasts can be customized via `toastErrorMessage`/`toastSuccessMessage` or i18n keys `toastErrorKey`/`toastSuccessKey`. Global method fallbacks use `errors.http.*` keys.
|
||||||
|
- `useApi` uses `useNuxtApp().$i18n` (not `useI18n`) to avoid setup-only constraint in service calls.
|
||||||
|
- Pinia store: `frontend/stores/reception.ts` is the source of truth for the current reception.
|
||||||
|
- Zod is used for form validation (e.g. `frontend/components/reception/reception-form.vue`); shared helpers live in `frontend/utils/zod-errors.ts`.
|
||||||
|
- Weighing logic is shared via `frontend/composables/useWeighing.ts`.
|
||||||
|
- Reception step UI uses store state (`currentStep`) in `frontend/pages/reception/[[id]].vue`.
|
||||||
|
- Active nav styles in header use `NuxtLink` with `custom` slot.
|
||||||
|
- Reusable UI components live under `frontend/components/ui/` and are auto-imported with `Ui` prefix (e.g. `UiLoadingDots`).
|
||||||
|
- Service layer lives in `frontend/services/` with typed DTOs in `frontend/services/dto/`.
|
||||||
|
- Reception service uses `receptions`, `receptions/{id}`, `receptions/weigh` and supports success/error toast keys.
|
||||||
|
- Reception receipt endpoint is `receptions/{id}/receipt` (PDF) via `frontend/composables/usePdfPrinter.ts`.
|
||||||
|
|
||||||
|
Environment & routing
|
||||||
|
- Frontend dev server: `npm run dev` in `frontend/`.
|
||||||
|
- API base for local dev: `http://localhost:8080/api` (set in `frontend/.env` via `NUXT_PUBLIC_API_BASE`).
|
||||||
|
- CORS handled by Nelmio; `.env` includes `CORS_ALLOW_ORIGIN` regex for localhost.
|
||||||
|
- Nuxt i18n locales live in `frontend/i18n/locales` (configured via `langDir: 'locales'`).
|
||||||
|
- Default locale is `fr`; translations in `frontend/i18n/locales/fr.json`.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
- Do not add a GET that creates resources; use POST + PATCH.
|
||||||
|
- Keep endpoints in plural (API Platform convention).
|
||||||
26
CHANGELOG.md
Normal file
26
CHANGELOG.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
Liste des évolutions du projet Ferme
|
||||||
|
|
||||||
|
## [0.0.0]
|
||||||
|
### Parameters
|
||||||
|
Ajouter dans le fichier .env
|
||||||
|
- DEFAULT_URI
|
||||||
|
- DATABASE_URL
|
||||||
|
- PONT_BASCULE_BYPASS (doit être à true en dev)
|
||||||
|
- PONT_BASCULE_URL
|
||||||
|
- JWT_SECRET_KEY (à générer avec la commande php bin/console lexik:jwt:generate-keypair)
|
||||||
|
- JWT_PUBLIC_KEY
|
||||||
|
- JWT_PASSPHRASE (à généré dans le conteneur avec la commande php -r "echo bin2hex(random_bytes(32));")
|
||||||
|
- COOKIE_SECURE=0 (en dev 0 et en prod 1)
|
||||||
|
|
||||||
|
Ajouter dans le fichier .env du frontend
|
||||||
|
- NUXT_PUBLIC_API_BASE
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* [#203] Réceptions — Parcours de pesée multi-étapes (début)
|
||||||
|
* [#202] Authentification — Connexion utilisateur (JWT)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
103
DEPLOYMENT.md
Normal file
103
DEPLOYMENT.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# Déploiement Ferme (recette)
|
||||||
|
|
||||||
|
## 1) Premier déploiement
|
||||||
|
|
||||||
|
### Pré-requis système (Ubuntu)
|
||||||
|
1. Mettre à jour la machine
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y software-properties-common ca-certificates curl gnupg unzip git nginx
|
||||||
|
```
|
||||||
|
2. Installer PHP 8.4 + FPM + extensions
|
||||||
|
```bash
|
||||||
|
sudo add-apt-repository -y ppa:ondrej/php
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y \
|
||||||
|
php8.4 php8.4-fpm php8.4-cli php8.4-common \
|
||||||
|
php8.4-mbstring php8.4-xml php8.4-curl php8.4-intl \
|
||||||
|
php8.4-zip php8.4-gd php8.4-pgsql php8.4-opcache
|
||||||
|
```
|
||||||
|
3. Installer Composer
|
||||||
|
```bash
|
||||||
|
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||||
|
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
|
||||||
|
rm composer-setup.php
|
||||||
|
```
|
||||||
|
4. Installer Node via NVM
|
||||||
|
```bash
|
||||||
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|
||||||
|
source ~/.bashrc
|
||||||
|
nvm install --lts
|
||||||
|
```
|
||||||
|
5. Installer PostgreSQL (si la DB est locale)
|
||||||
|
```bash
|
||||||
|
sudo apt install -y postgresql postgresql-contrib
|
||||||
|
sudo -u postgres psql
|
||||||
|
```
|
||||||
|
Dans psql :
|
||||||
|
```sql
|
||||||
|
CREATE USER ferme_user WITH PASSWORD 'motdepassefort';
|
||||||
|
CREATE DATABASE ferme OWNER ferme_user;
|
||||||
|
\q
|
||||||
|
```
|
||||||
|
|
||||||
|
### Déploiement applicatif
|
||||||
|
1. Cloner le repo
|
||||||
|
```bash
|
||||||
|
sudo mkdir -p /var/www
|
||||||
|
sudo git clone <repo> /var/www/ferme
|
||||||
|
sudo chown -R malio:malio /var/www/ferme
|
||||||
|
```
|
||||||
|
2. Variables d’environnement
|
||||||
|
- Backend : `/var/www/ferme/.env.local`
|
||||||
|
- `APP_ENV=prod`
|
||||||
|
- `APP_DEBUG=0`
|
||||||
|
- `APP_SECRET=...`
|
||||||
|
- `DATABASE_URL=postgresql://ferme_user:motdepassefort@127.0.0.1:5432/ferme?serverVersion=16&charset=utf8`
|
||||||
|
- `JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem`
|
||||||
|
- `JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem`
|
||||||
|
- `JWT_PASSPHRASE=...`
|
||||||
|
- `COOKIE_SECURE=1`
|
||||||
|
- `PONT_BASCULE_BYPASS=false`
|
||||||
|
- Frontend : `/var/www/ferme/frontend/.env`
|
||||||
|
- `NUXT_PUBLIC_APP_BASE=/`
|
||||||
|
- `NUXT_PUBLIC_API_BASE=/api`
|
||||||
|
3. Générer les clés JWT
|
||||||
|
```bash
|
||||||
|
cd /var/www/ferme
|
||||||
|
mkdir -p config/jwt
|
||||||
|
php bin/console lexik:jwt:generate-keypair
|
||||||
|
```
|
||||||
|
4. Config Nginx (sous-domaine)
|
||||||
|
```bash
|
||||||
|
sudo cp /var/www/ferme/deploy/nginx/ferme.conf /etc/nginx/sites-available/ferme.conf
|
||||||
|
sudo ln -s /etc/nginx/sites-available/ferme.conf /etc/nginx/sites-enabled/ferme.conf
|
||||||
|
sudo nginx -t && sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
6. Déployer l’app
|
||||||
|
```bash
|
||||||
|
cd /var/www/ferme
|
||||||
|
./scripts/deploy-native.sh
|
||||||
|
```
|
||||||
|
7. Vérifications
|
||||||
|
- Front : `http://ferme.malio-dev.fr/`
|
||||||
|
- API : `http://ferme.malio-dev.fr/api/users`
|
||||||
|
- Login : `POST http://ferme.malio-dev.fr/api/login_check`
|
||||||
|
|
||||||
|
## 2) Déployer une nouvelle version (app déjà en place)
|
||||||
|
|
||||||
|
1. Mettre à jour le code + build + migrations
|
||||||
|
```bash
|
||||||
|
cd /var/www/ferme
|
||||||
|
./scripts/deploy-native.sh
|
||||||
|
```
|
||||||
|
2. Si changement de conf Nginx
|
||||||
|
```bash
|
||||||
|
sudo cp /var/www/ferme/deploy/nginx/ferme.conf /etc/nginx/sites-available/ferme.conf
|
||||||
|
sudo nginx -t && sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
3. Si besoin, purger le cache Symfony
|
||||||
|
```bash
|
||||||
|
php /var/www/ferme/bin/console cache:clear --env=prod
|
||||||
|
php /var/www/ferme/bin/console cache:warmup --env=prod
|
||||||
|
```
|
||||||
80
README.md
80
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Installation du projet
|
## Installation du projet
|
||||||
### Windows
|
### Windows
|
||||||
Pour windows, il faut installer le WSL2, Ubuntu et nvm.
|
Pour windows, il faut installer le WSL2, Ubuntu, docker et nvm.
|
||||||
Il suffit de suivre cette [doc](https://wiki.malio.fr/bookstack/books/environnement-de-dev/chapter/windows)
|
Il suffit de suivre cette [doc](https://wiki.malio.fr/bookstack/books/environnement-de-dev/chapter/windows)
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
@@ -15,12 +15,90 @@ Une fois les prérequis installés, il suffit de cloner le projet et de lancer l
|
|||||||
make start
|
make start
|
||||||
make install
|
make install
|
||||||
```
|
```
|
||||||
|
Dans le cas ou le `make start` plante à cause du port de la bdd, il faut modifier **POSTGRES_PORT** dans le fichier .env.docker.local, remplacer le par un port disponible.
|
||||||
|
|
||||||
|
### Configuration global
|
||||||
|
Pour les variables d'environnement, il faut demander un .env.local pour le backend et un .env pour le frontend à votre collègue.
|
||||||
|
|
||||||
|
Vérifier que dans le .env.local, vous avez :
|
||||||
|
* APP_SECRET (à généré dans le conteneur avec la commande php -r "echo bin2hex(random_bytes(32));" et doit être différent de celui de votre collègue, puisque utilisé pour signer des tokens)
|
||||||
|
* DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:${POSTGRES_PORT}/${POSTGRES_DB}?serverVersion=16&charset=utf8"
|
||||||
|
* PONT_BASCULE_BYPASS (doit être à true en dev)
|
||||||
|
* PONT_BASCULE_URL
|
||||||
|
* JWT_SECRET_KEY (à générer avec la commande php bin/console lexik:jwt:generate-keypair)
|
||||||
|
* JWT_PUBLIC_KEY
|
||||||
|
* JWT_PASSPHRASE (à généré dans le conteneur avec la commande php -r "echo bin2hex(random_bytes(32));")
|
||||||
|
* COOKIE_SECURE=0 (en dev 0 et en prod 1)
|
||||||
|
|
||||||
|
Vérifier que dans le .env du dossier frontend, vous avez :
|
||||||
|
* NUXT_PUBLIC_API_BASE="http://localhost:8080/api"
|
||||||
|
|
||||||
|
### Configuration xdebug
|
||||||
|
Pour configurer xdebug, il faut ajouter un serveur sur phpstorm. <br>
|
||||||
|
Pour cela, il faut aller dans **Settings > PHP > Servers** <br>
|
||||||
|
* Name : ferme-docker
|
||||||
|
* Host : localhost
|
||||||
|
* Port : 8080
|
||||||
|
* Path : File/Directory -> l'endroit où est stocké votre projet et le path -> /var/www/html
|
||||||
|
|
||||||
|
Pour que xdebug fonctionne sur windows, il faut modifier la variable **XDEBUG_CLIENT_HOST** par votre ip local
|
||||||
|
|
||||||
## Utilisation du projet
|
## Utilisation du projet
|
||||||
|
### Backend
|
||||||
L'api est disponible sur http://localhost:8080/api
|
L'api est disponible sur http://localhost:8080/api
|
||||||
|
Pour la bdd toutes les infos sont dans le fichier **docker/.env.docker.local**
|
||||||
|
Vous pouvez modifier le port si nécessaire.
|
||||||
|
|
||||||
|
La bdd est déja pré-configuré dans PhpStorm, il suffit de rentrer les infos du .env.docker.local pour se connecter.
|
||||||
|
C'est un bdd local dans le docker.
|
||||||
|
### Frontend
|
||||||
Pour le frontend, il suffit de taper la commande suivante qui va lancer le serveur de dev
|
Pour le frontend, il suffit de taper la commande suivante qui va lancer le serveur de dev
|
||||||
```bash
|
```bash
|
||||||
make dev-nuxt
|
make dev-nuxt
|
||||||
```
|
```
|
||||||
Le front sera accessible sur http://localhost:3000
|
Le front sera accessible sur http://localhost:3000
|
||||||
|
|
||||||
|
### Authentification
|
||||||
|
Ce projet utilise l'authentification JWT avec un cookie httpOnly (LexikJWTAuthenticationBundle).
|
||||||
|
Le frontend ne lit jamais directement le token, le navigateur envoie automatiquement le cookie.
|
||||||
|
|
||||||
|
### Login flow
|
||||||
|
- Frontend envoie les identifiants à:
|
||||||
|
- `POST /api/login_check`
|
||||||
|
- Backend returns:
|
||||||
|
- `204 No Content` (normal)
|
||||||
|
- `Set-Cookie: BEARER=...; HttpOnly`
|
||||||
|
- Le cookie est automatiquement envoyé pour les futures requêtes.
|
||||||
|
- La déconnexion utilise `POST /api/logout` et redirige vers `/login`.
|
||||||
|
|
||||||
|
## Commandes utiles
|
||||||
|
Pour restart le container
|
||||||
|
```bash
|
||||||
|
make restart
|
||||||
|
```
|
||||||
|
Pour lancer les TU
|
||||||
|
```bash
|
||||||
|
make test
|
||||||
|
```
|
||||||
|
Pour accéder au container et lance des commandes
|
||||||
|
```bash
|
||||||
|
make shell
|
||||||
|
```
|
||||||
|
Pour clear le cache Symfony
|
||||||
|
```bash
|
||||||
|
make cache-clear
|
||||||
|
```
|
||||||
|
Faire une migration
|
||||||
|
```bash
|
||||||
|
make migration-migrate
|
||||||
|
```
|
||||||
|
Pour générer un password pour un user
|
||||||
|
```bash
|
||||||
|
make shell
|
||||||
|
php bin/console security:hash-password
|
||||||
|
```
|
||||||
|
Sélectionner entity User, taper sont mdp, le copier et l'ajouter dans l'insert de bdd suivant :
|
||||||
|
```sql
|
||||||
|
INSERT INTO "user" (username, roles, password)
|
||||||
|
VALUES ('Mon user', '["ROLE_USER"]', 'Mon mdp hashé');
|
||||||
|
```
|
||||||
|
|||||||
21
bin/console
Executable file
21
bin/console
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Kernel;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||||
|
|
||||||
|
if (!is_dir(dirname(__DIR__).'/vendor')) {
|
||||||
|
throw new LogicException('Dependencies are missing. Try running "composer install".');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
|
||||||
|
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
|
||||||
|
|
||||||
|
return function (array $context) {
|
||||||
|
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||||
|
|
||||||
|
return new Application($kernel);
|
||||||
|
};
|
||||||
4
bin/phpunit
Executable file
4
bin/phpunit
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit';
|
||||||
31
commit-msg
Normal file
31
commit-msg
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MSG_FILE="${1}"
|
||||||
|
FIRST_LINE="$(head -n 1 "$MSG_FILE" | tr -d '\r')"
|
||||||
|
|
||||||
|
# Autoriser commits auto-générés par git
|
||||||
|
if [[ "$FIRST_LINE" =~ ^Merge\ ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Types autorisés (MINUSCULES uniquement)
|
||||||
|
# Optionnel: scope => feat(auth) : ...
|
||||||
|
REGEX='^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([a-z0-9._-]+\))?\ :\ .+'
|
||||||
|
|
||||||
|
if [[ ! "$FIRST_LINE" =~ $REGEX ]]; then
|
||||||
|
echo "❌ Message de commit invalide."
|
||||||
|
echo ""
|
||||||
|
echo "➡️ Format attendu : <type>(<scope optionnel>) : <message>"
|
||||||
|
echo "➡️ Types autorisés (minuscules uniquement) :"
|
||||||
|
echo " build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test"
|
||||||
|
echo ""
|
||||||
|
echo "✅ Exemples :"
|
||||||
|
echo " feat : add login page"
|
||||||
|
echo " fix(auth) : prevent null token crash"
|
||||||
|
echo " docs : update README"
|
||||||
|
echo ""
|
||||||
|
echo "❌ Exemple refusé :"
|
||||||
|
echo " Feat : add login page"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
94
composer.json
Normal file
94
composer.json
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
"type": "project",
|
||||||
|
"license": "proprietary",
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"prefer-stable": true,
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.4",
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"api-platform/doctrine-orm": "^4.2",
|
||||||
|
"api-platform/symfony": "^4.2",
|
||||||
|
"doctrine/doctrine-bundle": "^3.2",
|
||||||
|
"doctrine/doctrine-migrations-bundle": "^4.0",
|
||||||
|
"doctrine/orm": "^3.6",
|
||||||
|
"dompdf/dompdf": "^3.1",
|
||||||
|
"lexik/jwt-authentication-bundle": "*",
|
||||||
|
"nelmio/cors-bundle": "^2.6",
|
||||||
|
"phpdocumentor/reflection-docblock": "^5.6",
|
||||||
|
"phpstan/phpdoc-parser": "^2.3",
|
||||||
|
"symfony/asset": "8.0.*",
|
||||||
|
"symfony/console": "8.0.*",
|
||||||
|
"symfony/dotenv": "8.0.*",
|
||||||
|
"symfony/expression-language": "8.0.*",
|
||||||
|
"symfony/flex": "^2",
|
||||||
|
"symfony/framework-bundle": "8.0.*",
|
||||||
|
"symfony/http-client": "8.0.*",
|
||||||
|
"symfony/property-access": "8.0.*",
|
||||||
|
"symfony/property-info": "8.0.*",
|
||||||
|
"symfony/runtime": "8.0.*",
|
||||||
|
"symfony/security-bundle": "8.0.*",
|
||||||
|
"symfony/serializer": "8.0.*",
|
||||||
|
"symfony/twig-bundle": "8.0.*",
|
||||||
|
"symfony/validator": "8.0.*",
|
||||||
|
"symfony/yaml": "8.0.*"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"php-http/discovery": true,
|
||||||
|
"symfony/flex": true,
|
||||||
|
"symfony/runtime": true
|
||||||
|
},
|
||||||
|
"bump-after-update": true,
|
||||||
|
"sort-packages": true
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"App\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"App\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"symfony/polyfill-ctype": "*",
|
||||||
|
"symfony/polyfill-iconv": "*",
|
||||||
|
"symfony/polyfill-php72": "*",
|
||||||
|
"symfony/polyfill-php73": "*",
|
||||||
|
"symfony/polyfill-php74": "*",
|
||||||
|
"symfony/polyfill-php80": "*",
|
||||||
|
"symfony/polyfill-php81": "*",
|
||||||
|
"symfony/polyfill-php82": "*",
|
||||||
|
"symfony/polyfill-php83": "*",
|
||||||
|
"symfony/polyfill-php84": "*"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"auto-scripts": {
|
||||||
|
"cache:clear": "symfony-cmd",
|
||||||
|
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
||||||
|
},
|
||||||
|
"post-install-cmd": [
|
||||||
|
"@auto-scripts"
|
||||||
|
],
|
||||||
|
"post-update-cmd": [
|
||||||
|
"@auto-scripts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/symfony": "*"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"symfony": {
|
||||||
|
"allow-contrib": false,
|
||||||
|
"require": "8.0.*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.92",
|
||||||
|
"phpunit/phpunit": "^12.5",
|
||||||
|
"symfony/browser-kit": "8.0.*",
|
||||||
|
"symfony/css-selector": "8.0.*"
|
||||||
|
}
|
||||||
|
}
|
||||||
11019
composer.lock
generated
Normal file
11019
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
config/bundles.php
Normal file
23
config/bundles.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use ApiPlatform\Symfony\Bundle\ApiPlatformBundle;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
|
||||||
|
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
|
||||||
|
use Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle;
|
||||||
|
use Nelmio\CorsBundle\NelmioCorsBundle;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||||
|
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
||||||
|
use Symfony\Bundle\TwigBundle\TwigBundle;
|
||||||
|
|
||||||
|
return [
|
||||||
|
FrameworkBundle::class => ['all' => true],
|
||||||
|
TwigBundle::class => ['all' => true],
|
||||||
|
SecurityBundle::class => ['all' => true],
|
||||||
|
DoctrineBundle::class => ['all' => true],
|
||||||
|
DoctrineMigrationsBundle::class => ['all' => true],
|
||||||
|
NelmioCorsBundle::class => ['all' => true],
|
||||||
|
LexikJWTAuthenticationBundle::class => ['all' => true],
|
||||||
|
ApiPlatformBundle::class => ['all' => true],
|
||||||
|
];
|
||||||
12
config/packages/api_platform.yaml
Normal file
12
config/packages/api_platform.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
api_platform:
|
||||||
|
title: Hello API Platform
|
||||||
|
version: 1.0.0
|
||||||
|
defaults:
|
||||||
|
stateless: true
|
||||||
|
cache_headers:
|
||||||
|
vary: ['Content-Type', 'Authorization', 'Origin']
|
||||||
|
formats:
|
||||||
|
json: ['application/json']
|
||||||
|
jsonld: ['application/ld+json']
|
||||||
|
patch_formats:
|
||||||
|
json: ['application/merge-patch+json']
|
||||||
19
config/packages/cache.yaml
Normal file
19
config/packages/cache.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
framework:
|
||||||
|
cache:
|
||||||
|
# Unique name of your app: used to compute stable namespaces for cache keys.
|
||||||
|
#prefix_seed: your_vendor_name/app_name
|
||||||
|
|
||||||
|
# The "app" cache stores to the filesystem by default.
|
||||||
|
# The data in this cache should persist between deploys.
|
||||||
|
# Other options include:
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
#app: cache.adapter.redis
|
||||||
|
#default_redis_provider: redis://localhost
|
||||||
|
|
||||||
|
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
|
||||||
|
#app: cache.adapter.apcu
|
||||||
|
|
||||||
|
# Namespaced pools use the above "app" backend by default
|
||||||
|
#pools:
|
||||||
|
#my.dedicated.cache: null
|
||||||
48
config/packages/doctrine.yaml
Normal file
48
config/packages/doctrine.yaml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
doctrine:
|
||||||
|
dbal:
|
||||||
|
url: '%env(resolve:DATABASE_URL)%'
|
||||||
|
|
||||||
|
# IMPORTANT: You MUST configure your server version,
|
||||||
|
# either here or in the DATABASE_URL env var (see .env file)
|
||||||
|
#server_version: '16'
|
||||||
|
|
||||||
|
profiling_collect_backtrace: '%kernel.debug%'
|
||||||
|
orm:
|
||||||
|
validate_xml_mapping: true
|
||||||
|
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||||
|
identity_generation_preferences:
|
||||||
|
Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity
|
||||||
|
auto_mapping: true
|
||||||
|
mappings:
|
||||||
|
App:
|
||||||
|
type: attribute
|
||||||
|
is_bundle: false
|
||||||
|
dir: '%kernel.project_dir%/src/Entity'
|
||||||
|
prefix: 'App\Entity'
|
||||||
|
alias: App
|
||||||
|
controller_resolver:
|
||||||
|
auto_mapping: false
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
doctrine:
|
||||||
|
dbal:
|
||||||
|
# "TEST_TOKEN" is typically set by ParaTest
|
||||||
|
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
|
||||||
|
|
||||||
|
when@prod:
|
||||||
|
doctrine:
|
||||||
|
orm:
|
||||||
|
query_cache_driver:
|
||||||
|
type: pool
|
||||||
|
pool: doctrine.system_cache_pool
|
||||||
|
result_cache_driver:
|
||||||
|
type: pool
|
||||||
|
pool: doctrine.result_cache_pool
|
||||||
|
|
||||||
|
framework:
|
||||||
|
cache:
|
||||||
|
pools:
|
||||||
|
doctrine.result_cache_pool:
|
||||||
|
adapter: cache.app
|
||||||
|
doctrine.system_cache_pool:
|
||||||
|
adapter: cache.system
|
||||||
6
config/packages/doctrine_migrations.yaml
Normal file
6
config/packages/doctrine_migrations.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
doctrine_migrations:
|
||||||
|
migrations_paths:
|
||||||
|
# namespace is arbitrary but should be different from App\Migrations
|
||||||
|
# as migrations classes should NOT be autoloaded
|
||||||
|
'DoctrineMigrations': '%kernel.project_dir%/migrations'
|
||||||
|
enable_profiler: false
|
||||||
15
config/packages/framework.yaml
Normal file
15
config/packages/framework.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
||||||
|
framework:
|
||||||
|
secret: '%env(APP_SECRET)%'
|
||||||
|
|
||||||
|
# Note that the session will be started ONLY if you read or write from it.
|
||||||
|
session: true
|
||||||
|
|
||||||
|
#esi: true
|
||||||
|
#fragments: true
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
framework:
|
||||||
|
test: true
|
||||||
|
session:
|
||||||
|
storage_factory_id: session.storage.factory.mock_file
|
||||||
20
config/packages/lexik_jwt_authentication.yaml
Normal file
20
config/packages/lexik_jwt_authentication.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
lexik_jwt_authentication:
|
||||||
|
secret_key: '%kernel.project_dir%/config/jwt/private.pem'
|
||||||
|
public_key: '%kernel.project_dir%/config/jwt/public.pem'
|
||||||
|
pass_phrase: '%env(JWT_PASSPHRASE)%'
|
||||||
|
token_ttl: 86400
|
||||||
|
token_extractors:
|
||||||
|
authorization_header:
|
||||||
|
enabled: true
|
||||||
|
prefix: Bearer
|
||||||
|
name: Authorization
|
||||||
|
cookie:
|
||||||
|
enabled: true
|
||||||
|
name: BEARER
|
||||||
|
set_cookies:
|
||||||
|
BEARER:
|
||||||
|
lifetime: 86400
|
||||||
|
path: /
|
||||||
|
samesite: lax
|
||||||
|
secure: '%env(bool:COOKIE_SECURE)%'
|
||||||
|
httpOnly: true
|
||||||
11
config/packages/nelmio_cors.yaml
Normal file
11
config/packages/nelmio_cors.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
nelmio_cors:
|
||||||
|
defaults:
|
||||||
|
origin_regex: true
|
||||||
|
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
|
||||||
|
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
|
||||||
|
allow_headers: ['Content-Type', 'Authorization']
|
||||||
|
allow_credentials: true
|
||||||
|
expose_headers: ['Link']
|
||||||
|
max_age: 3600
|
||||||
|
paths:
|
||||||
|
'^/': null
|
||||||
4
config/packages/prod/api_platform.yaml
Normal file
4
config/packages/prod/api_platform.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
api_platform:
|
||||||
|
enable_docs: false
|
||||||
|
enable_swagger: false
|
||||||
|
enable_swagger_ui: false
|
||||||
3
config/packages/property_info.yaml
Normal file
3
config/packages/property_info.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
framework:
|
||||||
|
property_info:
|
||||||
|
with_constructor_extractor: true
|
||||||
10
config/packages/routing.yaml
Normal file
10
config/packages/routing.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
framework:
|
||||||
|
router:
|
||||||
|
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
||||||
|
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
||||||
|
default_uri: '%env(DEFAULT_URI)%'
|
||||||
|
|
||||||
|
when@prod:
|
||||||
|
framework:
|
||||||
|
router:
|
||||||
|
strict_requirements: null
|
||||||
68
config/packages/security.yaml
Normal file
68
config/packages/security.yaml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
security:
|
||||||
|
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||||
|
password_hashers:
|
||||||
|
App\Entity\User: 'auto'
|
||||||
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
||||||
|
|
||||||
|
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
||||||
|
providers:
|
||||||
|
app_user_provider:
|
||||||
|
entity:
|
||||||
|
class: App\Entity\User
|
||||||
|
property: username
|
||||||
|
|
||||||
|
firewalls:
|
||||||
|
dev:
|
||||||
|
# Ensure dev tools and static assets are always allowed
|
||||||
|
pattern: ^/(_profiler|_wdt|assets|build)/
|
||||||
|
security: false
|
||||||
|
login:
|
||||||
|
pattern: ^/login_check
|
||||||
|
stateless: true
|
||||||
|
provider: app_user_provider
|
||||||
|
json_login:
|
||||||
|
check_path: /login_check
|
||||||
|
username_path: username
|
||||||
|
password_path: password
|
||||||
|
success_handler: lexik_jwt_authentication.handler.authentication_success
|
||||||
|
failure_handler: lexik_jwt_authentication.handler.authentication_failure
|
||||||
|
api:
|
||||||
|
pattern: ^/
|
||||||
|
stateless: true
|
||||||
|
provider: app_user_provider
|
||||||
|
jwt: ~
|
||||||
|
logout:
|
||||||
|
path: /api/logout
|
||||||
|
target: /login
|
||||||
|
enable_csrf: false
|
||||||
|
delete_cookies:
|
||||||
|
BEARER:
|
||||||
|
path: /
|
||||||
|
|
||||||
|
# Activate different ways to authenticate:
|
||||||
|
# https://symfony.com/doc/current/security.html#the-firewall
|
||||||
|
|
||||||
|
# https://symfony.com/doc/current/security/impersonating_user.html
|
||||||
|
# switch_user: true
|
||||||
|
|
||||||
|
# Note: Only the *first* matching rule is applied
|
||||||
|
access_control:
|
||||||
|
# Login JWT
|
||||||
|
- { path: ^/login_check, roles: PUBLIC_ACCESS }
|
||||||
|
# Liste des users en lecture publique
|
||||||
|
- { path: ^/api/users, roles: PUBLIC_ACCESS, methods: [GET] }
|
||||||
|
# Doc API (swagger) en public
|
||||||
|
- { path: ^/api/docs, roles: PUBLIC_ACCESS }
|
||||||
|
# Tout le reste nécessite un JWT
|
||||||
|
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
security:
|
||||||
|
password_hashers:
|
||||||
|
# Password hashers are resource-intensive by design to ensure security.
|
||||||
|
# In tests, it's safe to reduce their cost to improve performance.
|
||||||
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
||||||
|
algorithm: auto
|
||||||
|
cost: 4 # Lowest possible value for bcrypt
|
||||||
|
time_cost: 3 # Lowest possible value for argon
|
||||||
|
memory_cost: 10 # Lowest possible value for argon
|
||||||
6
config/packages/twig.yaml
Normal file
6
config/packages/twig.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
twig:
|
||||||
|
file_name_pattern: '*.twig'
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
twig:
|
||||||
|
strict_variables: true
|
||||||
11
config/packages/validator.yaml
Normal file
11
config/packages/validator.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
framework:
|
||||||
|
validation:
|
||||||
|
# Enables validator auto-mapping support.
|
||||||
|
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
|
||||||
|
#auto_mapping:
|
||||||
|
# App\Entity\: []
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
framework:
|
||||||
|
validation:
|
||||||
|
not_compromised_password: false
|
||||||
5
config/preload.php
Normal file
5
config/preload.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
|
||||||
|
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
|
||||||
|
}
|
||||||
1758
config/reference.php
Normal file
1758
config/reference.php
Normal file
File diff suppressed because it is too large
Load Diff
11
config/routes.yaml
Normal file
11
config/routes.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# yaml-language-server: $schema=../vendor/symfony/routing/Loader/schema/routing.schema.json
|
||||||
|
|
||||||
|
# This file is the entry point to configure the routes of your app.
|
||||||
|
# Methods with the #[Route] attribute are automatically imported.
|
||||||
|
# See also https://symfony.com/doc/current/routing.html
|
||||||
|
|
||||||
|
# To list all registered routes, run the following command:
|
||||||
|
# bin/console debug:router
|
||||||
|
|
||||||
|
controllers:
|
||||||
|
resource: routing.controllers
|
||||||
4
config/routes/api_platform.yaml
Normal file
4
config/routes/api_platform.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
api_platform:
|
||||||
|
resource: .
|
||||||
|
type: api_platform
|
||||||
|
prefix: /api
|
||||||
4
config/routes/framework.yaml
Normal file
4
config/routes/framework.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
when@dev:
|
||||||
|
_errors:
|
||||||
|
resource: '@FrameworkBundle/Resources/config/routing/errors.php'
|
||||||
|
prefix: /_error
|
||||||
7
config/routes/security.yaml
Normal file
7
config/routes/security.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
_security_logout:
|
||||||
|
resource: security.route_loader.logout
|
||||||
|
type: service
|
||||||
|
|
||||||
|
api_login:
|
||||||
|
path: /login_check
|
||||||
|
methods: [POST]
|
||||||
28
config/services.yaml
Normal file
28
config/services.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json
|
||||||
|
|
||||||
|
# This file is the entry point to configure your own services.
|
||||||
|
# Files in the packages/ subdirectory configure your dependencies.
|
||||||
|
# See also https://symfony.com/doc/current/service_container/import.html
|
||||||
|
|
||||||
|
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||||
|
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||||
|
parameters:
|
||||||
|
|
||||||
|
services:
|
||||||
|
# default configuration for services in *this* file
|
||||||
|
_defaults:
|
||||||
|
autowire: true # Automatically injects dependencies in your services.
|
||||||
|
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||||
|
|
||||||
|
# makes classes in src/ available to be used as services
|
||||||
|
# this creates a service per class whose id is the fully-qualified class name
|
||||||
|
App\:
|
||||||
|
resource: '../src/'
|
||||||
|
|
||||||
|
App\Service\PontBasculeService:
|
||||||
|
arguments:
|
||||||
|
$endpoint: '%env(PONT_BASCULE_URL)%'
|
||||||
|
$bypass: '%env(bool:PONT_BASCULE_BYPASS)%'
|
||||||
|
|
||||||
|
# add more service definitions when explicit configuration is needed
|
||||||
|
# please note that last definitions always *replace* previous ones
|
||||||
43
deploy/nginx/ferme.conf
Normal file
43
deploy/nginx/ferme.conf
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name ferme.malio-dev.fr;
|
||||||
|
|
||||||
|
root /var/www/ferme/frontend/.output/public;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location ^~ /api/ {
|
||||||
|
root /var/www/ferme/public;
|
||||||
|
try_files $uri /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /bundles/ {
|
||||||
|
root /var/www/ferme/public;
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /api/login_check {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/ferme/public/index.php;
|
||||||
|
fastcgi_param DOCUMENT_ROOT /var/www/ferme/public;
|
||||||
|
fastcgi_param SCRIPT_NAME /index.php;
|
||||||
|
fastcgi_param PATH_INFO /login_check;
|
||||||
|
fastcgi_param REQUEST_URI /login_check;
|
||||||
|
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/index\.php(/|$) {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/ferme/public/index.php;
|
||||||
|
fastcgi_param DOCUMENT_ROOT /var/www/ferme/public;
|
||||||
|
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
|
||||||
|
internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
55
docker-compose.yml
Normal file
55
docker-compose.yml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
services:
|
||||||
|
php:
|
||||||
|
container_name: php-${DOCKER_APP_NAME}-fpm
|
||||||
|
build:
|
||||||
|
context: ./docker/php
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
DOCKER_PHP_VERSION: ${DOCKER_PHP_VERSION}
|
||||||
|
DOCKER_NODE_VERSION: ${DOCKER_NODE_VERSION}
|
||||||
|
CURRENT_UID: ${CURRENT_UID}
|
||||||
|
CURRENT_GID: ${CURRENT_GID}
|
||||||
|
environment:
|
||||||
|
PHP_IDE_CONFIG: serverName=${DOCKER_APP_NAME}-docker
|
||||||
|
XDEBUG_CLIENT_HOST: ${XDEBUG_CLIENT_HOST:-host.docker.internal}
|
||||||
|
XDEBUG_CONFIG: client_host=${XDEBUG_CLIENT_HOST:-host.docker.internal} client_port=9003
|
||||||
|
DATABASE_URL: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?serverVersion=16&charset=utf8"
|
||||||
|
volumes:
|
||||||
|
- ./:/var/www/html
|
||||||
|
- ~/.cache:/var/www/.cache # Pour la cache de composer
|
||||||
|
- ~/.config:/var/www/.config # Pour la config de yarn
|
||||||
|
- ~/.composer:/var/www/.composer # Pour la config de composer
|
||||||
|
- ./docker/php/config/php.ini:/usr/local/etc/php/php.ini
|
||||||
|
- ./docker/php/config/docker-php-ext-xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||||
|
- ./LOG:/var/www/html/LOG
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
restart: unless-stopped
|
||||||
|
nginx:
|
||||||
|
image: nginx:1.27-alpine
|
||||||
|
container_name: nginx-${DOCKER_APP_NAME}
|
||||||
|
depends_on:
|
||||||
|
- php
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
volumes:
|
||||||
|
- ./:/var/www/html:ro
|
||||||
|
- ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
|
||||||
|
restart: unless-stopped
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB}
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- pg_data:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "${POSTGRES_PORT:-5432}:5432"
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
pg_data:
|
||||||
9
docker/.env.docker
Normal file
9
docker/.env.docker
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
DOCKER_APP_NAME=ferme
|
||||||
|
DOCKER_PHP_VERSION=8.4.6
|
||||||
|
DOCKER_NODE_VERSION=24.12.0
|
||||||
|
APP_USER=www-data
|
||||||
|
POSTGRES_DB=ferme
|
||||||
|
POSTGRES_USER=root
|
||||||
|
POSTGRES_PASSWORD=root
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
XDEBUG_CLIENT_HOST=host.docker.internal
|
||||||
42
docker/nginx/conf.d/ferme.conf
Normal file
42
docker/nginx/conf.d/ferme.conf
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
root /var/www/html/frontend/dist;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location ^~ /api/ {
|
||||||
|
root /var/www/html/public;
|
||||||
|
try_files $uri /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /bundles/ {
|
||||||
|
root /var/www/html/public;
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /api/login_check {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/html/public/index.php;
|
||||||
|
fastcgi_param DOCUMENT_ROOT /var/www/html/public;
|
||||||
|
fastcgi_param SCRIPT_NAME /index.php;
|
||||||
|
fastcgi_param PATH_INFO /login_check;
|
||||||
|
fastcgi_param REQUEST_URI /login_check;
|
||||||
|
fastcgi_pass php:9000;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/index\.php(/|$) {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/html/public/index.php;
|
||||||
|
fastcgi_param DOCUMENT_ROOT /var/www/html/public;
|
||||||
|
fastcgi_pass php:9000;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
124
docker/php/Dockerfile
Normal file
124
docker/php/Dockerfile
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
ARG DOCKER_PHP_VERSION
|
||||||
|
|
||||||
|
FROM php:${DOCKER_PHP_VERSION}-fpm-bullseye
|
||||||
|
|
||||||
|
ARG DOCKER_NODE_VERSION
|
||||||
|
ENV DOCKER_NODE_VERSION="${DOCKER_NODE_VERSION}"
|
||||||
|
|
||||||
|
# Installer les dépendances et extensions PHP nécessaires
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
libicu-dev \
|
||||||
|
libpq-dev \
|
||||||
|
libpng-dev \
|
||||||
|
libzip-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
ca-certificates \
|
||||||
|
gnupg \
|
||||||
|
libbz2-dev \
|
||||||
|
libgmp-dev \
|
||||||
|
libldap2-dev \
|
||||||
|
libonig-dev \
|
||||||
|
libsodium-dev \
|
||||||
|
libxslt1-dev \
|
||||||
|
unixodbc-dev \
|
||||||
|
libsqlite3-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
libssl-dev \
|
||||||
|
libc-client-dev \
|
||||||
|
libkrb5-dev \
|
||||||
|
freetds-dev \
|
||||||
|
vim \
|
||||||
|
tcpdump \
|
||||||
|
dnsutils \
|
||||||
|
wget \
|
||||||
|
git \
|
||||||
|
unzip \
|
||||||
|
&& docker-php-ext-install -j$(nproc) \
|
||||||
|
intl \
|
||||||
|
zip \
|
||||||
|
bcmath \
|
||||||
|
bz2 \
|
||||||
|
calendar \
|
||||||
|
exif \
|
||||||
|
gd \
|
||||||
|
gettext \
|
||||||
|
gmp \
|
||||||
|
ldap \
|
||||||
|
# mysqli \
|
||||||
|
pcntl \
|
||||||
|
pdo_pgsql \
|
||||||
|
# pdo_mysql \
|
||||||
|
# pdo_sqlite \
|
||||||
|
# pdo_sqlsrv \
|
||||||
|
soap \
|
||||||
|
sockets \
|
||||||
|
sysvsem \
|
||||||
|
xsl
|
||||||
|
|
||||||
|
|
||||||
|
# Installation de node
|
||||||
|
RUN wget -qO- "https://nodejs.org/dist/v${DOCKER_NODE_VERSION}/node-v${DOCKER_NODE_VERSION}-linux-x64.tar.xz" | tar xJC /tmp/ && \
|
||||||
|
cp -r /tmp/node-v${DOCKER_NODE_VERSION}-linux-x64/bin /usr/ && \
|
||||||
|
cp -r /tmp/node-v${DOCKER_NODE_VERSION}-linux-x64/include /usr/ && \
|
||||||
|
cp -r /tmp/node-v${DOCKER_NODE_VERSION}-linux-x64/lib /usr/ && \
|
||||||
|
cp -r /tmp/node-v${DOCKER_NODE_VERSION}-linux-x64/share /usr/ && \
|
||||||
|
npm install --global yarn
|
||||||
|
|
||||||
|
# installation/activation d'extensions php
|
||||||
|
RUN pecl install xdebug
|
||||||
|
RUN docker-php-ext-enable xdebug && \
|
||||||
|
docker-php-ext-install zip && \
|
||||||
|
docker-php-ext-install gd && \
|
||||||
|
docker-php-ext-install soap && \
|
||||||
|
docker-php-ext-configure intl && \
|
||||||
|
docker-php-ext-install intl
|
||||||
|
|
||||||
|
# Configuration spéciale pour quelques extensions
|
||||||
|
# RUN docker-php-ext-configure pdo_odbc --with-pdo-odbc=unixODBC,/usr && \
|
||||||
|
# docker-php-ext-install pdo_odbc \
|
||||||
|
RUN docker-php-ext-enable opcache
|
||||||
|
|
||||||
|
# Configurer Oracle OCI8 (nécessite le SDK Oracle, à installer manuellement ou à lier via les dépendances)
|
||||||
|
#RUN apt-get update && apt-get -y install wget unzip libaio1 && \
|
||||||
|
# wget https://download.oracle.com/otn_software/linux/instantclient/2340000/instantclient-basic-linux.x64-23.4.0.24.05.zip && \
|
||||||
|
# unzip -o instantclient-basic-linux.x64-23.4.0.24.05.zip -d /usr/local && \
|
||||||
|
# wget https://download.oracle.com/otn_software/linux/instantclient/2340000/instantclient-sdk-linux.x64-23.4.0.24.05.zip && \
|
||||||
|
# unzip -o instantclient-sdk-linux.x64-23.4.0.24.05.zip -d /usr/local
|
||||||
|
#
|
||||||
|
#RUN echo 'instantclient,/usr/local/instantclient_23_4' | pecl install oci8-3.4.0 \
|
||||||
|
# && docker-php-ext-enable oci8
|
||||||
|
#
|
||||||
|
#ENV ORACLE_BASE /usr/local/instantclient_23_4
|
||||||
|
#ENV LD_LIBRARY_PATH /usr/local/instantclient_23_4
|
||||||
|
#ENV TNS_ADMIN /usr/local/instantclient_23_4
|
||||||
|
#ENV ORACLE_HOME /usr/local/instantclient_23_4
|
||||||
|
|
||||||
|
|
||||||
|
# Configuration pour utiliser Kerberos avec IMAP (si nécessaire)
|
||||||
|
# RUN docker-php-ext-configure imap --with-kerberos --with-imap-ssl \
|
||||||
|
# && docker-php-ext-install imap
|
||||||
|
|
||||||
|
# installation de composer
|
||||||
|
RUN rm -rf /var/cache/apk/* && rm -rf /tmp/* && \
|
||||||
|
curl --insecure https://getcomposer.org/composer.phar -o /usr/bin/composer && chmod +x /usr/bin/composer
|
||||||
|
|
||||||
|
# Création de la structure du projet
|
||||||
|
RUN mkdir /var/www/html/LOG
|
||||||
|
|
||||||
|
###> User ###
|
||||||
|
ARG CURRENT_UID
|
||||||
|
ARG CURRENT_GID
|
||||||
|
# mapping du user host avec www-data
|
||||||
|
RUN usermod -o -u ${CURRENT_UID} www-data && groupmod -o -g ${CURRENT_GID} www-data
|
||||||
|
RUN chown www-data:www-data -R /var/www/*
|
||||||
|
RUN chown www-data:www-data -R /var/www/.*
|
||||||
|
###< User ###
|
||||||
|
|
||||||
|
RUN rm -rf \
|
||||||
|
/var/lib/apt/lists/* \
|
||||||
|
/tmp/* \
|
||||||
|
/var/tmp/*
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
9
docker/php/config/docker-php-ext-xdebug.ini
Normal file
9
docker/php/config/docker-php-ext-xdebug.ini
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
zend_extension = /usr/local/lib/php/extensions/no-debug-non-zts-20240924/xdebug.so
|
||||||
|
xdebug.mode=debug
|
||||||
|
xdebug.idekey=PHPSTORM
|
||||||
|
xdebug.start_with_request=yes
|
||||||
|
xdebug.discover_client_host=1
|
||||||
|
xdebug.client_port=9003
|
||||||
|
xdebug.log="/var/www/html/LOG/xdebug.log"
|
||||||
|
xdebug.log_level=0
|
||||||
|
xdebug.connect_timeout_ms=2
|
||||||
4
docker/php/config/php.ini
Normal file
4
docker/php/config/php.ini
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[Date]
|
||||||
|
; Defines the default timezone used by the date functions
|
||||||
|
; http://php.net/date.timezone
|
||||||
|
date.timezone = Europe/Paris
|
||||||
24
frontend/.gitignore
vendored
Normal file
24
frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Nuxt dev/build outputs
|
||||||
|
.output
|
||||||
|
.data
|
||||||
|
.nuxt
|
||||||
|
.nitro
|
||||||
|
.cache
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Node dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
|
.fleet
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Local env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
75
frontend/README.md
Normal file
75
frontend/README.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# Nuxt Minimal Starter
|
||||||
|
|
||||||
|
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Make sure to install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Server
|
||||||
|
|
||||||
|
Start the development server on `http://localhost:3000`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm dev
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production
|
||||||
|
|
||||||
|
Build the application for production:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm build
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Locally preview production build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm
|
||||||
|
npm run preview
|
||||||
|
|
||||||
|
# pnpm
|
||||||
|
pnpm preview
|
||||||
|
|
||||||
|
# yarn
|
||||||
|
yarn preview
|
||||||
|
|
||||||
|
# bun
|
||||||
|
bun run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||||
5
frontend/app.vue
Normal file
5
frontend/app.vue
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<NuxtLayout>
|
||||||
|
<NuxtPage />
|
||||||
|
</NuxtLayout>
|
||||||
|
</template>
|
||||||
18
frontend/assets/css/toast.css
Normal file
18
frontend/assets/css/toast.css
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
.iziToast {
|
||||||
|
font-size: 16px;
|
||||||
|
min-height: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iziToast > .iziToast-body {
|
||||||
|
padding: 18px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iziToast > .iziToast-body .iziToast-title {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iziToast > .iziToast-body .iziToast-message {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
0
frontend/components/.gitkeep
Normal file
0
frontend/components/.gitkeep
Normal file
80
frontend/components/reception/reception-form.vue
Normal file
80
frontend/components/reception/reception-form.vue
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<form @submit.prevent="validate">
|
||||||
|
<div class="grid grid-cols-1 items-start gap-8 mb-16">
|
||||||
|
<h1 class="font-bold text-5xl uppercase">Réception</h1>
|
||||||
|
<div>
|
||||||
|
<UiLicensePlateInput
|
||||||
|
v-model="form.licensePlate"
|
||||||
|
v-model:allowAny="allowAnyLicensePlate"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<label for="reception-date" class="font-bold uppercase text-xl mb-4">Date de reception</label>
|
||||||
|
<input
|
||||||
|
id="reception-date"
|
||||||
|
v-model="form.receptionDate"
|
||||||
|
type="date"
|
||||||
|
class="border-b border-black justify-self-start text-xl pb-[6px] uppercase"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] justify-self-end"
|
||||||
|
>Peser
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useReceptionStore } from '~/stores/reception'
|
||||||
|
|
||||||
|
type ReceptionFormData = {
|
||||||
|
licensePlate: string
|
||||||
|
receptionDate: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const receptionStore = useReceptionStore()
|
||||||
|
const form = reactive<ReceptionFormData>({
|
||||||
|
licensePlate: '',
|
||||||
|
receptionDate: new Date().toISOString().slice(0, 10)
|
||||||
|
})
|
||||||
|
const allowAnyLicensePlate = ref(false)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => receptionStore.current,
|
||||||
|
(reception) => {
|
||||||
|
form.licensePlate = reception?.licensePlate ?? ''
|
||||||
|
form.receptionDate = reception?.receptionDate ?? new Date().toISOString().slice(0, 10)
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
async function validate() {
|
||||||
|
const normalizedLicensePlate = form.licensePlate.trim()
|
||||||
|
const normalizedReceptionDate = form.receptionDate.trim()
|
||||||
|
|
||||||
|
if (!receptionStore.current) {
|
||||||
|
const created = await receptionStore.createReception({
|
||||||
|
currentStep: 1,
|
||||||
|
licensePlate: normalizedLicensePlate,
|
||||||
|
receptionDate: normalizedReceptionDate
|
||||||
|
})
|
||||||
|
if (created) {
|
||||||
|
await router.push(`/reception/${created.id}`)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextStep = receptionStore.current.currentStep + 1
|
||||||
|
await receptionStore.updateReception(receptionStore.current.id, {
|
||||||
|
currentStep: nextStep,
|
||||||
|
licensePlate: normalizedLicensePlate,
|
||||||
|
receptionDate: normalizedReceptionDate
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
30
frontend/components/reception/reception-unloading.vue
Normal file
30
frontend/components/reception/reception-unloading.vue
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col items-center mt-[164px] gap-32">
|
||||||
|
<div class="flex gap-8 items-center justify-center">
|
||||||
|
<!--@TODO Prendre en compte que l'on peut aussi décharger de la marchandise-->
|
||||||
|
<h1 class="text-4xl uppercase font-bold">Décharger les bêtes</h1>
|
||||||
|
<UiLoadingDots />
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
|
||||||
|
@click="goNext"
|
||||||
|
>Peser</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useReceptionStore } from '~/stores/reception'
|
||||||
|
|
||||||
|
const receptionStore = useReceptionStore()
|
||||||
|
|
||||||
|
async function goNext() {
|
||||||
|
if (!receptionStore.current) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextStep = receptionStore.current.currentStep + 1
|
||||||
|
await receptionStore.updateReception(receptionStore.current.id, {
|
||||||
|
currentStep: nextStep
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
104
frontend/components/reception/reception-weight.vue
Normal file
104
frontend/components/reception/reception-weight.vue
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<div class="flex flex-col items-center w-[660px]">
|
||||||
|
<h1 class="font-bold text-5xl uppercase">{{ title }}</h1>
|
||||||
|
<!--@TODO Voir comment faire pour savoir si le pont-bascule et bien connecté + ajouter un icon comme sur la maquette-->
|
||||||
|
<p class="text-primary-500 uppercase text-2xl mt-2">Pont-bascule connecté</p>
|
||||||
|
<div
|
||||||
|
v-if="showLoadingBox"
|
||||||
|
class="w-full flex flex-col items-center justify-center border border-black h-[90px] mt-12 mb-[86px]">
|
||||||
|
<UiLoadingDots />
|
||||||
|
</div>
|
||||||
|
<div v-else-if="displayWeight !== null" class="w-full">
|
||||||
|
<div
|
||||||
|
class="w-full flex flex-col items-center justify-center border border-black h-[90px] mt-12 mb-[25px] text-4xl">
|
||||||
|
{{ displayWeight }} kg
|
||||||
|
</div>
|
||||||
|
<!-- <div class="grid grid-cols-2 border border-black text-center">-->
|
||||||
|
<!-- <p class="border-r border-black py-3 text-4xl font-bold">DSD</p>-->
|
||||||
|
<!-- <p class="py-3 text-4xl">{{ displayDsd }}</p>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-center mt-[54px]">
|
||||||
|
<button
|
||||||
|
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
|
||||||
|
@click="fetchWeight"
|
||||||
|
>{{ displayWeight !== null ? 'refaire une pesee' : 'peser' }}</button>
|
||||||
|
<button
|
||||||
|
v-if="displayWeight !== null && !showGenerateReceipt"
|
||||||
|
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] ml-4"
|
||||||
|
@click="saveWeight"
|
||||||
|
>Valider la pesée</button>
|
||||||
|
<button
|
||||||
|
v-if="showGenerateReceipt"
|
||||||
|
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] ml-4"
|
||||||
|
@click="printReceipt"
|
||||||
|
>Générer le bon</button>
|
||||||
|
</div>
|
||||||
|
<UiPdfPrinter ref="pdfPrinter" />
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useWeighing } from '~/composables/useWeighing'
|
||||||
|
import { useReceptionStore } from '~/stores/reception'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
mode: 'gross' | 'tare'
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const receptionStore = useReceptionStore()
|
||||||
|
const { current: storeReception } = storeToRefs(receptionStore)
|
||||||
|
type PdfPrinterHandle = {
|
||||||
|
print: (url: string) => Promise<void>
|
||||||
|
}
|
||||||
|
// Ref sur le composant d'impression pour déclencher le print() du PDF.
|
||||||
|
const pdfPrinter = ref<PdfPrinterHandle | null>(null)
|
||||||
|
const {
|
||||||
|
displayWeight,
|
||||||
|
displayDsd,
|
||||||
|
title,
|
||||||
|
showLoadingBox,
|
||||||
|
fetchWeight,
|
||||||
|
saveWeight
|
||||||
|
} = useWeighing({
|
||||||
|
mode: props.mode,
|
||||||
|
reception: storeReception,
|
||||||
|
updateReception: receptionStore.updateReception,
|
||||||
|
loadReception: receptionStore.loadReception
|
||||||
|
})
|
||||||
|
const showGenerateReceipt = computed(
|
||||||
|
() => props.mode === 'tare' && displayWeight.value !== null
|
||||||
|
)
|
||||||
|
|
||||||
|
const printReceipt = async () => {
|
||||||
|
if (!import.meta.client || !receptionStore.current || !pdfPrinter.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await saveWeight()
|
||||||
|
await pdfPrinter.value.print(`/receptions/${receptionStore.current.id}/receipt`)
|
||||||
|
|
||||||
|
// Laisse le temps a la boite de dialogue d'impression de s'ouvrir.
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 600))
|
||||||
|
|
||||||
|
const result = await receptionStore.updateReception(receptionStore.current.id, {
|
||||||
|
isValid: true
|
||||||
|
})
|
||||||
|
if (!result) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
receptionStore.clearCurrent()
|
||||||
|
await router.push('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchWeight()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
93
frontend/components/ui/license-plate-input.vue
Normal file
93
frontend/components/ui/license-plate-input.vue
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<label :for="inputId" class="font-bold uppercase text-xl mb-4">{{ label }}</label>
|
||||||
|
<input
|
||||||
|
:id="inputId"
|
||||||
|
:value="modelValue"
|
||||||
|
v-maska="maskOptions"
|
||||||
|
type="text"
|
||||||
|
:maxlength="maxLength"
|
||||||
|
:placeholder="placeholderText"
|
||||||
|
class="border-b border-black justify-self-start text-xl pb-[6px] uppercase"
|
||||||
|
@input="handleInput"
|
||||||
|
/>
|
||||||
|
<label :for="checkboxId" class="mt-3 flex items-center gap-3 text-sm">
|
||||||
|
<input
|
||||||
|
:id="checkboxId"
|
||||||
|
:checked="allowAny"
|
||||||
|
type="checkbox"
|
||||||
|
class="h-4 w-4 accent-primary-500"
|
||||||
|
@change="toggleAllowAny"
|
||||||
|
/>
|
||||||
|
Autoriser un format libre
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { vMaska } from 'maska/vue'
|
||||||
|
type Props = {
|
||||||
|
modelValue: string
|
||||||
|
allowAny?: boolean
|
||||||
|
label?: string
|
||||||
|
id?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
allowAny: false,
|
||||||
|
label: 'Immatriculation',
|
||||||
|
id: 'license-plate'
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(event: 'update:modelValue', value: string): void
|
||||||
|
(event: 'update:allowAny', value: boolean): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const inputId = computed(() => props.id)
|
||||||
|
const checkboxId = computed(() => `${props.id}-format`)
|
||||||
|
|
||||||
|
const maskOptions = computed(() =>
|
||||||
|
props.allowAny
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
mask: '@@-###-@@',
|
||||||
|
eager: true,
|
||||||
|
tokens: {
|
||||||
|
'@': {
|
||||||
|
pattern: /[A-Za-z]/,
|
||||||
|
transform: (char: string) => char.toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const placeholderText = computed(() => (props.allowAny ? '' : 'AA-123-AA'))
|
||||||
|
const maxLength = computed(() => (props.allowAny ? 20 : 9))
|
||||||
|
|
||||||
|
const handleInput = (event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement | null
|
||||||
|
if (!target) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.allowAny) {
|
||||||
|
emit('update:modelValue', target.value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('update:modelValue', target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleAllowAny = (event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement | null
|
||||||
|
if (!target) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextValue = target.checked
|
||||||
|
emit('update:allowAny', nextValue)
|
||||||
|
if (!nextValue) {
|
||||||
|
emit('update:modelValue', props.modelValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
50
frontend/components/ui/loading-dots.vue
Normal file
50
frontend/components/ui/loading-dots.vue
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex items-center gap-2 text-sm uppercase">
|
||||||
|
<span class="loader-dots">
|
||||||
|
<span class="loader-dot"></span>
|
||||||
|
<span class="loader-dot"></span>
|
||||||
|
<span class="loader-dot"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.loader-dots {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-dot {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 9999px;
|
||||||
|
background: currentColor;
|
||||||
|
animation: loader-bounce 1s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-dot:nth-child(2) {
|
||||||
|
animation-delay: 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-dot:nth-child(3) {
|
||||||
|
animation-delay: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loader-bounce {
|
||||||
|
0%,
|
||||||
|
80%,
|
||||||
|
100% {
|
||||||
|
transform: scale(0.6);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
20
frontend/components/ui/pdf-printer.vue
Normal file
20
frontend/components/ui/pdf-printer.vue
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<iframe ref="printFrame" class="hidden" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { usePdfPrinter } from '~/composables/usePdfPrinter'
|
||||||
|
|
||||||
|
const printFrame = ref<HTMLIFrameElement | null>(null)
|
||||||
|
const { printPdf } = usePdfPrinter()
|
||||||
|
|
||||||
|
// Expose une methode simple pour imprimer un PDF depuis les ecrans.
|
||||||
|
const print = async (url: string): Promise<void> => {
|
||||||
|
return printPdf(url, printFrame)
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
print
|
||||||
|
})
|
||||||
|
</script>
|
||||||
166
frontend/composables/useApi.ts
Normal file
166
frontend/composables/useApi.ts
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
import type { FetchOptions } from 'ofetch'
|
||||||
|
import { $fetch, FetchError } from 'ofetch'
|
||||||
|
import { useAuthStore } from '~/stores/auth'
|
||||||
|
|
||||||
|
export type AnyObject = Record<string, unknown>
|
||||||
|
|
||||||
|
export type ApiClient = {
|
||||||
|
get<T>(url: string, query?: AnyObject, options?: ApiFetchOptions<'json'>): Promise<T>
|
||||||
|
getBlob(url: string, query?: AnyObject, options?: ApiFetchOptions<'blob'>): Promise<Blob>
|
||||||
|
post<T>(url: string, body?: AnyObject, options?: ApiFetchOptions<'json'>): Promise<T>
|
||||||
|
put<T>(url: string, body?: AnyObject, options?: ApiFetchOptions<'json'>): Promise<T>
|
||||||
|
patch<T>(url: string, body?: AnyObject, options?: ApiFetchOptions<'json'>): Promise<T>
|
||||||
|
delete<T>(url: string, query?: AnyObject, options?: ApiFetchOptions<'json'>): Promise<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ApiFetchOptions<ResponseType extends 'json' | 'blob'> =
|
||||||
|
FetchOptions<ResponseType> & {
|
||||||
|
toast?: boolean
|
||||||
|
toastTitle?: string
|
||||||
|
toastErrorMessage?: string
|
||||||
|
toastSuccessMessage?: string
|
||||||
|
toastErrorKey?: string
|
||||||
|
toastSuccessKey?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useApi = (): ApiClient => {
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
const baseURL = config.public.apiBase ?? '/api'
|
||||||
|
const toast = useToast()
|
||||||
|
const auth = useAuthStore()
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
const i18n = nuxtApp.$i18n as
|
||||||
|
| {
|
||||||
|
t: (key: string) => string
|
||||||
|
te?: (key: string) => boolean
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
const t = (key: string) => (i18n?.t ? String(i18n.t(key)) : key)
|
||||||
|
const te = (key: string) => (i18n?.te ? i18n.te(key) : false)
|
||||||
|
|
||||||
|
const extractErrorMessage = (error: unknown, responseData?: unknown): string => {
|
||||||
|
const data = responseData ?? (error as FetchError)?.data
|
||||||
|
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data && typeof data === 'object') {
|
||||||
|
const record = data as Record<string, unknown>
|
||||||
|
return (
|
||||||
|
(record['hydra:description'] as string) ||
|
||||||
|
(record.detail as string) ||
|
||||||
|
(record.message as string) ||
|
||||||
|
(record.error as string) ||
|
||||||
|
(record.title as string) ||
|
||||||
|
(record['hydra:title'] as string) ||
|
||||||
|
''
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (error as FetchError)?.message ?? 'Erreur inconnue.'
|
||||||
|
}
|
||||||
|
|
||||||
|
const methodErrorKeys: Record<string, string> = {
|
||||||
|
GET: 'errors.http.get',
|
||||||
|
POST: 'errors.http.post',
|
||||||
|
PUT: 'errors.http.put',
|
||||||
|
PATCH: 'errors.http.patch',
|
||||||
|
DELETE: 'errors.http.delete'
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = $fetch.create({
|
||||||
|
baseURL,
|
||||||
|
retry: 0,
|
||||||
|
credentials: 'include',
|
||||||
|
onResponse({ options, response }) {
|
||||||
|
const apiOptions = options as ApiFetchOptions<'json'>
|
||||||
|
if (apiOptions?.toast === false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response?.status && response.status >= 400) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const successKey = apiOptions?.toastSuccessKey
|
||||||
|
const successMessage =
|
||||||
|
apiOptions?.toastSuccessMessage ||
|
||||||
|
(successKey ? (te(successKey) ? t(successKey) : successKey) : '')
|
||||||
|
|
||||||
|
if (successMessage) {
|
||||||
|
toast.success({
|
||||||
|
title: 'Succès',
|
||||||
|
message: successMessage
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onResponseError({ response, error, options }) {
|
||||||
|
const apiOptions = options as ApiFetchOptions<'json'>
|
||||||
|
if (apiOptions?.toast === false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const method =
|
||||||
|
typeof options?.method === 'string' ? options.method.toUpperCase() : 'GET'
|
||||||
|
const defaultKey = methodErrorKeys[method]
|
||||||
|
const defaultMessage =
|
||||||
|
defaultKey && te(defaultKey) ? t(defaultKey) : ''
|
||||||
|
const errorKey = apiOptions?.toastErrorKey
|
||||||
|
const errorMessage =
|
||||||
|
errorKey ? (te(errorKey) ? t(errorKey) : errorKey) : ''
|
||||||
|
const extractedMessage = extractErrorMessage(error, response?._data)
|
||||||
|
const message =
|
||||||
|
apiOptions?.toastErrorMessage ||
|
||||||
|
errorMessage ||
|
||||||
|
defaultMessage ||
|
||||||
|
extractedMessage ||
|
||||||
|
'Une erreur est survenue.'
|
||||||
|
|
||||||
|
toast.error({
|
||||||
|
title: apiOptions?.toastTitle ?? 'Erreur',
|
||||||
|
message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const request = <T>(
|
||||||
|
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
|
||||||
|
url: string,
|
||||||
|
options: ApiFetchOptions<'json'> = {}
|
||||||
|
) => {
|
||||||
|
const needsJsonBody = method === 'POST' || method === 'PUT'
|
||||||
|
const needsMergePatch = method === 'PATCH'
|
||||||
|
|
||||||
|
const headers = new Headers(options.headers as HeadersInit | undefined)
|
||||||
|
|
||||||
|
if (needsMergePatch && !headers.has('Content-Type')) {
|
||||||
|
headers.set('Content-Type', 'application/merge-patch+json')
|
||||||
|
} else if (needsJsonBody && !headers.has('Content-Type')) {
|
||||||
|
headers.set('Content-Type', 'application/json')
|
||||||
|
}
|
||||||
|
|
||||||
|
return client<T>(url, { ...options, method, headers })
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
get<T>(url: string, query: AnyObject = {}, options: ApiFetchOptions<'json'> = {}) {
|
||||||
|
return request<T>('GET', url, { ...options, query })
|
||||||
|
},
|
||||||
|
getBlob(url: string, query: AnyObject = {}, options: ApiFetchOptions<'blob'> = {}) {
|
||||||
|
return client<Blob>(url, { ...options, method: 'GET', query, responseType: 'blob' })
|
||||||
|
},
|
||||||
|
post<T>(url: string, body: AnyObject = {}, options: ApiFetchOptions<'json'> = {}) {
|
||||||
|
return request<T>('POST', url, { ...options, body })
|
||||||
|
},
|
||||||
|
put<T>(url: string, body: AnyObject = {}, options: ApiFetchOptions<'json'> = {}) {
|
||||||
|
return request<T>('PUT', url, { ...options, body })
|
||||||
|
},
|
||||||
|
patch<T>(url: string, body: AnyObject = {}, options: ApiFetchOptions<'json'> = {}) {
|
||||||
|
return request<T>('PATCH', url, { ...options, body })
|
||||||
|
},
|
||||||
|
delete<T>(url: string, query: AnyObject = {}, options: ApiFetchOptions<'json'> = {}) {
|
||||||
|
return request<T>('DELETE', url, { ...options, query })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
frontend/composables/usePdfPrinter.ts
Normal file
40
frontend/composables/usePdfPrinter.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import type { Ref } from 'vue'
|
||||||
|
import { useApi } from '~/composables/useApi'
|
||||||
|
|
||||||
|
type PrintFrameRef = Ref<HTMLIFrameElement | null>
|
||||||
|
|
||||||
|
export const usePdfPrinter = () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const printPdf = async (url: string, frameRef: PrintFrameRef): Promise<void> => {
|
||||||
|
if (!import.meta.client) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const frame = frameRef.value
|
||||||
|
if (!frame) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// On charge le PDF en blob pour rester en same-origin dans l'iframe.
|
||||||
|
const blob = await api.getBlob(url)
|
||||||
|
const blobUrl = URL.createObjectURL(blob)
|
||||||
|
|
||||||
|
const tryPrint = () => {
|
||||||
|
frame.contentWindow?.focus()
|
||||||
|
frame.contentWindow?.print()
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.onload = () => {
|
||||||
|
tryPrint()
|
||||||
|
// On libere l'URL blob apres l'impression.
|
||||||
|
setTimeout(() => URL.revokeObjectURL(blobUrl), 2000)
|
||||||
|
}
|
||||||
|
frame.src = blobUrl
|
||||||
|
setTimeout(tryPrint, 1200)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
printPdf
|
||||||
|
}
|
||||||
|
}
|
||||||
99
frontend/composables/useWeighing.ts
Normal file
99
frontend/composables/useWeighing.ts
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import type {Ref} from 'vue'
|
||||||
|
import {computed, ref} from 'vue'
|
||||||
|
import type {ReceptionData, WeightEntryData} from '~/services/dto/reception-data'
|
||||||
|
import type {WeightData} from '~/services/dto/weight-data'
|
||||||
|
import {getWeight} from '~/services/reception'
|
||||||
|
import {createWeight, updateWeight} from '~/services/weight'
|
||||||
|
|
||||||
|
export type WeighingMode = 'gross' | 'tare'
|
||||||
|
|
||||||
|
type UseWeighingOptions = {
|
||||||
|
mode: WeighingMode
|
||||||
|
reception: Ref<ReceptionData | null>
|
||||||
|
updateReception: (id: number, payload: Partial<ReceptionData>) => Promise<ReceptionData | null>
|
||||||
|
loadReception?: (id: number) => Promise<ReceptionData | null>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useWeighing = ({
|
||||||
|
mode,
|
||||||
|
reception,
|
||||||
|
updateReception,
|
||||||
|
loadReception
|
||||||
|
}: UseWeighingOptions) => {
|
||||||
|
const weightData = ref<WeightData | null>(null)
|
||||||
|
const isFetching = ref(false)
|
||||||
|
|
||||||
|
const currentWeightEntry = computed<WeightEntryData | null>(() => {
|
||||||
|
const weights = reception.value?.weights ?? []
|
||||||
|
return weights.find((entry) => entry.type === mode) ?? null
|
||||||
|
})
|
||||||
|
|
||||||
|
const displayWeight = computed(() => weightData.value?.weight ?? currentWeightEntry.value?.weight ?? null)
|
||||||
|
const displayDsd = computed(() => weightData.value?.dsd ?? currentWeightEntry.value?.dsd ?? '-')
|
||||||
|
const title = computed(() => (mode === 'gross' ? 'Pesée à plein' : 'Pesée à vide'))
|
||||||
|
const showLoadingBox = computed(
|
||||||
|
() => isFetching.value || (displayWeight.value === null && currentWeightEntry.value === null)
|
||||||
|
)
|
||||||
|
|
||||||
|
const fetchWeight = async () => {
|
||||||
|
isFetching.value = true
|
||||||
|
weightData.value = await getWeight().finally(() => {
|
||||||
|
isFetching.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveWeight = async () => {
|
||||||
|
if (!reception.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingEntry = currentWeightEntry.value
|
||||||
|
const baseDsd = weightData.value?.dsd ?? existingEntry?.dsd ?? null
|
||||||
|
const baseWeight = weightData.value?.weight ?? existingEntry?.weight ?? null
|
||||||
|
const baseWeighedAt = weightData.value?.weighedAt ?? existingEntry?.weighedAt ?? null
|
||||||
|
|
||||||
|
if (baseWeight === null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingEntry?.id) {
|
||||||
|
await updateWeight(existingEntry.id, {
|
||||||
|
type: mode,
|
||||||
|
dsd: baseDsd,
|
||||||
|
weight: baseWeight,
|
||||||
|
weighedAt: baseWeighedAt
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await createWeight({
|
||||||
|
reception: `/receptions/${reception.value.id}`,
|
||||||
|
type: mode,
|
||||||
|
dsd: baseDsd,
|
||||||
|
weight: baseWeight,
|
||||||
|
weighedAt: baseWeighedAt
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextStep = mode === 'tare'
|
||||||
|
? reception.value.currentStep
|
||||||
|
: reception.value.currentStep + 1
|
||||||
|
await updateReception(reception.value.id, {
|
||||||
|
currentStep: nextStep,
|
||||||
|
isValid: reception.value.isValid
|
||||||
|
})
|
||||||
|
|
||||||
|
if (loadReception) {
|
||||||
|
await loadReception(reception.value.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
weightData,
|
||||||
|
currentWeightEntry,
|
||||||
|
displayWeight,
|
||||||
|
displayDsd,
|
||||||
|
title,
|
||||||
|
showLoadingBox,
|
||||||
|
fetchWeight,
|
||||||
|
saveWeight
|
||||||
|
}
|
||||||
|
}
|
||||||
32
frontend/i18n/locales/fr.json
Normal file
32
frontend/i18n/locales/fr.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"errors": {
|
||||||
|
"http": {
|
||||||
|
"get": "Impossible de récupérer les données.",
|
||||||
|
"post": "Impossible de créer la ressource.",
|
||||||
|
"put": "Impossible de mettre à jour la ressource.",
|
||||||
|
"patch": "Impossible de mettre à jour la ressource.",
|
||||||
|
"delete": "Impossible de supprimer la ressource."
|
||||||
|
},
|
||||||
|
"reception": {
|
||||||
|
"list": "Impossible de récupérer la liste des réceptions.",
|
||||||
|
"fetch": "Impossible de récupérer la réception.",
|
||||||
|
"create": "Impossible de créer la réception.",
|
||||||
|
"update": "Impossible de mettre à jour la réception.",
|
||||||
|
"weigh": "Impossible de récupérer la pesée."
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"login": "Identifiants invalides.",
|
||||||
|
"users": "Impossible de récupérer les utilisateurs.",
|
||||||
|
"logout": "Impossible de se déconnecter."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"reception": {
|
||||||
|
"update": "Réception mise à jour avec succès."
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"login": "Connexion réussie.",
|
||||||
|
"logout": "Déconnexion réussie."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
frontend/layouts/auth.vue
Normal file
7
frontend/layouts/auth.vue
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<div class="min-h-screen bg-primary-500 from-primary-50 via-white to-neutral-100 text-neutral-900">
|
||||||
|
<main class="mx-auto flex min-h-screen w-full max-w-[720px] items-center px-6 py-12">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
61
frontend/layouts/default.vue
Normal file
61
frontend/layouts/default.vue
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<div class="min-h-screen bg-white text-neutral-900">
|
||||||
|
<header class="w-full border-b border-neutral-200 bg-primary-500">
|
||||||
|
<div class="flex w-full items-center px-6 py-4">
|
||||||
|
<NuxtLink to="/" class="flex items-center gap-3">
|
||||||
|
<span
|
||||||
|
class="flex items-center justify-center bg-white text-xl font-bold uppercase text-primary-500 p-4"
|
||||||
|
>
|
||||||
|
LOGO
|
||||||
|
</span>
|
||||||
|
</NuxtLink>
|
||||||
|
<nav class="mx-8 flex flex-1 gap-8 text-2xl font-bold uppercase text-white">
|
||||||
|
<NuxtLink to="/" custom v-slot="{ href, navigate, isExactActive }">
|
||||||
|
<a
|
||||||
|
:href="href"
|
||||||
|
@click="navigate"
|
||||||
|
:class="isExactActive ? 'opacity-100' : 'opacity-50'"
|
||||||
|
>
|
||||||
|
Accueil
|
||||||
|
</a>
|
||||||
|
</NuxtLink>
|
||||||
|
<NuxtLink to="/reception" custom v-slot="{ href, navigate, isActive }">
|
||||||
|
<a
|
||||||
|
:href="href"
|
||||||
|
@click="navigate"
|
||||||
|
:class="isReceptionActive ? 'opacity-100' : 'opacity-50'"
|
||||||
|
>
|
||||||
|
Reception
|
||||||
|
</a>
|
||||||
|
</NuxtLink>
|
||||||
|
</nav>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="ml-auto text-xl font-bold uppercase text-white transition hover:opacity-80"
|
||||||
|
@click="handleLogout"
|
||||||
|
>
|
||||||
|
Déconnexion
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="mx-auto w-full max-w-[1050px] px-6 pt-[90px] pb-0">
|
||||||
|
<slot/>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useAuthStore } from '~/stores/auth'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const auth = useAuthStore()
|
||||||
|
const isReceptionActive = computed(() => route.path.startsWith('/reception'))
|
||||||
|
|
||||||
|
const handleLogout = async () => {
|
||||||
|
try {
|
||||||
|
await auth.logout()
|
||||||
|
} finally {
|
||||||
|
await navigateTo('/login')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
17
frontend/middleware/auth.global.ts
Normal file
17
frontend/middleware/auth.global.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { useAuthStore } from '~/stores/auth'
|
||||||
|
|
||||||
|
export default defineNuxtRouteMiddleware(async (to) => {
|
||||||
|
const auth = useAuthStore()
|
||||||
|
|
||||||
|
if (to.path === '/login') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!auth.isAuthenticated) {
|
||||||
|
await auth.ensureSession()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!auth.isAuthenticated) {
|
||||||
|
return navigateTo('/login')
|
||||||
|
}
|
||||||
|
})
|
||||||
38
frontend/nuxt.config.ts
Normal file
38
frontend/nuxt.config.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
export default defineNuxtConfig({
|
||||||
|
compatibilityDate: '2025-07-15',
|
||||||
|
devtools: { enabled: true },
|
||||||
|
ssr: false,
|
||||||
|
app: {
|
||||||
|
baseURL: process.env.NUXT_PUBLIC_APP_BASE || '/'
|
||||||
|
},
|
||||||
|
modules: [
|
||||||
|
'@nuxtjs/tailwindcss',
|
||||||
|
'@pinia/nuxt',
|
||||||
|
'nuxt-toast',
|
||||||
|
'@nuxtjs/i18n'
|
||||||
|
],
|
||||||
|
css: ['~/assets/css/toast.css'],
|
||||||
|
runtimeConfig: {
|
||||||
|
public: {
|
||||||
|
apiBase: process.env.NUXT_PUBLIC_API_BASE
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toast: {
|
||||||
|
settings: {
|
||||||
|
timeout: 0,
|
||||||
|
closeOnClick: true,
|
||||||
|
progressBar: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
i18n: {
|
||||||
|
strategy: 'no_prefix',
|
||||||
|
defaultLocale: 'fr',
|
||||||
|
langDir: 'locales',
|
||||||
|
locales: [
|
||||||
|
{ code: 'fr', file: 'fr.json', name: 'Français' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
typescript: {
|
||||||
|
strict: true
|
||||||
|
}
|
||||||
|
})
|
||||||
14365
frontend/package-lock.json
generated
Normal file
14365
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
frontend/package.json
Normal file
28
frontend/package.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "frontend",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "nuxt build",
|
||||||
|
"dev": "nuxt dev",
|
||||||
|
"generate": "nuxt generate",
|
||||||
|
"preview": "nuxt preview",
|
||||||
|
"postinstall": "nuxt prepare",
|
||||||
|
"build:dist": "nuxt generate && rm -rf dist && cp -R .output/public dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nuxtjs/i18n": "^10.2.1",
|
||||||
|
"@pinia/nuxt": "^0.11.3",
|
||||||
|
"izitoast": "^1.4.0",
|
||||||
|
"maska": "^3.2.0",
|
||||||
|
"nuxt": "^4.2.2",
|
||||||
|
"nuxt-toast": "^1.4.0",
|
||||||
|
"pinia": "^3.0.4",
|
||||||
|
"vue": "^3.5.26",
|
||||||
|
"vue-router": "^4.6.4",
|
||||||
|
"zod": "^4.3.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@nuxtjs/tailwindcss": "^6.14.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
21
frontend/pages/index.vue
Normal file
21
frontend/pages/index.vue
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div class="">
|
||||||
|
<h1 class="text-3xl font-bold">Liste des receptions</h1>
|
||||||
|
<ul>
|
||||||
|
<li v-for="reception in receptionList" :key="reception.id">
|
||||||
|
<NuxtLink :to="`/reception/${reception.id}`">Réception numéro {{ reception.id}}</NuxtLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type {ReceptionData} from "~/services/dto/reception-data";
|
||||||
|
import {getReceptionList} from "~/services/reception";
|
||||||
|
|
||||||
|
const receptionList = ref<ReceptionData[]>()
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
receptionList.value = await getReceptionList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
95
frontend/pages/login.vue
Normal file
95
frontend/pages/login.vue
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mx-auto w-full max-w-lg">
|
||||||
|
<span
|
||||||
|
class="flex items-center justify-center bg-white text-xl font-bold uppercase text-primary-500 p-4"
|
||||||
|
>
|
||||||
|
LOGO
|
||||||
|
</span>
|
||||||
|
<form
|
||||||
|
class="mt-8 space-y-6 rounded-lg border border-neutral-200 bg-white p-6 shadow-sm"
|
||||||
|
@submit.prevent="handleSubmit"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-neutral-700" for="user-select">
|
||||||
|
Utilisateur
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="user-select"
|
||||||
|
v-model="selectedUsername"
|
||||||
|
class="mt-2 w-full rounded-md border border-neutral-300 bg-white px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-200"
|
||||||
|
:disabled="isLoadingUsers"
|
||||||
|
>
|
||||||
|
<option value="" disabled>Choisir un utilisateur</option>
|
||||||
|
<option v-for="user in users" :key="user.username" :value="user.username">
|
||||||
|
{{ user.username }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-neutral-700" for="password">
|
||||||
|
Mot de passe
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="password"
|
||||||
|
v-model="password"
|
||||||
|
type="password"
|
||||||
|
autocomplete="current-password"
|
||||||
|
class="mt-2 w-full rounded-md border border-neutral-300 bg-white px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-200"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="w-full rounded-md bg-primary-500 px-4 py-2 text-base font-semibold text-white transition hover:bg-primary-600 disabled:cursor-not-allowed disabled:opacity-60"
|
||||||
|
:disabled="isSubmitting"
|
||||||
|
>
|
||||||
|
Connexion
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { UserData } from '~/services/dto/user-data'
|
||||||
|
import { getUsers } from '~/services/auth'
|
||||||
|
import { useAuthStore } from '~/stores/auth'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const auth = useAuthStore()
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
layout: 'auth'
|
||||||
|
})
|
||||||
|
|
||||||
|
const users = ref<UserData[]>([])
|
||||||
|
const isLoadingUsers = ref(true)
|
||||||
|
const selectedUsername = ref('')
|
||||||
|
const password = ref('')
|
||||||
|
|
||||||
|
const isSubmitting = computed(() => {
|
||||||
|
return auth.isLoading || !selectedUsername.value || !password.value
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadUsers = async () => {
|
||||||
|
isLoadingUsers.value = true
|
||||||
|
try {
|
||||||
|
users.value = await getUsers()
|
||||||
|
} finally {
|
||||||
|
isLoadingUsers.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (isSubmitting.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await auth.login(selectedUsername.value, password.value)
|
||||||
|
await router.push('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
void loadUsers()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
63
frontend/pages/reception/[[id]].vue
Normal file
63
frontend/pages/reception/[[id]].vue
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex justify-between h-[52px] mb-[90px]">
|
||||||
|
<p class="self-center">Indicateur d’étapes</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex flex-col justify-center uppercase text-xl bg-black text-white h-[50px] w-[272px] text-center"
|
||||||
|
@click="saveAndHold"
|
||||||
|
>Mettre en attente</button>
|
||||||
|
</div>
|
||||||
|
<ReceptionForm v-if="!storeReception || storeReception.currentStep === 0"/>
|
||||||
|
<ReceptionWeight v-if="storeReception?.currentStep === 1" mode="gross"/>
|
||||||
|
<ReceptionUnloading v-if="storeReception?.currentStep === 2"/>
|
||||||
|
<ReceptionWeight v-if="storeReception?.currentStep !== null && storeReception?.currentStep >= 3" mode="tare"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useReceptionStore } from '~/stores/reception'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const receptionStore = useReceptionStore()
|
||||||
|
const { current: storeReception } = storeToRefs(receptionStore)
|
||||||
|
|
||||||
|
const resolveReceptionId = (param: unknown) => {
|
||||||
|
const idStr = Array.isArray(param) ? param[0] : param
|
||||||
|
if (!idStr) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const id = Number(idStr)
|
||||||
|
return Number.isFinite(id) ? id : null
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
async (param) => {
|
||||||
|
const id = resolveReceptionId(param)
|
||||||
|
if (id === null) {
|
||||||
|
receptionStore.clearCurrent()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await receptionStore.loadReception(id)
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
const saveAndHold = async () => {
|
||||||
|
if (!receptionStore.current) {
|
||||||
|
await router.push('/')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await receptionStore.updateReception(receptionStore.current.id, {
|
||||||
|
currentStep: receptionStore.current.currentStep,
|
||||||
|
licensePlate: receptionStore.current.licensePlate,
|
||||||
|
receptionDate: receptionStore.current.receptionDate
|
||||||
|
})
|
||||||
|
await router.push('/')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
BIN
frontend/public/favicon.ico
Normal file
BIN
frontend/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
2
frontend/public/robots.txt
Normal file
2
frontend/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
User-Agent: *
|
||||||
|
Disallow:
|
||||||
38
frontend/services/auth.ts
Normal file
38
frontend/services/auth.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { useApi } from '~/composables/useApi'
|
||||||
|
import type { UserData } from '~/services/dto/user-data'
|
||||||
|
|
||||||
|
export async function getUsers() {
|
||||||
|
const api = useApi()
|
||||||
|
const data = await api.get<UserData[] | { 'hydra:member': UserData[] }>('users', {}, {
|
||||||
|
toastErrorKey: 'errors.auth.users'
|
||||||
|
})
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
return data['hydra:member'] ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCurrentUser() {
|
||||||
|
const api = useApi()
|
||||||
|
return api.get<UserData>('me', {}, {
|
||||||
|
toast: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function login(username: string, password: string) {
|
||||||
|
const api = useApi()
|
||||||
|
return api.post<{ token: string }>('login_check', { username, password }, {
|
||||||
|
toastErrorKey: 'errors.auth.login',
|
||||||
|
toastSuccessKey: 'success.auth.login'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function logout() {
|
||||||
|
const api = useApi()
|
||||||
|
return api.post<void>('logout', {}, {
|
||||||
|
toastErrorKey: 'errors.auth.logout',
|
||||||
|
toastSuccessKey: 'success.auth.logout',
|
||||||
|
redirect: 'manual'
|
||||||
|
})
|
||||||
|
}
|
||||||
16
frontend/services/dto/reception-data.ts
Normal file
16
frontend/services/dto/reception-data.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export interface ReceptionData {
|
||||||
|
id: number
|
||||||
|
licensePlate: string | null
|
||||||
|
weights?: WeightEntryData[] | null
|
||||||
|
receptionDate: string
|
||||||
|
currentStep: number
|
||||||
|
isValid: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WeightEntryData {
|
||||||
|
id?: number
|
||||||
|
type: 'gross' | 'tare'
|
||||||
|
dsd: number | null
|
||||||
|
weight: number | null
|
||||||
|
weighedAt: string | null
|
||||||
|
}
|
||||||
3
frontend/services/dto/user-data.ts
Normal file
3
frontend/services/dto/user-data.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export interface UserData {
|
||||||
|
username: string
|
||||||
|
}
|
||||||
5
frontend/services/dto/weight-data.ts
Normal file
5
frontend/services/dto/weight-data.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export interface WeightData {
|
||||||
|
weight: number | null
|
||||||
|
dsd: number | null
|
||||||
|
weighedAt: string | null
|
||||||
|
}
|
||||||
39
frontend/services/reception.ts
Normal file
39
frontend/services/reception.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import {useApi} from '~/composables/useApi'
|
||||||
|
import type {ReceptionData} from '~/services/dto/reception-data'
|
||||||
|
import type {WeightData} from '~/services/dto/weight-data'
|
||||||
|
|
||||||
|
export async function getReceptionList() {
|
||||||
|
const api = useApi()
|
||||||
|
return api.get<ReceptionData>(`receptions`, {}, {
|
||||||
|
toastErrorKey: 'errors.reception.list'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getReception(id: number) {
|
||||||
|
const api = useApi()
|
||||||
|
return api.get<ReceptionData>(`receptions/${id}`, {}, {
|
||||||
|
toastErrorKey: 'errors.reception.fetch'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createReception(payload: Partial<ReceptionData> = {}) {
|
||||||
|
const api = useApi()
|
||||||
|
return api.post<ReceptionData>('receptions', payload, {
|
||||||
|
toastErrorKey: 'errors.reception.create'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateReception(id: number, payload: Partial<ReceptionData>) {
|
||||||
|
const api = useApi()
|
||||||
|
return api.patch<ReceptionData>(`receptions/${id}`, payload, {
|
||||||
|
toastErrorKey: 'errors.reception.update',
|
||||||
|
toastSuccessKey: 'success.reception.update'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getWeight(): Promise<WeightData> {
|
||||||
|
const api = useApi()
|
||||||
|
return api.get<WeightData>('receptions/weigh', {}, {
|
||||||
|
toastErrorKey: 'errors.reception.weigh'
|
||||||
|
})
|
||||||
|
}
|
||||||
20
frontend/services/weight.ts
Normal file
20
frontend/services/weight.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { useApi } from '~/composables/useApi'
|
||||||
|
import type { WeightEntryData } from '~/services/dto/reception-data'
|
||||||
|
|
||||||
|
export type WeightPayload = {
|
||||||
|
reception: string
|
||||||
|
type: 'gross' | 'tare'
|
||||||
|
dsd: number | null
|
||||||
|
weight: number | null
|
||||||
|
weighedAt: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createWeight(payload: WeightPayload) {
|
||||||
|
const api = useApi()
|
||||||
|
return api.post<WeightEntryData>('weights', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateWeight(id: number, payload: Partial<WeightPayload>) {
|
||||||
|
const api = useApi()
|
||||||
|
return api.patch<WeightEntryData>(`weights/${id}`, payload)
|
||||||
|
}
|
||||||
58
frontend/stores/auth.ts
Normal file
58
frontend/stores/auth.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import type { UserData } from '~/services/dto/user-data'
|
||||||
|
import { getCurrentUser, login, logout } from '~/services/auth'
|
||||||
|
|
||||||
|
export const useAuthStore = defineStore('auth', {
|
||||||
|
state: () => ({
|
||||||
|
user: null as UserData | null,
|
||||||
|
isLoading: false,
|
||||||
|
checked: false
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
isAuthenticated: (state) => Boolean(state.user)
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
async ensureSession() {
|
||||||
|
if (this.checked) {
|
||||||
|
return this.user
|
||||||
|
}
|
||||||
|
|
||||||
|
this.checked = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const me = await getCurrentUser()
|
||||||
|
this.user = me
|
||||||
|
return me
|
||||||
|
} catch {
|
||||||
|
this.user = null
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async login(username: string, password: string) {
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
await login(username, password)
|
||||||
|
const me = await getCurrentUser()
|
||||||
|
this.user = me
|
||||||
|
this.checked = true
|
||||||
|
return me
|
||||||
|
} finally {
|
||||||
|
this.isLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async logout() {
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
await logout()
|
||||||
|
} catch {
|
||||||
|
// Ignore logout errors so we can still clear local auth state.
|
||||||
|
} finally {
|
||||||
|
this.user = null
|
||||||
|
this.checked = true
|
||||||
|
this.isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
59
frontend/stores/reception.ts
Normal file
59
frontend/stores/reception.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import type { ReceptionData } from '~/services/dto/reception-data'
|
||||||
|
import { createReception, getReception, updateReception } from '~/services/reception'
|
||||||
|
|
||||||
|
const isReceptionData = (value: unknown): value is ReceptionData => {
|
||||||
|
return Boolean(value && typeof value === 'object' && 'id' in value)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useReceptionStore = defineStore('reception', {
|
||||||
|
state: () => ({
|
||||||
|
current: null as ReceptionData | null,
|
||||||
|
isLoading: false
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
setCurrent(reception: ReceptionData | null) {
|
||||||
|
this.current = reception
|
||||||
|
},
|
||||||
|
clearCurrent() {
|
||||||
|
this.current = null
|
||||||
|
},
|
||||||
|
async loadReception(id: number) {
|
||||||
|
this.isLoading = true
|
||||||
|
const result = await getReception(id).finally(() => {
|
||||||
|
this.isLoading = false
|
||||||
|
})
|
||||||
|
if (!isReceptionData(result)) {
|
||||||
|
this.current = null
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.current = result
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
async createReception(payload: Partial<ReceptionData> = {}) {
|
||||||
|
this.isLoading = true
|
||||||
|
const result = await createReception(payload).finally(() => {
|
||||||
|
this.isLoading = false
|
||||||
|
})
|
||||||
|
if (!isReceptionData(result)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.current = result
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
async updateReception(id: number, payload: Partial<ReceptionData>) {
|
||||||
|
this.isLoading = true
|
||||||
|
const result = await updateReception(id, payload).finally(() => {
|
||||||
|
this.isLoading = false
|
||||||
|
})
|
||||||
|
if (!isReceptionData(result)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.current = result
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
22
frontend/tailwind.config.ts
Normal file
22
frontend/tailwind.config.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import type { Config } from 'tailwindcss'
|
||||||
|
|
||||||
|
export default <Partial<Config>>{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: {
|
||||||
|
50: '#f6f9ea',
|
||||||
|
100: '#eaf2cf',
|
||||||
|
200: '#d6e3a4',
|
||||||
|
300: '#c1d47a',
|
||||||
|
400: '#afc85a',
|
||||||
|
500: '#9ebb43',
|
||||||
|
600: '#7e9735',
|
||||||
|
700: '#607228',
|
||||||
|
800: '#414d1a',
|
||||||
|
900: '#24290d'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
frontend/tsconfig.json
Normal file
18
frontend/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
// https://nuxt.com/docs/guide/concepts/typescript
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./.nuxt/tsconfig.app.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./.nuxt/tsconfig.server.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./.nuxt/tsconfig.shared.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./.nuxt/tsconfig.node.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
17
frontend/utils/zod-errors.ts
Normal file
17
frontend/utils/zod-errors.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import type { ZodError } from 'zod'
|
||||||
|
|
||||||
|
export type FieldErrors<T extends Record<string, unknown>> = Partial<Record<keyof T, string>>
|
||||||
|
|
||||||
|
export const mapZodErrors = <T extends Record<string, unknown>>(error: ZodError<T>): FieldErrors<T> => {
|
||||||
|
const flattened = error.flatten().fieldErrors
|
||||||
|
const result: FieldErrors<T> = {}
|
||||||
|
|
||||||
|
for (const key in flattened) {
|
||||||
|
const message = flattened[key]?.[0]
|
||||||
|
if (message) {
|
||||||
|
result[key as keyof T] = message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
117
makefile
Normal file
117
makefile
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
# Permet d'utiliser un .env.docker.local pour override
|
||||||
|
ENV_DEFAULT = docker/.env.docker
|
||||||
|
ENV_LOCAL = docker/.env.docker.local
|
||||||
|
ENV_FILE := $(if $(wildcard $(ENV_LOCAL)),$(ENV_LOCAL),$(ENV_DEFAULT))
|
||||||
|
|
||||||
|
# Permet d'avoir les variables du fichier .env.docker.local
|
||||||
|
include $(ENV_DEFAULT)
|
||||||
|
-include $(ENV_LOCAL)
|
||||||
|
|
||||||
|
PHP_CONTAINER = php-$(DOCKER_APP_NAME)-fpm
|
||||||
|
SYMFONY_CONSOLE = $(EXEC_PHP) php bin/console
|
||||||
|
|
||||||
|
DOCKER_COMPOSE = docker compose --env-file $(ENV_FILE)
|
||||||
|
DOCKER = docker
|
||||||
|
|
||||||
|
EXEC_PHP = $(DOCKER) exec -t -u $(APP_USER) $(PHP_CONTAINER)
|
||||||
|
EXEC_PHP_CS_FIXER = $(EXEC_PHP) php vendor/bin/php-cs-fixer
|
||||||
|
EXEC_PHP_ROOT = $(DOCKER) exec -t -u root $(PHP_CONTAINER)
|
||||||
|
EXEC_PHP_INTERACTIVE = $(DOCKER) exec -it -u $(APP_USER) $(PHP_CONTAINER)
|
||||||
|
EXEC_PHP_INTERACTIVE_ROOT = $(DOCKER) exec -it -u root $(PHP_CONTAINER)
|
||||||
|
FILES =
|
||||||
|
|
||||||
|
#========================================================================================
|
||||||
|
|
||||||
|
env-init:
|
||||||
|
@mkdir -p docker
|
||||||
|
@cp --update=none $(ENV_DEFAULT) $(ENV_LOCAL)
|
||||||
|
|
||||||
|
# Lance le container
|
||||||
|
start: env-init
|
||||||
|
@echo "**** START CONTAINERS ****"
|
||||||
|
@cp --update=none docker/.env.docker docker/.env.docker.local
|
||||||
|
CURRENT_UID=$(shell id -u) CURRENT_GID=$(shell id -g) $(DOCKER_COMPOSE) up -d
|
||||||
|
|
||||||
|
# Éteint le container
|
||||||
|
stop:
|
||||||
|
$(DOCKER_COMPOSE) stop
|
||||||
|
|
||||||
|
restart: env-init
|
||||||
|
$(DOCKER_COMPOSE) down
|
||||||
|
CURRENT_UID=$(shell id -u) CURRENT_GID=$(shell id -g) $(DOCKER_COMPOSE) up -d
|
||||||
|
|
||||||
|
install: copy-git-hook composer-install cache-clear node-use build-nuxtJS migration-migrate
|
||||||
|
|
||||||
|
# Supprime tout est réinstalle tout (Attention ça supprime la bdd aussi)
|
||||||
|
reset: delete_built_dir remove_orphans build-without-cache start wait install
|
||||||
|
|
||||||
|
composer-install:
|
||||||
|
$(EXEC_PHP) composer install
|
||||||
|
$(SYMFONY_CONSOLE) lexik:jwt:generate-keypair --skip-if-exists
|
||||||
|
|
||||||
|
build-nuxtJS:
|
||||||
|
# $(EXEC_PHP) cp -n frontend/.env.dist frontend/.env.local
|
||||||
|
$(EXEC_PHP) sh -lc "cd frontend && npm install && npm run build:dist"
|
||||||
|
|
||||||
|
dev-nuxt:
|
||||||
|
$(EXEC_PHP) sh -c "cd frontend && npm run dev"
|
||||||
|
|
||||||
|
delete_built_dir:
|
||||||
|
CURRENT_UID=$(shell id -u) CURRENT_GID=$(shell id -g) $(DOCKER_COMPOSE) up -d
|
||||||
|
$(DOCKER) exec -u root $(PHP_CONTAINER) rm -rf vendor/
|
||||||
|
$(DOCKER) exec -u root $(PHP_CONTAINER) rm -rf frontend/node_modules
|
||||||
|
|
||||||
|
remove_orphans:
|
||||||
|
$(DOCKER_COMPOSE) kill
|
||||||
|
$(DOCKER_COMPOSE) down --volumes --remove-orphans
|
||||||
|
|
||||||
|
build-without-cache:
|
||||||
|
$(DOCKER_COMPOSE) build \
|
||||||
|
--build-arg="DOCKER_PHP_VERSION=$(DOCKER_PHP_VERSION)" \
|
||||||
|
--build-arg="DOCKER_NODE_VERSION=$(DOCKER_NODE_VERSION)" \
|
||||||
|
--build-arg="CURRENT_UID=$(shell id -u)" \
|
||||||
|
--build-arg="CURRENT_GID=$(shell id -g)" \
|
||||||
|
--no-cache
|
||||||
|
|
||||||
|
migration-migrate:
|
||||||
|
$(SYMFONY_CONSOLE) bin/console doctrine:migrations:migrate --no-interaction
|
||||||
|
|
||||||
|
# Attention, supprime votre bdd local
|
||||||
|
db-reset:
|
||||||
|
$(DOCKER_COMPOSE) down -v
|
||||||
|
$(DOCKER_COMPOSE) up -d
|
||||||
|
$(MAKE) wait
|
||||||
|
$(SYMFONY_CONSOLE) doctrine:database:create --if-not-exists
|
||||||
|
$(MAKE) migration-migrate
|
||||||
|
|
||||||
|
# Restart la bdd
|
||||||
|
db-restart:
|
||||||
|
$(DOCKER_COMPOSE) down
|
||||||
|
$(DOCKER_COMPOSE) up -d
|
||||||
|
|
||||||
|
cache-clear:
|
||||||
|
$(SYMFONY_CONSOLE) cache:clear
|
||||||
|
|
||||||
|
copy-git-hook:
|
||||||
|
$(EXEC_PHP) cp pre-commit .git/hooks/
|
||||||
|
$(EXEC_PHP) cp commit-msg .git/hooks/
|
||||||
|
$(EXEC_PHP) chmod a+x .git/hooks/pre-commit
|
||||||
|
$(EXEC_PHP) chmod a+x .git/hooks/commit-msg
|
||||||
|
|
||||||
|
shell:
|
||||||
|
$(EXEC_PHP_INTERACTIVE) bash
|
||||||
|
|
||||||
|
# Force la version node
|
||||||
|
node-use:
|
||||||
|
bash -lc 'source "$$HOME/.nvm/nvm.sh" && nvm install && nvm use'
|
||||||
|
|
||||||
|
# Utilisé par le pre-commit pour fix les fichiers modifiés
|
||||||
|
php-cs-fixer-allow-risky:
|
||||||
|
@echo "Fixing files: $(FILES)"
|
||||||
|
$(EXEC_PHP_CS_FIXER) fix --config=.php-cs-fixer.dist.php --allow-risky=yes $(FILES)
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(EXEC_PHP) php -d memory_limit="512M" vendor/bin/phpunit $(FILES)
|
||||||
|
|
||||||
|
wait:
|
||||||
|
sleep 10
|
||||||
0
migrations/.gitignore
vendored
Normal file
0
migrations/.gitignore
vendored
Normal file
26
migrations/Version20260112000100.php
Normal file
26
migrations/Version20260112000100.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20260112000100 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Create reception table';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('CREATE TABLE reception (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, dsd INT DEFAULT NULL, weight DOUBLE PRECISION DEFAULT NULL, weighed_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('DROP TABLE reception');
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user