diff --git a/.github/workflows/Check_lint.yml b/.github/workflows/Check_lint.yml index 852afe30..837a303e 100644 --- a/.github/workflows/Check_lint.yml +++ b/.github/workflows/Check_lint.yml @@ -1,33 +1,20 @@ -name: Check lint +name: Run linters on: pull_request: branches: - - master + - production - main push: branches: - - master + - production - main jobs: - black: - name: Check black has been run + linter: + name: run pre-commit runs-on: ubuntu-latest steps: - - name: Setup git - uses: actions/checkout@v3 - - - name: Setup python - uses: actions/setup-python@v4 - with: - python-version: 3.9 - - - name: Install python dependencies - run: | - python -m pip install --upgrade pip - pip install -r web/requirements.app.txt - pip install -r web/requirements.dev.txt - - - name: Check black has nothing to do - run: black . --check + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/Check_local_run.yml b/.github/workflows/Check_local_run.yml index 457f1e8a..7fd1e674 100644 --- a/.github/workflows/Check_local_run.yml +++ b/.github/workflows/Check_local_run.yml @@ -3,11 +3,11 @@ name: Check local run on: pull_request: branches: - - master + - production - main push: branches: - - master + - production - main jobs: @@ -24,6 +24,14 @@ jobs: test-local: name: Run test locally runs-on: ubuntu-latest + strategy: + matrix: + python: + - '3.11' + - '3.10' + - '3.9' + - '3.8' + steps: - name: Setup git uses: actions/checkout@v3 @@ -31,7 +39,7 @@ jobs: - name: Setup python uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: ${{ matrix.python }} - name: Install python dependencies run: | @@ -39,7 +47,7 @@ jobs: pip install -r web/requirements.app.txt pip install -r web/requirements.dev.txt - name: Check local environment tests - run: pytest --envfile web.env.example + run: pytest healthy-containers: name: Check containers run diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml new file mode 100644 index 00000000..f1157cd1 --- /dev/null +++ b/.github/workflows/Documentation.yml @@ -0,0 +1,37 @@ +--- +name: Documentation +on: + push: + branches: + - production + - main + pull_request: + branches: + - production + - main +jobs: + tests: + name: ${{ matrix.python }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + with: + python-version: 3.11 + + - uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: pip|${{ hashFiles('web/requirements.doc.txt') }} + + - name: Install python dependencies + run: | + python -m pip install --upgrade pip + pip install -r web/requirements.doc.txt + + - name: Run unit tests + run: sphinx-build documentation build/sphinx/html diff --git a/.github/workflows/Test_coverage.yml b/.github/workflows/Test_coverage.yml index d9cca6ff..743f47ac 100644 --- a/.github/workflows/Test_coverage.yml +++ b/.github/workflows/Test_coverage.yml @@ -3,11 +3,11 @@ name: Check coverage on: pull_request: branches: - - master + - production - main push: branches: - - master + - production - main jobs: @@ -18,41 +18,25 @@ jobs: - name: Setup git uses: actions/checkout@v3 - - name: Setup python - uses: actions/setup-python@v4 - with: - python-version: 3.9 - - - name: Switch to main branch + - name: Get the git branch uses: actions/checkout@v3 with: - ref: ${{ github.event.repository.default_branch }} + ref: main # TODO: dynamically get the branch against which the PR will be merged? - - name: Install previous python dependencies - run: | - python -m pip install --upgrade pip - pip install -r web/requirements.app.txt - pip install -r web/requirements.dev.txt - - - name: Get previous coverage - id: get_coverage - run: | - coverage run -m pytest --envfile web.env.example - coverage json - export PERCENT_COVERED=$(python -c "import json;print(json.load(open('coverage.json'))['totals']['percent_covered'])") - echo "percent_covered=$PERCENT_COVERED" >> $GITHUB_OUTPUT - - - name: Switch to branch to merge - uses: actions/checkout@v3 + - name: Setup python + uses: actions/setup-python@v4 with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha }} + python-version: 3.11 - - name: Install new python dependencies + - name: Install python dependencies run: | python -m pip install --upgrade pip pip install -r web/requirements.app.txt pip install -r web/requirements.dev.txt + pip install diff-cover + + - name: Run unit tests with coverage + run: pytest --cov --cov-report=xml - - name: Check that coverage at least equals to main coverage - run: pytest --envfile web.env.example --cov --cov-fail-under=${{ steps.get_coverage.outputs.percent_covered }} + - name: Check that the edited lines are all covered + run: diff-cover coverage.xml --fail-under=100 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c20878f0..d3fbd651 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,13 @@ --- repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: 'v0.3.4' + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: fix-byte-order-marker - id: trailing-whitespace @@ -9,22 +15,18 @@ repos: - id: end-of-file-fixer exclude: "\\.svg$|\\.map$|\\.min\\.css$|\\.min\\.js$|\\.po$|\\.pot$" - id: check-toml - - repo: https://github.com/asottile/reorder_python_imports - rev: v3.10.0 + - repo: https://github.com/pycqa/isort + rev: "5.13.2" hooks: - - id: reorder-python-imports - args: ["--application-directories", "canaille"] - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 'v0.0.284' + - id: isort + name: isort (python) + args: ["--force-single-line-imports", "--line-length", "120"] + - repo: https://github.com/PyCQA/docformatter + rev: v1.7.5 hooks: - - id: ruff - args: [--fix, --exit-non-zero-on-fix] + - id: docformatter - repo: https://github.com/asottile/pyupgrade - rev: v3.10.1 + rev: v3.15.2 hooks: - id: pyupgrade args: ["--py38-plus"] - - repo: https://github.com/psf/black - rev: 23.7.0 - hooks: - - id: black diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..d4a2c57d --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,32 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.12" + # You can also specify other tool versions: + # nodejs: "19" + # rust: "1.64" + # golang: "1.19" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: documentation/conf.py + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: web/requirements.doc.txt diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2d8ab49d..aee9ae02 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,32 +4,6 @@ Bienvenue sur B3Desk, et merci de prendre le temps de vous intéresser à la con Vous trouverez ici les quelques indications qui permettront à B3Desk de grandir et de se développer que nous avons jugées intéressantes. N'hésitez pas à faire des suggestions ! -**Sommaire** - -[Lancer B3Desk localement](#lancer-b3desk-localement) - -- [Docker](#Docker) -- [Environnement de développement](#environnement-de-développement) - - [Installation locale](#installation-locale) - - [Poetry](#Poetry) - -[Soumettre des modifications](#soumettre-des-modifications) - -- [Prérequis](#Prérequis) - - [Validité du code](#validité-du-code) - - [Conventions de code](#conventions-de-code) - - [Intégration continue GitHub](#intégration-continue-github) -- [Pull requests](#pull-requests) - - [Workflow](#Workflow) - - [Commits](#Commits) -- [Cas particuliers](#cas-particuliers) - - [Migration des données](#migration-des-données) - - [Traductions](#Traductions) - -[Mise en forme des pages](#mise-en-forme-des-pages) - -[Liens utiles](#liens-utiles) - ## Lancer B3Desk localement ### Docker @@ -43,7 +17,7 @@ Pour lancer l'application et coller au plus proche des conditions de production, - broker : le broker redis qui maintient une liste de tâches dans laquelle vient se servir le worker - tokenmock : un mock qui vient reproduire les conditions de prod de distribution d'un token pour la communication entre B3Desk et l'instance Nextcloud de l'utilisateur -Vous trouverez plus d'informations concernant la persistance des données pour certains de ces conteneurs dans la documentation [./documentation/dockerPersistence.md](./documentation/dockerPersistence.md). +Vous trouverez plus d'informations concernant la persistance des données pour certains de ces conteneurs dans {doc}`la documentation `. 1. Configurer l'application web en créant le fichier `web.env` à partir du fichier `web.env.example`. Ce nouveau fichier est précisé dans `docker-compose.override.yml` qui vient surcharger le fichier `docker-compose.yml` lorsqu'aucun fichier n'est précisé dans la commande `docker compose`. Pour que les liens vers le service BBB fonctionne, il est nécessaire de configurer les variables d'environnement BIGBLUEBUTTON_ENDPOINT et BIGBLUEBUTTON_SECRET. @@ -114,6 +88,11 @@ ou bien dans l'environnement Poetry avec pytest (dont certains settings sont dan pytest ``` +Pour tester le code sur les différentes versions de python en cours, et prévenir des incompatibilités avec des versions futures, utilisez : +```bash +tox +``` + #### Conventions de code Le code python doit suivre les conventions de la PEP 8. Dans les dépendance de développement du projet, on retrouve `flake8` et `black`. @@ -137,7 +116,7 @@ Ainsi, lorsque vous ferez un commit, black sera automatiquement lancé et format GitHub Actions est utilisé afin de s'assurer que le code reste propre et fonctionnel et que les conteneurs peuvent communiquer entre eux pour s'assurer que l'embarquement de nouveaux développeur·euses sur de nouvelles machines est possible. -Cette intégration continue fait tourner des conteneurs Docker, les [fichiers de requirements](#poetry) doivent donc être maintenus à jour. +Cette intégration continue fait tourner des conteneurs Docker, les fichiers de requirements doivent donc être maintenus à jour. La CI GitHub est utilisée pour : - lancer les tests dans un environnement local (sans conteneur docker) : pour permettre aux développeurs d'être indépendant de docker sur leurs machines @@ -156,7 +135,7 @@ Le projet est organisé de la façon suivante : - Les modification sont faites sur une `branche` de votre **fork**. - Lorsque le développement est prêt, une *pull request* vers la branche `main` du projet d'*origine* est réalisée -- Une fois ce [développement validé](./documentation/pullRequestValidation.md), les mainteneurs du projet vont *merger* ces modifications sur `main` +- Une fois ce {doc}`développement validé <../maintainers/pullRequestValidation>`, les mainteneurs du projet vont *merger* ces modifications sur `main` - Lorsque suffisamment de modifications sont faites dans `main`, les mainteneurs peuvent décider de créer une nouvelle version du projet - La branche `main` est *mergée* dans la branche `production`, référente pour les déploiements du projet B3Desk @@ -187,15 +166,13 @@ En production, les migrations sont réalisées automatiquement par `run_webserve #### Traductions -Vous trouverez toutes les informations sur la traduction dans cette [documentation](./documentation/translation.md). +Vous trouverez toutes les informations sur la traduction dans cette {doc}`documentation `. ## Mise en forme des pages -Le service utilise le style du Système de Design de l'État (dsfr) : - -https://gouvfr.atlassian.net/wiki/spaces/DB/overview?homepageId=145359476 +Le service utilise le style du [Système de Design de l'État (dsfr)](https://gouvfr.atlassian.net/wiki/spaces/DB/overview?homepageId=145359476) ## Liens utiles -- https://docs.bigbluebutton.org/dev/api.html -- https://mconf.github.io/api-mate/ +- [docs.bigbluebutton.org/dev/api.html](https://docs.bigbluebutton.org/dev/api.html) +- [mconf.github.io/api-mate](https://mconf.github.io/api-mate/) diff --git a/Makefile b/Makefile index f36ea072..c53cf217 100644 --- a/Makefile +++ b/Makefile @@ -4,17 +4,23 @@ install-dev: # Install dependencies for local development usage - poetry env use 3.8 ; poetry install --with dev ; poetry shell + poetry install --with dev --with doc; poetry shell pre-commit install +export-dependencies: export-base-dependencies export-dev-dependencies export-doc-dependencies + export-base-dependencies: # Update requirements file for web service - poetry export --without-hashes --with task-management -o web/requirements.app.txt + poetry export --without-hashes -o web/requirements.app.txt export-dev-dependencies: # Update requirements file for development environment used in GitHub Actions poetry export --without-hashes --only dev -o web/requirements.dev.txt +export-doc-dependencies: + # Update requirements file for development environment used in GitHub Actions + poetry export --without-hashes --with doc -o web/requirements.doc.txt + translation-extract: # Extract messages to be translated with: pybabel extract --mapping-file web/translations/babel.cfg --output-file web/translations/messages.pot --keywords lazy_gettext web @@ -26,3 +32,6 @@ translation-update: translation-compile: # Compile translation catalogs with: pybabel compile --directory web/translations + +doc: + sphinx-build documentation build/sphinx/html diff --git a/README.md b/README.md index e38dbcf5..9622db59 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Frontal OIDC de gestion simplifiée des visioconférences BigBlueButton. -[![Check coverage](https://github.com/numerique-gouv/b3desk/actions/workflows/Test_coverage.yml/badge.svg)](https://github.com/numerique-gouv/b3desk/actions/workflows/Test_coverage.yml) [![Check lint](https://github.com/numerique-gouv/b3desk/actions/workflows/Check_lint.yml/badge.svg)](https://github.com/numerique-gouv/b3desk/actions/workflows/Check_lint.yml) [![Check local run](https://github.com/numerique-gouv/b3desk/actions/workflows/Check_local_run.yml/badge.svg)](https://github.com/numerique-gouv/b3desk/actions/workflows/Check_local_run.yml) +[![Documentation Status](https://readthedocs.org/projects/b3desk/badge/?version=latest)](https://b3desk.readthedocs.io/fr/latest/?badge=latest) [![Check coverage](https://github.com/numerique-gouv/b3desk/actions/workflows/Test_coverage.yml/badge.svg)](https://github.com/numerique-gouv/b3desk/actions/workflows/Test_coverage.yml) [![Check lint](https://github.com/numerique-gouv/b3desk/actions/workflows/Check_lint.yml/badge.svg)](https://github.com/numerique-gouv/b3desk/actions/workflows/Check_lint.yml) [![Check local run](https://github.com/numerique-gouv/b3desk/actions/workflows/Check_local_run.yml/badge.svg)](https://github.com/numerique-gouv/b3desk/actions/workflows/Check_local_run.yml) B3Desk permet de créer et configurer des visioconférences et de garder ces configurations. @@ -13,32 +13,14 @@ B3Desk permet donc de paramétrer les options offertes par BBB : le titre, le n Son usage réside dans le fait que toute cette configuration est enregistrée et peut être réutilisée pour la prochaine visio. -## Déployer B3Desk en production avec Docker +## Documentation -Pour déployer uniquement l'application b3desk en production, seuls les conteneurs **web, broker, worker** sont requis, les autres peuvent être disponibles sur d'autres serveurs. +La documentation pour les mainteneurs et les développeurs est déployée sur [b3desk.readthedocs.io](https://b3desk.readthedocs.io), et peut être construite localement avec `make doc`. -La commande ci-après permet de déployer en mode production ou préproduction : -``` -docker compose -f docker-compose.yml -f docker-compose.prod.yml up -# ou -# docker compose -f docker-compose.yml -f docker-compose.preprod.yml up -``` -## Installer B3Desk dans un environnement de développement local +## Développement et contributions -Vous pouvez suivre la documentation dans [./CONTRIBUTING.md](./CONTRIBUTING.md) pour installer localement le projet et le tester. - -## Publier une nouvelle version - -- Mettre un tag sur le commit, portant le numéro de la version, avec `git tag vX.Y.Z` -- Pousser le commit ET le tag `git push origin main --tags` -- Se rendre sur [la page github de publication de version](https://github.com/numerique-gouv/b3desk/releases/new) -- Choisir le tag récemment ajouté, remplir les informations, publier la version. - -Attention, pour que le numéro de version s'affiche correctement sur la version déployée, -il est nécessaire que le projet soit déployé avec git (c.à.d. qu'il y ait un dépôt git -qui soit déployé), et aussi que le commit qui soit déployé soit directement marqué par -un tag git. Dans les autres cas, c'est le numéro de commit qui sera affiché. +Vous pouvez suivre la documentation dans [CONTRIBUTING.md](./CONTRIBUTING.md) pour installer localement le projet et le tester. ## Licence diff --git a/docker-compose.override.yml b/docker-compose.override.yml index ac5516f0..066cff90 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -107,5 +107,5 @@ services: env_file: - ${ENV_FILE_OVERRIDE-web.env} volumes: - - ./web/flaskr:/opt/bbb-visio/flaskr + - ./web/b3desk:/opt/bbb-visio/b3desk - ./web/tests:/opt/bbb-visio/tests diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 5dce963a..b1a3aa47 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -16,7 +16,7 @@ services: - ./nextcloud/nextcloudcheck.sh:/var/tmp/nextcloudcheck.sh healthcheck: test: "bash /var/tmp/nextcloudcheck.sh" - start_period: 30s + start_period: 60s interval: 5s worker: diff --git a/docker-compose.yml b/docker-compose.yml index ba0240a4..2f88c370 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,9 +12,11 @@ services: dockerfile: Dockerfile # env_file: # - web.env + environment: + - FLASK_APP=b3desk volumes: - ./web/logs:/var/log - - ./web/flaskr:/opt/bbb-visio/flaskr + - ./web/b3desk:/opt/bbb-visio/b3desk - ./web/instance:/opt/bbb-visio/instance - ./web/migrations:/opt/bbb-visio/migrations - ./web/translations:/opt/bbb-visio/translations @@ -34,7 +36,7 @@ services: environment: - APP=tasks.celery volumes: - - ./web/flaskr:/usr/src/app + - ./web/b3desk:/usr/src/app command: celery --app tasks.celery worker --loglevel=info broker: diff --git a/web/flaskr/common/__init__.py b/documentation/__init__.py similarity index 100% rename from web/flaskr/common/__init__.py rename to documentation/__init__.py diff --git a/documentation/_static/b3desk-500.png b/documentation/_static/b3desk-500.png new file mode 100644 index 00000000..cb3a8394 Binary files /dev/null and b/documentation/_static/b3desk-500.png differ diff --git a/documentation/_static/ci.png b/documentation/_static/ci.png new file mode 100644 index 00000000..8d52023b Binary files /dev/null and b/documentation/_static/ci.png differ diff --git a/documentation/_static/keycloak-audience.png b/documentation/_static/keycloak-audience.png new file mode 100644 index 00000000..cc53fb39 Binary files /dev/null and b/documentation/_static/keycloak-audience.png differ diff --git a/documentation/conf.py b/documentation/conf.py new file mode 100644 index 00000000..35824429 --- /dev/null +++ b/documentation/conf.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +import datetime +import os +import sys + +sys.path.insert(0, os.path.abspath("../web")) + +import b3desk + +# -- General configuration ------------------------------------------------ + + +extensions = [ + "myst_parser", + "sphinx.ext.autodoc", + "sphinx.ext.autosectionlabel", + "sphinx.ext.doctest", + "sphinx.ext.graphviz", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "sphinxcontrib.autodoc_pydantic", +] + +templates_path = ["_templates"] +source_suffix = { + ".rst": "restructuredtext", + ".md": "markdown", +} +master_doc = "index" +project = "b3desk" +year = datetime.datetime.now().strftime("%Y") +copyright = f"{year}, Ministère de l'Éducation Nationale" +author = "Ministère de l'Éducation Nationale" + +release = b3desk.__version__ +version = "%s.%s" % tuple(map(int, release.split(".")[:2])) +language = "fr" +exclude_patterns = [] +pygments_style = "sphinx" +todo_include_todos = False + +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), +} + +# -- Options for HTML output ---------------------------------------------- + +html_theme = "sphinx_rtd_theme" +html_static_path = [] + + +# -- Options for HTMLHelp output ------------------------------------------ + +htmlhelp_basename = "b3deskdoc" +html_logo = "" + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = {} +latex_documents = [ + ( + master_doc, + "b3desk.tex", + "B3Desk Documentation", + "Ministère de l’Éducation Nationale", + "manual", + ) +] + +# -- Options for manual page output --------------------------------------- + +man_pages = [(master_doc, "b3desk", "B3Desk Documentation", [author], 1)] + +# -- Options for Texinfo output ------------------------------------------- + +texinfo_documents = [ + ( + master_doc, + "b3desk", + "B3Desk Documentation", + author, + "B3Desk", + "BBB frontend by the French Ministry of Education.", + "Miscellaneous", + ) +] + +# -- Options for autosectionlabel ----------------------------------------- + +autosectionlabel_prefix_document = True + +# -- Options for autodo_pydantic_settings ------------------------------------------- + +autodoc_pydantic_model_show_json = False +autodoc_pydantic_model_show_config_summary = False +autodoc_pydantic_model_show_config_summary = False +autodoc_pydantic_model_show_validator_summary = False +autodoc_pydantic_model_show_validator_members = False +autodoc_pydantic_model_show_field_summary = False +autodoc_pydantic_field_list_validators = False diff --git a/documentation/developers/api.md b/documentation/developers/api.md new file mode 100644 index 00000000..94b03654 --- /dev/null +++ b/documentation/developers/api.md @@ -0,0 +1,63 @@ +# API publique + +## Points d'accès + +Une API publique est disponible sur `/api/meetings`. Cette API est utilisée par les greffons Thunderbird et Outlook. + +Les réponses sont au format json sous la forme suivante : + +```json +{ + "meetings": [ + { + "attendee_url": "https://example.tld/meeting/signin/1234/creator/5678/hash/27955e8c3a16ecadbb3cf61df7806a04ce6fd18c", + "moderator_url": "https://example.tld/meeting/signin/1234/creator/5678/hash/3e73643801d5013d389f8fc610e258aba38e597d", + "name": "Mon Séminaire" + } + ] +} +``` + +## Authentification + +L'authentification à l'API se fait en passant un jeton OIDC émis par le serveur d'identifié configuré dans `OIDC_ISSUER`. + +### Tests + +On peut tester le bon fonctionnement de l'API comme ceci (*en renseignant au préalable la variable `$TOKEN`*). + +```bash +curl -s -H "Authorization:Bearer $TOKEN" https://example.tld/api/meetings +``` + +### Problèmes de connexion + +#### Jeton manquant + +Lorsque le jeton d'identification n'a pas été fourni dans la requête, l'API retourne des codes d'erreur HTTP 401. + +#### Jeton expiré + +Lorsque le jeton est expiré, l'API retourne des codes d'erreur HTTP 403. + +#### Mauvaise audience du jeton + +Lorsque l'audience du jeton est incorrecte, l'API retourne des codes d'erreur 403. +Dans les faits il faut s'assurer que le paramètre `aud` du jeton contient bien l'ID client OIDC de l'application, définie dans le paramètre `OIDC_CLIENT_ID` de l'application, et prenant par défaut la valeur `bbb-vision`. +On peut vérifier l'audience d'un token avec des outils tels que [jwt.io](https://jwt.io). + +Par défaut, keycloak ne remplit pas l'audience du jeton avec l'ID client. +Il est nécessaire d'effectuer une configuration dans la console d'aministration de keycloak comme celle-ci (c'est un exemple, d'autres sont probablement possibles) : + +1. Se rendre sur la console d'administration de keycloak +2. Se rendre dans le menu « Clients » +3. Sélectionner le client « bbb-visio » +4. Se rendre dans l'onglet « Mappers » +5. Cliquer sur le bouton « Create » +6. Remplir (par exemple) le formulaire comme ceci: + - Name: bbb-visio-audience + - Mapper Type: audience + - Included Custom Audience: bbb-visio + + ![keycloak](../_static/keycloak-audience.png) +7. Générer un nouveau token et vérifier qu'il contient bien la valeur `bbb-vision` dans le paramètre `aud`. diff --git a/documentation/developers/ci.md b/documentation/developers/ci.md new file mode 100644 index 00000000..c8efcc3b --- /dev/null +++ b/documentation/developers/ci.md @@ -0,0 +1,46 @@ +# Intégration Continue + +Quand l’intégration continue (CI) s’est correctement déroulée, l’interface de github affiche cet encart : + +![ci](../_static/ci.png) + +Les différentes étapes de l’intégration continue + +## Tests dans un virtualenv + +GitHub Actions fait passer la suite de test sur un virtualenv. + +Pour passer cette étape, il faut que `pytest` soit vert sur votre environnement local. + +## Tests dans un conteneur + +GitHub Actions fait passer la suite de test dans un conteneur Docker. + +Pour passer cette étape, il faut que la commande `docker-compose run --rm tests` soit verte sur votre machine. + +## Healthcheck sur les conteneurs + +GitHub Actions lance tous les conteneurs requis pour un environnement de développement local et fait un healthcheck sur chacun. Certains vont vérifier que le service fonctionne, d'autres on besoin de valider que les ocnteneurs peuvent communiquer entre eux. + +Cela permet d'assurer que le code reste fonctionnel lorsqu'on lance le projet de zéro sur une nouvelle machine, et qu'il est donc possible d'embarquer de nouvelles·aux contributeur·rice·s. + +## Couverture de code croissante + +GitHub Actions va vérifier que la couverture de test de la pull request est correcte. + +Toutes les lignes de code modifiées lors de la PR doivent être couvertes. + +Cela permet d'augmenter au fur et à mesure ce que les tests vont couvrir et donc d'assurer de plus en plus l'état fonctionnel du projet. + +Pour être sûr de passer cette étape, il suffit d'ajouter des tests **au moins** sur le code que vous modifiez. + +## Formattage du code + +GitHub Actions va vérifier que le code a bien été formatté : + +- Les espaces de fin de ligne sont supprimés. +- Les imports python sont triés +- Le code est formatté à l’aide de `black` +- Quelques vérifications statiques sont effectuées avec `ruff` + +À l’avenir, `mypy` pourrait être utilisé. diff --git a/documentation/developers/contributing.rst b/documentation/developers/contributing.rst new file mode 100644 index 00000000..7a661a30 --- /dev/null +++ b/documentation/developers/contributing.rst @@ -0,0 +1,2 @@ +.. include:: ../../CONTRIBUTING.md + :parser: myst_parser.sphinx_ diff --git a/documentation/dockerPersistence.md b/documentation/developers/dockerPersistence.md similarity index 100% rename from documentation/dockerPersistence.md rename to documentation/developers/dockerPersistence.md diff --git a/documentation/developers/index.rst b/documentation/developers/index.rst new file mode 100644 index 00000000..30d019da --- /dev/null +++ b/documentation/developers/index.rst @@ -0,0 +1,14 @@ +Développement +============= + +Cette documentation est à destination des développeurs. + +.. toctree:: + :maxdepth: 2 + + api + contributing + ci + dockerPersistence + translation + meetingFiles diff --git a/documentation/meetingFiles.md b/documentation/developers/meetingFiles.md similarity index 75% rename from documentation/meetingFiles.md rename to documentation/developers/meetingFiles.md index 85847492..22cafe94 100644 --- a/documentation/meetingFiles.md +++ b/documentation/developers/meetingFiles.md @@ -1,29 +1,29 @@ -# Associer un fichier à un salon BBB dans B3desk +# Associer un fichier à un salon BBB Il est possible d'associer un fichier à un salon ## Association des fichiers avant le lancement du salon L'association des fichiers avant le lancement se fait via l'URL formattée -https://B3DESK/meeting/files/MEETINGID +`https://B3DESK/meeting/files/MEETINGID` Si la connexion Nextcloud est fonctionnelle, 3 boutons s'affichent, sinon, seulement l'association par URL s'affiche. ### Nextcloud -L'association par Nextcloud se fait grâce aux donnéees user.nc_login, user.nc_token et user.nc_locator pour avoir une connexion webdav. -Un client webdav est initié et, une fois les fichiers sélectionnés, permet de lister et récupérer le chemin complet d'accès au fichier, stocké dans meeting_files.nc_path. +L'association par Nextcloud se fait grâce aux donnéees `user.nc_login`, `user.nc_token` et `user.nc_locator` pour avoir une connexion webdav. +Un client webdav est initié et, une fois les fichiers sélectionnés, permet de lister et récupérer le chemin complet d'accès au fichier, stocké dans `meeting_files.nc_path`. ### URL -L'association par URL est simpliste et consiste en l'écriture de l'URL directement dans la table meeting_files.url. +L'association par URL est simpliste et consiste en l'écriture de l'URL directement dans la table `meeting_files.url`. ### Téléversement L'association par téléversement se fait en cliquer-glisser grâce au module JS 'dropzone', disponible localement et versionné dans le code source, ce fichier est donc une dépendance qu'il faut penser à mettre à jour régulièrement. -Une fois le fichier déposé, l'upload commence, et se fait par morceaux ( chunk ). -Le fichier est reconstitué sur le serveur B3desk dans le dossier renseigné à la variable d'environnement TMP_UPLOAD ( disponible dans web.env ). +Une fois le fichier déposé, l'upload commence, et se fait par morceaux (chunk). +Le fichier est reconstitué sur le serveur B3desk dans le dossier renseigné à la variable d'environnement `TMP_UPLOAD` (disponible dans `web.env`). -Une fois le fichier entièrement reçu, le client WEBDAV ( connecté à Nextcloud donc ) réenvoie ce fichier dans le Nextcloud, dans le dossier créé à la racine de la connexion, nommé visio-agent. +Une fois le fichier entièrement reçu, le client WEBDAV (connecté à Nextcloud donc) réenvoie ce fichier dans le Nextcloud, dans le dossier créé à la racine de la connexion, nommé visio-agent. Lorsque le téléversement se déroule sans accroc, le fichier stocké sur le serveur B3desk est ensuite supprimé. **En revanche, pour les cas où l'upload pose un problème quelconque, on se retrouve avec un dossier qui ne fait 'que' grossir, il faut donc le purger régulièrement.** -Actuellement, un cron d'exemple est proposé : web/misc/delete_uploaded_files.cron. +Actuellement, un cron d'exemple est proposé : `web/misc/delete_uploaded_files.cron`. ### Gestion de l'identité @@ -32,9 +32,9 @@ La récupération des éléments de connexion à Nextcloud se fait comme suit : 1. la personne arrive sur B3desk 2. la personne se connecte via le keycloak 3. par le keycloak, B3desk reçoit l'information 'preferred_username', qui **FAIT LE LIEN D'IDENTITÉ AVEC LE LOGIN NEXTCLOUD** -4. B3desk fait ensuite une requête aux variable d'environnement NC_LOGIN_API_URL avec la clé NC_LOGIN_API_KEY. L'équivalent dans l'environnement de développement local est le service 'tokenmock'. -5. L'appli 'tokenmock', elle, lance à son tour une requête au nextcloud associé au 'preferred_username' qu'on lui demande (dans le code actuel, tout est envoyé vers le même docker, mais l'appli 'tokenmock', en étant entre B3desk et Nextcloud, permet d'avoir XXX instances nextcloud derrière elle) -6. L'instance Nextcloud associée au 'preferred_username' demandé reçoit une requête HTTP sur l'url '/apps/sessiontoken/token' ( ou un endpoint qui appelle l'appli 'sessiontoken' ). +4. B3desk fait ensuite une requête aux variable d'environnement `NC_LOGIN_API_URL` avec la clé `NC_LOGIN_API_KEY`. L'équivalent dans l'environnement de développement local est le service 'tokenmock'. +5. L'appli 'tokenmock', elle, lance à son tour une requête au nextcloud associé au `preferred_username` qu'on lui demande (dans le code actuel, tout est envoyé vers le même docker, mais l'appli 'tokenmock', en étant entre B3desk et Nextcloud, permet d'avoir XXX instances nextcloud derrière elle) +6. L'instance Nextcloud associée au 'preferred_username' demandé reçoit une requête HTTP sur l'url `/apps/sessiontoken/token` (ou un endpoint qui appelle l'appli 'sessiontoken'). 7. L'appli sessiontoken crée un token d'accès et les infos redescendent jusqu'à B3desk. Pour vérifier que la communication entre chacun des conteneurs fonctionne correctement, vous pouvez suivre les étapes suivantes : @@ -70,8 +70,8 @@ Il se déroule alors la chose suivante : 1. si le salon est déjà ouvert, la personne est juste redirigée vers le salon en cours 2. si le salon doit être créé, il est créé ( eh ouais ), il se passe alors 2 choses au niveau des fichiers associés - - Le fichier noté comme étant celui par défaut est DIRECTEMENT associé au salon, via un fichier XML inséré dans l'appel API 'create' ( doc de référence : https://docs.bigbluebutton.org/development/api#pre-upload-slides ) - - Les autres fichiers sont poussés dans une job queue via celery ( qui communique avec B3desk via redis ). Une requête au BBB va ensuite être lancée sur l'endpoint insertDocument ( doc de référence : https://docs.bigbluebutton.org/development/api#insertdocument ) + - Le fichier noté comme étant celui par défaut est DIRECTEMENT associé au salon, via un fichier XML inséré dans l'appel API 'create' ([doc de référence](https://docs.bigbluebutton.org/development/api#pre-upload-slides)). + - Les autres fichiers sont poussés dans une job queue via celery ( qui communique avec B3desk via redis ). Une requête au BBB va ensuite être lancée sur l'endpoint insertDocument ([doc de référence](https://docs.bigbluebutton.org/development/api#insertdocument)). Le résultat obtenu est une association des fichiers fonctionnelle, un salon qui se lance rapidement, et des fichiers 'secondaires' qui s'uploadent ensuite en background sans bloquer le déroulé du cours. Des notifications dans le salon apparaissent à chaque ajout de fichier. @@ -81,8 +81,8 @@ Il se déroule alors la chose suivante : Une fois le salon lancé et le cours en cours ( eh ouais ), il est encore possible d'associer des fichiers depuis nextcloud. Les infos pour cela sont passées lors de la création du salon, via les paramètres `presentationUploadExternalUrl` et `presentationUploadExternalDescription` -( doc de référence : https://docs.bigbluebutton.org/development/api#upload-slides-from-external-application-to-a-live-bigbluebutton-session ). -L'URL fournie en l'occurence pour B3desk est /meeting/files//insertDocuments -La description fournie est modifiable via la var d'env "EXTERNAL_UPLOAD_DESCRIPTION" dans le fichier web.env +([doc de référence](https://docs.bigbluebutton.org/development/api#upload-slides-from-external-application-to-a-live-bigbluebutton-session)). +L'URL fournie en l'occurence pour B3desk est `/meeting/files//insertDocuments`. +La description fournie est modifiable via la var d'env `EXTERNAL_UPLOAD_DESCRIPTION` dans le fichier `web.env`. **Remarque : sur l'interface d'ajout de fichiers par l'extérieur, la personne qui s'y rend doit avoir une connexion Nextcloud valide.** diff --git a/documentation/translation.md b/documentation/developers/translation.md similarity index 96% rename from documentation/translation.md rename to documentation/developers/translation.md index 4f165803..ee118657 100644 --- a/documentation/translation.md +++ b/documentation/developers/translation.md @@ -1,4 +1,3 @@ - # Traductions ## Ajouter du texte à traduire @@ -25,7 +24,7 @@ Cette commande va mettre à jour les catalogues existants avec de nouveaux messa ## Traduire du texte -Les fichiers à traduire sont `web/flaskr/translations/*/LC_MESSAGES/messages.po`. +Les fichiers à traduire sont `web/b3desk/translations/*/LC_MESSAGES/messages.po`. Lors de la traduction, il ne faut pas traduire les motifs du type `%(...)s` mais simplement mettre l'équivalent traduit. Par exemple, pour une traduction vers l'anglais : diff --git a/documentation/index.rst b/documentation/index.rst new file mode 100644 index 00000000..b09cade1 --- /dev/null +++ b/documentation/index.rst @@ -0,0 +1,20 @@ +B3Desk +====== + +Frontend Big Blue Button du Ministère de l’Éducation Nationale. + +Table des matières +------------------ + +.. toctree:: + :maxdepth: 2 + + maintainers/index + developers/index + +Index et tables +--------------- + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/documentation/maintainers/codeReview.md b/documentation/maintainers/codeReview.md new file mode 100644 index 00000000..1367444f --- /dev/null +++ b/documentation/maintainers/codeReview.md @@ -0,0 +1,35 @@ +# Revue de code + +Les correctifs et évolutions nécessitant une validation de l’équipe produit font l’objet de *pull request (PR)* sur le dépôt GitHub. + +Le *périmètre technique* est la responsabilité de l’équipe de développement. +Elle est donc autonome pour valider les modifications de code touchant à la qualité, aux réusinages etc. + +Le *périmètre fonctionnel* est la responsabilité de l’équipe produit. +C’est donc à elle de valider les modifications touchant aux fonctionnalités, et certaines corrections, en suivant le processus suivant. + +## 1. S’assurer que la CI est bien verte + +Quand l’intégration continue (CI) s’est correctement déroulée, l’interface de github affiche cet encart : + +![ci](../_static/ci.png) + +Ne pas valider un PR qui ne passerait pas la batterie de tests automatiques de la CI. +Plus de détails sur l’intégration continue sont disponibles dans la {ref}`section dédiée `. + +## 2. Déployer la PR dans un environnement de test + +Passées ces étapes, les mainteneurs font une validation manuelle des développements réalisés. + +Sur un serveur de préprod, il faut récupérer la PR en suivant les instructions de la {ref}`section déploiement ` + +## 3. Tests fonctionnels + +Sur l’instance de test, vérifier que les corrections ou fonctionnalités correspondent aux attentes, et ne créent pas d’effets de bord indésirables. + +S’il y a des choses à améliorer, commenter dans le fil de discussion de la PR sur github, puis reprendre à l’étape 1 lorsque des corrections sont appportées. +Il suffira d’effectuer un `git pull origin pr` pour mettre le code à jour. + +## 4. Fusionner. + +Enfin, lorsque tout semble bon, fusionner la Pull Request sur Github. diff --git a/documentation/maintainers/deployment.md b/documentation/maintainers/deployment.md new file mode 100644 index 00000000..59ca48f5 --- /dev/null +++ b/documentation/maintainers/deployment.md @@ -0,0 +1,95 @@ +# Déploiement + +## Branches et tags + +Sur le [dépôt git](https://github.com/numerique-gouv/b3desk) les branches et tags suivants sont utilisés : + +- `main` est la branche de développement. + Elle sert à recevoir les PR de fonctionnalités et les corrections de bugs importantes. + Elle est considérée non stable et ne doit pas être utilisée dans les envirorrements de production. +- `production` est la branche stable. Elle sert à recevoir les hotfixes. + Elle est considérée stable et utilisable sur les environnements de production. + Elle correspond toujours au dernier tag publié. +- Différents tags `vXX.YY.ZZ` marquent les jalons du projet. + Chaque tag est considéré stable et peut être utilisé sur les environnements de production. + + +## Téléchargement du code source + +### Primo-installation + +Pour récupérer le code source la premier fois, utiliser `git clone` : + +```bash +git clone https://github.com/numerique-gouv/b3desk.git +git switch production +``` + +La commande `git clone` n’est à utiliser qu’une seule fois lors d’une primo-installation. +Les mise à jour du code se feront avec d’autres commandes git. + +### Version stable + +On peut utiliser `git checkout` pour passer sur une branche ou tag stable : + +```bash +# pour charger la dernière version stable +git switch production +git pull origin production + +# pour charger un jalon spécifique +git fetch origin --tags +git checkout v1.0.0 +``` + +### Version de développement + +Afin de valider des PR provenant de github, on peut charger du code instable pour pouvoir le tester ensuite. Dans les commandes suivantes remplacer `` par le numéro de la PR : + +```bash +# Récupération de la PR +git fetch origin pull//head:pr + +# Changement vers la branche de la PR +git switch pr +``` + +Puis, si de nouvelles modifications ont été ajoutées à la PR on peut mettre à jour le code avec : + +```bash +git switch pr +git pull origin pr +``` + +## Configuration + +### B3Desk + +La configuration se fait dans un fichier nommé `web.env`. +Lors d’une primo-installation, créer le fichier de configuration à partir de `web.env.example` : + +```bash +cp web.env.example web.env +``` + +Adapter les valeurs du fichiers de configuration à partir des indications du chapitre sur la {ref}`Configuration de B3Desk`. + +### Serveur web + +Paramétrer le chargement des pages d’erreurs statique sur le serveur web frontal à partir des indications du chapitre sur la {ref}`Configuration de Nginx`. + +Faire attention à ne pas mettre en cache les pages dynamiques de B3Desk. + +## Lancement des conteneurs + +Enfin lorsque la bonne branche est chargée et que l’application est correctement configurée, on peut lancer les conteneurs avec les commandes suivantes : + +```bash +# En production +docker compose -f docker-compose.yml -f docker-compose.prod.yml up + +# En pré-production +docker compose -f docker-compose.yml -f docker-compose.preprod.yml up +``` + +Le fichier `run_webserver.sh` est lancé par le `Dockerfile` et migre la base de données automatiquement. Ces docker-compose de production et preproduction peuvent donc être utilisés pour une primo-installation, ou sur une instance existante. diff --git a/documentation/maintainers/index.rst b/documentation/maintainers/index.rst new file mode 100644 index 00000000..0e592886 --- /dev/null +++ b/documentation/maintainers/index.rst @@ -0,0 +1,12 @@ +Maintenance et administration +============================= + +Cette partie de la documentation est à destination des personnes qui déploient et administrent des instances de B3Desk. + +.. toctree:: + :maxdepth: 2 + + codeReview + versioning + deployment + settings diff --git a/documentation/maintainers/settings.rst b/documentation/maintainers/settings.rst new file mode 100644 index 00000000..af569a71 --- /dev/null +++ b/documentation/maintainers/settings.rst @@ -0,0 +1,21 @@ +Configuration +############# + +B3Desk +====== + +L’ensemble des paramètres décrits sur cette page peuvent être passées en variables d’environnement à l’application B3Desk. + +.. autopydantic_model:: b3desk.settings.MainSettings + +Nginx +===== + +B3Desk fournit des pages d'erreurs statiques qui peuvent être affichées en cas de problème. +Pour utiliser ces pages statiques, on peut utiliser le paramètre `error_page `_ de Nginx:: + + error_page 500 502 503 504 /static/errors/custom_50x.html; + +Avec cette configuration, dès que le service est indisponible, Nginx servira cette page d'erreur: + +.. image:: ../_static/b3desk-500.png diff --git a/documentation/maintainers/versioning.md b/documentation/maintainers/versioning.md new file mode 100644 index 00000000..82dae414 --- /dev/null +++ b/documentation/maintainers/versioning.md @@ -0,0 +1,16 @@ +# Publication + +La branche de référence pour les releases est `production`. C'est ici qu'on retrouve les différentes versions installées sur les instances. À ces releases correspondent des tags git. + +Pour publier une nouvelle version : +- S'assurer d'être sur la branche `production` +- Mettre à jour le numéro de version dans `pyproject.toml` et dans `web/b3desk/__init__.py` +- Mettre un tag sur le commit, portant le numéro de la version, avec `git tag vX.Y.Z` +- Pousser le commit ET le tag `git push origin production --follow-tags` +- Se rendre sur [la page github de publication de version](https://github.com/numerique-gouv/b3desk/releases/new) +- Choisir le tag récemment ajouté, remplir les informations, publier la version. + +Attention, pour que le numéro de version s'affiche correctement sur la version déployée, +il est nécessaire que le projet soit déployé avec git (c.à.d. qu'il y ait un dépôt git +qui soit déployé), et aussi que le commit qui soit déployé soit directement marqué par +un tag git. Dans les autres cas, c'est le numéro de commit qui sera affiché. diff --git a/documentation/pullRequestValidation.md b/documentation/pullRequestValidation.md deleted file mode 100644 index ae81521d..00000000 --- a/documentation/pullRequestValidation.md +++ /dev/null @@ -1,54 +0,0 @@ -# Validation de Pull Request - -Pour qu'une pull request soit validée par les mainteneurs, elle doit passer un certain nombre d'étapes : - -## CI : Tests dans un virtualenv - -GitHub Actions fait passer la suite de test sur un virtualenv. - -Pour passer cette étape, il faut que `pytest` soit vert sur votre environnement local. - -## CI : Tests dans un conteneur - -GitHub Actions fait passer la suite de test dans un conteneur Docker. - -Pour passer cette étape, il faut que la commande `docker-compose run --rm tests` soit verte sur votre machine. - -## CI : Healthcheck sur les conteneurs - -GitHub Actions lance tous les conteneurs requis pour un environnement de développement local et fait un healthcheck sur chacun. Certains vont vérifier que le service fonctionne, d'autres on besoin de valider que les ocnteneurs peuvent communiquer entre eux. - -Cela permet d'assurer que le code reste fonctionnel lorsqu'on lance le projet de zéro sur une nouvelle machine, et qu'il est donc possible d'embarquer de nouvelles·aux contributeur·rice·s. - -## CI : Couverture de code croissante - -GitHub Actions va vérifier que la couverture de test de la pull request est au moins égale à celle du dernier commit. - -Cela permet d'augmenter au fur et à mesure ce que les tests vont couvrir et donc d'assurer de plus en plus l'état fonctionnel du projet. - -Pour être sûr de passer cette étape, il suffit d'ajouter des tests **au moins** sur le code que vous modifiez. - -## CI : Formattage du code - -GitHub Actions va vérifier que le code a bien été formatté. Pour le moment, seul `black` est exécuté, mais à l'avenir, `flake8` ou encore `mypy` pourraient être requis. Le même genre de décisions pourait être appliquée au front. - -## Tests en préprod - -Passé ces étapes, les mainteneurs font une validation manuelle des développements réalisés. - -Sur un serveur de préprod, il faut récupérer la *pull request* en question : -```bash -git fetch origin pull/ID/head:BRANCH_NAME -``` -en remplaçant `ID` par l'**id** de la pull request et `BRANCH_NAME` par le nom de la **branche** sur laquelle ont été réalisés les modifications, celle du *fork*. - -Il faut ensuite passer sur cette branche puis lancer la préprod : -```bash -git switch BRANCH_NAME -# Switched to a new branch 'BRANCH_NAME' -docker compose -f docker-compose.yml -f docker-compose.preprod.yml up -``` - -À partir de là, l'état fonctionnel du projet peut être testé manuellement ainsi que les modifications apportées par la PR. - -Lorsqu'assez de modifications suffisamment cohérentes ont été ajoutées sur la branche `main`, les mainteneurs peuvent merger celle-ci dans la branche `production` qui sert de référence pour les déploiements. Un tag avec un numéro de version ainsi qu'un changelog peut également être ajouté. diff --git a/nextcloud/apache2-sessiontoken b/nextcloud/apache2-sessiontoken index 090dec1b..64e0f24c 100755 --- a/nextcloud/apache2-sessiontoken +++ b/nextcloud/apache2-sessiontoken @@ -2,6 +2,10 @@ # deploy the sessiontoken app: git clone https://gitlab.octopuce.fr/octopuce-public/nextcloud-sessiontoken.git /var/www/html/apps/sessiontoken +cd /var/www/html/apps/sessiontoken +git config --global --add safe.directory '*' +git checkout 7cf4ff5eea1f16820aa20c3995c3a663e74a9eb7 +cd /var/www/html chown -R www-data: /var/www/html/apps/sessiontoken # ## install the sessiontoken key in /var/www/html/config/config.php diff --git a/poetry.lock b/poetry.lock index 36eec00e..47d7c741 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,14 +1,40 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. + +[[package]] +name = "aiosmtpd" +version = "1.4.5" +description = "aiosmtpd - asyncio based SMTP server" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiosmtpd-1.4.5-py3-none-any.whl", hash = "sha256:a196922f1903e54c4d37c53415b7613056d39e2b1e8249f324b9ee7a439be0f1"}, + {file = "aiosmtpd-1.4.5.tar.gz", hash = "sha256:78d7b14f859ad0e6de252b47f9cf1ca6f1c82a8b0f10a9e39bec7e915a6aa5fe"}, +] + +[package.dependencies] +atpublic = "*" +attrs = "*" + +[[package]] +name = "alabaster" +version = "0.7.13" +description = "A configurable sidebar-enabled Sphinx theme" +optional = false +python-versions = ">=3.6" +files = [ + {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, + {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, +] [[package]] name = "alembic" -version = "1.11.3" +version = "1.13.1" description = "A database migration tool for SQLAlchemy." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "alembic-1.11.3-py3-none-any.whl", hash = "sha256:d6c96c2482740592777c400550a523bc7a9aada4e210cae2e733354ddae6f6f8"}, - {file = "alembic-1.11.3.tar.gz", hash = "sha256:3db4ce81a9072e1b5aa44c2d202add24553182672a12daf21608d6f62a8f9cf9"}, + {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, + {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, ] [package.dependencies] @@ -19,31 +45,31 @@ SQLAlchemy = ">=1.3.0" typing-extensions = ">=4" [package.extras] -tz = ["python-dateutil"] +tz = ["backports.zoneinfo"] [[package]] name = "amqp" -version = "5.1.1" +version = "5.2.0" description = "Low-level AMQP client for Python (fork of amqplib)." optional = false python-versions = ">=3.6" files = [ - {file = "amqp-5.1.1-py3-none-any.whl", hash = "sha256:6f0956d2c23d8fa6e7691934d8c3930eadb44972cbbd1a7ae3a520f735d43359"}, - {file = "amqp-5.1.1.tar.gz", hash = "sha256:2c1b13fecc0893e946c65cbd5f36427861cffa4ea2201d8f6fca22e2a373b5e2"}, + {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"}, + {file = "amqp-5.2.0.tar.gz", hash = "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd"}, ] [package.dependencies] -vine = ">=5.0.0" +vine = ">=5.0.0,<6.0.0" [[package]] name = "annotated-types" -version = "0.5.0" +version = "0.6.0" description = "Reusable constraint types to use with typing.Annotated" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, - {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, ] [package.dependencies] @@ -60,20 +86,90 @@ files = [ {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, ] +[[package]] +name = "atpublic" +version = "4.1.0" +description = "Keep all y'all's __all__'s in sync" +optional = false +python-versions = ">=3.8" +files = [ + {file = "atpublic-4.1.0-py3-none-any.whl", hash = "sha256:df90de1162b1a941ee486f484691dc7c33123ee638ea5d6ca604061306e0fdde"}, + {file = "atpublic-4.1.0.tar.gz", hash = "sha256:d1c8cd931af7461f6d18bc6063383e8654d9e9ef19d58ee6dc01e8515bbf55df"}, +] + +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "authlib" +version = "1.3.0" +description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Authlib-1.3.0-py2.py3-none-any.whl", hash = "sha256:9637e4de1fb498310a56900b3e2043a206b03cb11c05422014b0302cbc814be3"}, + {file = "Authlib-1.3.0.tar.gz", hash = "sha256:959ea62a5b7b5123c5059758296122b57cd2585ae2ed1c0622c21b371ffdae06"}, +] + +[package.dependencies] +cryptography = "*" + +[[package]] +name = "autodoc-pydantic" +version = "2.1.0" +description = "Seamlessly integrate pydantic models in your Sphinx documentation." +optional = false +python-versions = ">=3.8,<4.0.0" +files = [ + {file = "autodoc_pydantic-2.1.0-py3-none-any.whl", hash = "sha256:9f1f82ee3667589dfa08b21697be8bbd80b15110e838cd765bb1bf3ce1b0ea8f"}, + {file = "autodoc_pydantic-2.1.0.tar.gz", hash = "sha256:3cf1b973e2f5ff0fbbe9b951c11827b5e32d3409e238f7f5782359426ab8d360"}, +] + +[package.dependencies] +importlib-metadata = {version = ">1", markers = "python_version <= \"3.8\""} +pydantic = ">=2.0,<3.0.0" +pydantic-settings = ">=2.0,<3.0.0" +Sphinx = ">=4.0" + +[package.extras] +dev = ["coverage (>=7,<8)", "flake8 (>=3,<4)", "pytest (>=7,<8)", "sphinx-copybutton (>=0.4,<0.5)", "sphinx-rtd-theme (>=1.0,<2.0)", "sphinx-tabs (>=3,<4)", "sphinxcontrib-mermaid (>=0.7,<0.8)", "tox (>=3,<4)"] +docs = ["sphinx-copybutton (>=0.4,<0.5)", "sphinx-rtd-theme (>=1.0,<2.0)", "sphinx-tabs (>=3,<4)", "sphinxcontrib-mermaid (>=0.7,<0.8)"] +erdantic = ["erdantic (>=0.6,<0.7)"] +test = ["coverage (>=7,<8)", "pytest (>=7,<8)"] + [[package]] name = "babel" -version = "2.12.1" +version = "2.14.0" description = "Internationalization utilities" optional = false python-versions = ">=3.7" files = [ - {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, - {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, + {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, + {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, ] [package.dependencies] pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + [[package]] name = "backports-zoneinfo" version = "0.2.1" @@ -107,88 +203,45 @@ tzdata = ["tzdata"] [[package]] name = "beautifulsoup4" -version = "4.12.2" +version = "4.12.3" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, - {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, ] [package.dependencies] soupsieve = ">1.2" [package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] [[package]] name = "billiard" -version = "3.6.4.0" +version = "4.2.0" description = "Python multiprocessing fork with improvements and bugfixes" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"}, - {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, + {file = "billiard-4.2.0-py3-none-any.whl", hash = "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d"}, + {file = "billiard-4.2.0.tar.gz", hash = "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c"}, ] -[[package]] -name = "black" -version = "23.7.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, - {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, - {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, - {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, - {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, - {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, - {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, - {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, - {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, - {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, - {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "blinker" -version = "1.6.2" +version = "1.7.0" description = "Fast, simple object-to-object and broadcast signaling" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "blinker-1.6.2-py3-none-any.whl", hash = "sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0"}, - {file = "blinker-1.6.2.tar.gz", hash = "sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213"}, + {file = "blinker-1.7.0-py3-none-any.whl", hash = "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9"}, + {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"}, ] [[package]] @@ -202,142 +255,159 @@ files = [ {file = "cachelib-0.9.0.tar.gz", hash = "sha256:38222cc7c1b79a23606de5c2607f4925779e37cdcea1c2ad21b8bae94b5425a5"}, ] +[[package]] +name = "canaille" +version = "0.0.45" +description = "Lightweight identity and autorization management software" +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "canaille-0.0.45-cp311-cp311-manylinux_2_39_x86_64.whl", hash = "sha256:135d74840257cb6a38e5af3462dcb18a96eaa5150b4d715ce7fe62a761362c88"}, + {file = "canaille-0.0.45.tar.gz", hash = "sha256:6d34e0ede5a91ca49c66723db25c687f08a578e970d85c6f36169fa34da213f2"}, +] + +[package.dependencies] +authlib = {version = ">=1.2.1,<2.0.0", optional = true, markers = "extra == \"oidc\" or extra == \"all\""} +flask = ">=3.0.0,<4.0.0" +flask-wtf = ">=1.2.1,<2.0.0" +pydantic-settings = ">=2.0.3,<3.0.0" +sphinx-enum-extend = ">=0.1.3,<0.2.0" +wtforms = ">=3.1.1,<4.0.0" + +[package.extras] +all = ["authlib (>=1.2.1,<2.0.0)", "email_validator (>=2.0.0,<3.0.0)", "flask-babel (>=4.0.0,<5.0.0)", "flask-themer (>=2.0.0,<3.0.0)", "passlib (>=1.7.4,<2.0.0)", "pycountry (>=22.1.10)", "python-ldap (>=3.4.0,<4.0.0)", "pytz (>=2022.7)", "sentry-sdk[flask] (<2)", "sqlalchemy (>=2.0.23,<3.0.0)", "sqlalchemy-json (>=0.7.0,<0.8.0)", "sqlalchemy-utils (>=0.41.1,<0.42.0)", "toml (>=0.10.0,<0.11.0)"] +front = ["email_validator (>=2.0.0,<3.0.0)", "flask-babel (>=4.0.0,<5.0.0)", "flask-themer (>=2.0.0,<3.0.0)", "pycountry (>=22.1.10)", "pytz (>=2022.7)", "toml (>=0.10.0,<0.11.0)"] +ldap = ["python-ldap (>=3.4.0,<4.0.0)"] +oidc = ["authlib (>=1.2.1,<2.0.0)"] +sentry = ["sentry-sdk[flask] (<2)"] +sql = ["passlib (>=1.7.4,<2.0.0)", "sqlalchemy (>=2.0.23,<3.0.0)", "sqlalchemy-json (>=0.7.0,<0.8.0)", "sqlalchemy-utils (>=0.41.1,<0.42.0)"] + [[package]] name = "celery" -version = "5.2.7" +version = "5.3.6" description = "Distributed Task Queue." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "celery-5.2.7-py3-none-any.whl", hash = "sha256:138420c020cd58d6707e6257b6beda91fd39af7afde5d36c6334d175302c0e14"}, - {file = "celery-5.2.7.tar.gz", hash = "sha256:fafbd82934d30f8a004f81e8f7a062e31413a23d444be8ee3326553915958c6d"}, + {file = "celery-5.3.6-py3-none-any.whl", hash = "sha256:9da4ea0118d232ce97dff5ed4974587fb1c0ff5c10042eb15278487cdd27d1af"}, + {file = "celery-5.3.6.tar.gz", hash = "sha256:870cc71d737c0200c397290d730344cc991d13a057534353d124c9380267aab9"}, ] [package.dependencies] -billiard = ">=3.6.4.0,<4.0" -click = ">=8.0.3,<9.0" -click-didyoumean = ">=0.0.3" +"backports.zoneinfo" = {version = ">=0.2.1", markers = "python_version < \"3.9\""} +billiard = ">=4.2.0,<5.0" +click = ">=8.1.2,<9.0" +click-didyoumean = ">=0.3.0" click-plugins = ">=1.1.1" click-repl = ">=0.2.0" -kombu = ">=5.2.3,<6.0" -pytz = ">=2021.3" -vine = ">=5.0.0,<6.0" +kombu = ">=5.3.4,<6.0" +python-dateutil = ">=2.8.2" +tzdata = ">=2022.7" +vine = ">=5.1.0,<6.0" [package.extras] -arangodb = ["pyArango (>=1.3.2)"] -auth = ["cryptography"] -azureblockblob = ["azure-storage-blob (==12.9.0)"] +arangodb = ["pyArango (>=2.0.2)"] +auth = ["cryptography (==41.0.5)"] +azureblockblob = ["azure-storage-blob (>=12.15.0)"] brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"] -cassandra = ["cassandra-driver (<3.21.0)"] -consul = ["python-consul2"] -cosmosdbsql = ["pydocumentdb (==2.3.2)"] +cassandra = ["cassandra-driver (>=3.25.0,<4)"] +consul = ["python-consul2 (==0.1.5)"] +cosmosdbsql = ["pydocumentdb (==2.3.5)"] couchbase = ["couchbase (>=3.0.0)"] -couchdb = ["pycouchdb"] -django = ["Django (>=1.11)"] -dynamodb = ["boto3 (>=1.9.178)"] -elasticsearch = ["elasticsearch"] +couchdb = ["pycouchdb (==1.14.2)"] +django = ["Django (>=2.2.28)"] +dynamodb = ["boto3 (>=1.26.143)"] +elasticsearch = ["elastic-transport (<=8.10.0)", "elasticsearch (<=8.11.0)"] eventlet = ["eventlet (>=0.32.0)"] gevent = ["gevent (>=1.5.0)"] -librabbitmq = ["librabbitmq (>=1.5.0)"] -memcache = ["pylibmc"] -mongodb = ["pymongo[srv] (>=3.11.1)"] -msgpack = ["msgpack"] -pymemcache = ["python-memcached"] -pyro = ["pyro4"] -pytest = ["pytest-celery"] -redis = ["redis (>=3.4.1,!=4.0.0,!=4.0.1)"] -s3 = ["boto3 (>=1.9.125)"] +librabbitmq = ["librabbitmq (>=2.0.0)"] +memcache = ["pylibmc (==1.6.3)"] +mongodb = ["pymongo[srv] (>=4.0.2)"] +msgpack = ["msgpack (==1.0.7)"] +pymemcache = ["python-memcached (==1.59)"] +pyro = ["pyro4 (==4.82)"] +pytest = ["pytest-celery (==0.0.0)"] +redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"] +s3 = ["boto3 (>=1.26.143)"] slmq = ["softlayer-messaging (>=1.0.3)"] -solar = ["ephem"] -sqlalchemy = ["sqlalchemy"] -sqs = ["kombu[sqs]"] +solar = ["ephem (==4.1.5)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.0)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"] yaml = ["PyYAML (>=3.10)"] zookeeper = ["kazoo (>=1.3.1)"] -zstd = ["zstandard"] +zstd = ["zstandard (==0.22.0)"] [[package]] name = "certifi" -version = "2023.7.22" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] name = "cffi" -version = "1.15.1" +version = "1.16.0" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] [package.dependencies] @@ -356,86 +426,101 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, - {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] @@ -454,13 +539,13 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "click-didyoumean" -version = "0.3.0" +version = "0.3.1" description = "Enables git-like *did-you-mean* feature in click" optional = false -python-versions = ">=3.6.2,<4.0.0" +python-versions = ">=3.6.2" files = [ - {file = "click-didyoumean-0.3.0.tar.gz", hash = "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"}, - {file = "click_didyoumean-0.3.0-py3-none-any.whl", hash = "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667"}, + {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, + {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, ] [package.dependencies] @@ -514,63 +599,63 @@ files = [ [[package]] name = "coverage" -version = "7.3.0" +version = "7.4.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5"}, - {file = "coverage-7.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51"}, - {file = "coverage-7.3.0-cp310-cp310-win32.whl", hash = "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527"}, - {file = "coverage-7.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1"}, - {file = "coverage-7.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f"}, - {file = "coverage-7.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f"}, - {file = "coverage-7.3.0-cp311-cp311-win32.whl", hash = "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482"}, - {file = "coverage-7.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70"}, - {file = "coverage-7.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b"}, - {file = "coverage-7.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b"}, - {file = "coverage-7.3.0-cp312-cp312-win32.whl", hash = "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321"}, - {file = "coverage-7.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479"}, - {file = "coverage-7.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1"}, - {file = "coverage-7.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985"}, - {file = "coverage-7.3.0-cp38-cp38-win32.whl", hash = "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9"}, - {file = "coverage-7.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543"}, - {file = "coverage-7.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba"}, - {file = "coverage-7.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54"}, - {file = "coverage-7.3.0-cp39-cp39-win32.whl", hash = "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3"}, - {file = "coverage-7.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e"}, - {file = "coverage-7.3.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0"}, - {file = "coverage-7.3.0.tar.gz", hash = "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, + {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, + {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, + {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, + {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, + {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, + {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, + {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, + {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, + {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, + {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, + {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, + {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, ] [package.dependencies] @@ -581,49 +666,69 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "41.0.3" +version = "42.0.5" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507"}, - {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922"}, - {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81"}, - {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd"}, - {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47"}, - {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116"}, - {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c"}, - {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae"}, - {file = "cryptography-41.0.3-cp37-abi3-win32.whl", hash = "sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306"}, - {file = "cryptography-41.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574"}, - {file = "cryptography-41.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087"}, - {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858"}, - {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906"}, - {file = "cryptography-41.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e"}, - {file = "cryptography-41.0.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd"}, - {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207"}, - {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84"}, - {file = "cryptography-41.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7"}, - {file = "cryptography-41.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d"}, - {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de"}, - {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1"}, - {file = "cryptography-41.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4"}, - {file = "cryptography-41.0.3.tar.gz", hash = "sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34"}, -] - -[package.dependencies] -cffi = ">=1.12" + {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16"}, + {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec"}, + {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb"}, + {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4"}, + {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278"}, + {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7"}, + {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee"}, + {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1"}, + {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d"}, + {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da"}, + {file = "cryptography-42.0.5-cp37-abi3-win32.whl", hash = "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74"}, + {file = "cryptography-42.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940"}, + {file = "cryptography-42.0.5-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8"}, + {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1"}, + {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e"}, + {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc"}, + {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a"}, + {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7"}, + {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922"}, + {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc"}, + {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30"}, + {file = "cryptography-42.0.5-cp39-abi3-win32.whl", hash = "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413"}, + {file = "cryptography-42.0.5-cp39-abi3-win_amd64.whl", hash = "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400"}, + {file = "cryptography-42.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8"}, + {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2"}, + {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c"}, + {file = "cryptography-42.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576"}, + {file = "cryptography-42.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6"}, + {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e"}, + {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac"}, + {file = "cryptography-42.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd"}, + {file = "cryptography-42.0.5.tar.gz", hash = "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1"}, +] + +[package.dependencies] +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] nox = ["nox"] -pep8test = ["black", "check-sdist", "mypy", "ruff"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] +[[package]] +name = "cssselect" +version = "1.2.0" +description = "cssselect parses CSS3 Selectors and translates them to XPath 1.0" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cssselect-1.2.0-py2.py3-none-any.whl", hash = "sha256:da1885f0c10b60c03ed5eccbb6b68d6eff248d91976fcde348f395d54c9fd35e"}, + {file = "cssselect-1.2.0.tar.gz", hash = "sha256:666b19839cfaddb9ce9d36bfe4c969132c647b92fc9088c4e23f786b30f1b3dc"}, +] + [[package]] name = "defusedxml" version = "0.7.1" @@ -637,43 +742,81 @@ files = [ [[package]] name = "distlib" -version = "0.3.7" +version = "0.3.8" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, - {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + +[[package]] +name = "docutils" +version = "0.20.1" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, + {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, +] + +[[package]] +name = "enum-extend" +version = "0.1.1" +description = "Enum base classes that support enum comparsion and auto numbering with doc strings" +optional = false +python-versions = ">=3.4.0" +files = [ + {file = "enum-extend-0.1.1.tar.gz", hash = "sha256:943208b2e62535e1a649945ee8dceab4576473a85cbb740ff84b4821492161b1"}, + {file = "enum_extend-0.1.1-py3-none-any.whl", hash = "sha256:a6bd4b09e1539d144d433ecf7c7d94def45b8852e5e494b2c31faf618d6a5a17"}, ] [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "faker" +version = "24.4.0" +description = "Faker is a Python package that generates fake data for you." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Faker-24.4.0-py3-none-any.whl", hash = "sha256:998c29ee7d64429bd59204abffa9ba11f784fb26c7b9df4def78d1a70feb36a7"}, + {file = "Faker-24.4.0.tar.gz", hash = "sha256:a5ddccbe97ab691fad6bd8036c31f5697cfaa550e62e000078d1935fa8a7ec2e"}, +] + +[package.dependencies] +python-dateutil = ">=2.4" +typing-extensions = {version = ">=3.10.0.1", markers = "python_version <= \"3.8\""} + [[package]] name = "filelock" -version = "3.12.2" +version = "3.13.3" description = "A platform independent file lock." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.13.3-py3-none-any.whl", hash = "sha256:5ffa845303983e7a0b7ae17636509bc97997d58afeafa72fb141a17b152284cb"}, + {file = "filelock-3.13.3.tar.gz", hash = "sha256:a79895a25bbefdf55d1a2a0a80968f7dbb28edcd6d4234a0afb3f37ecde4b546"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "filetype" @@ -688,37 +831,38 @@ files = [ [[package]] name = "flake8" -version = "6.1.0" +version = "7.0.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" files = [ - {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, - {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, + {file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"}, + {file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"}, ] [package.dependencies] mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.1.0,<3.2.0" +pyflakes = ">=3.2.0,<3.3.0" [[package]] name = "flask" -version = "2.2.5" +version = "3.0.2" description = "A simple framework for building complex web applications." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Flask-2.2.5-py3-none-any.whl", hash = "sha256:58107ed83443e86067e41eff4631b058178191a355886f8e479e347fa1285fdf"}, - {file = "Flask-2.2.5.tar.gz", hash = "sha256:edee9b0a7ff26621bd5a8c10ff484ae28737a2410d99b0bb9a6850c7fb977aa0"}, + {file = "flask-3.0.2-py3-none-any.whl", hash = "sha256:3232e0e9c850d781933cf0207523d1ece087eb8d87b23777ae38456e2fbe7c6e"}, + {file = "flask-3.0.2.tar.gz", hash = "sha256:822c03f4b799204250a7ee84b1eddc40665395333973dfb9deebfe425fefcb7d"}, ] [package.dependencies] -click = ">=8.0" +blinker = ">=1.6.2" +click = ">=8.1.3" importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""} -itsdangerous = ">=2.0" -Jinja2 = ">=3.0" -Werkzeug = ">=2.2.2" +itsdangerous = ">=2.1.2" +Jinja2 = ">=3.1.2" +Werkzeug = ">=3.0.0" [package.extras] async = ["asgiref (>=3.2)"] @@ -726,64 +870,61 @@ dotenv = ["python-dotenv"] [[package]] name = "flask-babel" -version = "2.0.0" -description = "Adds i18n/l10n support to Flask applications" +version = "4.0.0" +description = "Adds i18n/l10n support for Flask applications." optional = false -python-versions = "*" +python-versions = ">=3.8,<4.0" files = [ - {file = "Flask-Babel-2.0.0.tar.gz", hash = "sha256:f9faf45cdb2e1a32ea2ec14403587d4295108f35017a7821a2b1acb8cfd9257d"}, - {file = "Flask_Babel-2.0.0-py3-none-any.whl", hash = "sha256:e6820a052a8d344e178cdd36dd4bb8aea09b4bda3d5f9fa9f008df2c7f2f5468"}, + {file = "flask_babel-4.0.0-py3-none-any.whl", hash = "sha256:638194cf91f8b301380f36d70e2034c77ee25b98cb5d80a1626820df9a6d4625"}, + {file = "flask_babel-4.0.0.tar.gz", hash = "sha256:dbeab4027a3f4a87678a11686496e98e1492eb793cbdd77ab50f4e9a2602a593"}, ] [package.dependencies] -Babel = ">=2.3" -Flask = "*" -Jinja2 = ">=2.5" -pytz = "*" - -[package.extras] -dev = ["Pallets-Sphinx-Themes", "bumpversion", "ghp-import", "pytest", "pytest-mock", "sphinx"] +Babel = ">=2.12" +Flask = ">=2.0" +Jinja2 = ">=3.1" +pytz = ">=2022.7" [[package]] name = "flask-caching" -version = "2.0.2" +version = "2.1.0" description = "Adds caching support to Flask applications." optional = false python-versions = ">=3.7" files = [ - {file = "Flask-Caching-2.0.2.tar.gz", hash = "sha256:24b60c552d59a9605cc1b6a42c56cdb39a82a28dab4532bbedb9222ae54ecb4e"}, - {file = "Flask_Caching-2.0.2-py3-none-any.whl", hash = "sha256:19571f2570e9b8dd9dd9d2f49d7cbee69c14ebe8cc001100b1eb98c379dd80ad"}, + {file = "Flask-Caching-2.1.0.tar.gz", hash = "sha256:b7500c145135836a952e3de3a80881d9654e327a29c852c9265607f5c449235c"}, + {file = "Flask_Caching-2.1.0-py3-none-any.whl", hash = "sha256:f02645a629a8c89800d96dc8f690a574a0d49dcd66c7536badc6d362ba46b716"}, ] [package.dependencies] cachelib = ">=0.9.0,<0.10.0" -Flask = "<3" +Flask = "*" [[package]] name = "flask-migrate" -version = "3.1.0" +version = "4.0.7" description = "SQLAlchemy database migrations for Flask applications using Alembic." optional = false python-versions = ">=3.6" files = [ - {file = "Flask-Migrate-3.1.0.tar.gz", hash = "sha256:57d6060839e3a7f150eaab6fe4e726d9e3e7cffe2150fb223d73f92421c6d1d9"}, - {file = "Flask_Migrate-3.1.0-py3-none-any.whl", hash = "sha256:a6498706241aba6be7a251078de9cf166d74307bca41a4ca3e403c9d39e2f897"}, + {file = "Flask-Migrate-4.0.7.tar.gz", hash = "sha256:dff7dd25113c210b069af280ea713b883f3840c1e3455274745d7355778c8622"}, + {file = "Flask_Migrate-4.0.7-py3-none-any.whl", hash = "sha256:5c532be17e7b43a223b7500d620edae33795df27c75811ddf32560f7d48ec617"}, ] [package.dependencies] -alembic = ">=0.7" +alembic = ">=1.9.0" Flask = ">=0.9" Flask-SQLAlchemy = ">=1.0" [[package]] name = "flask-pyoidc" -version = "3.14.2" +version = "3.14.3" description = "Flask extension for OpenID Connect authentication." optional = false python-versions = "*" files = [ - {file = "Flask-pyoidc-3.14.2.tar.gz", hash = "sha256:34cf5325f678754e1281904e06263a30595588c2947905625033d992a3d9d35b"}, - {file = "Flask_pyoidc-3.14.2-py3-none-any.whl", hash = "sha256:776eb64fd39d90d59c866d31c7a69b90f4e33e9311801e8ae36e68d6a97590d2"}, + {file = "Flask-pyoidc-3.14.3.tar.gz", hash = "sha256:4a42589f76733c3968ac5f99595c1525a682754916c34f7c029acee6c8ce3bb7"}, + {file = "Flask_pyoidc-3.14.3-py3-none-any.whl", hash = "sha256:a29b7c7660aed9e7b602bfe3cf1d2e5b4e5bc52448cb58babffe2ed10a74cac5"}, ] [package.dependencies] @@ -822,13 +963,13 @@ Flask = ">=0.8.0" [[package]] name = "flask-webtest" -version = "0.1.3" +version = "0.1.4" description = "Utilities for testing Flask applications with WebTest." optional = false python-versions = "*" files = [ - {file = "Flask-WebTest-0.1.3.tar.gz", hash = "sha256:8da31ae2ffef403496dd4752a0937ac39d4619849f2f54c5c7a3792747949559"}, - {file = "Flask_WebTest-0.1.3-py2.py3-none-any.whl", hash = "sha256:71efd3212b2c39ef20914b180ba7bfa6d0b8c0dc17e274ba508cc7a9cdd4ead9"}, + {file = "Flask-WebTest-0.1.4.tar.gz", hash = "sha256:0b22485b9fad5a4ac7c2f2aa1d5767883115c64f2e156c94e2bf2b3deb70ac1a"}, + {file = "Flask_WebTest-0.1.4-py2.py3-none-any.whl", hash = "sha256:35a85328aaf9e977dd82af470063eadec6356cea0bce83e3ed26d5831fa3d48b"}, ] [package.dependencies] @@ -837,36 +978,36 @@ Flask = ">=1.1.0" WebTest = "*" [package.extras] -tests = ["flask-sqlalchemy"] +tests = ["flask-sqlalchemy", "greenlet"] [[package]] name = "flask-wtf" -version = "1.1.1" +version = "1.2.1" description = "Form rendering, validation, and CSRF protection for Flask with WTForms." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Flask-WTF-1.1.1.tar.gz", hash = "sha256:41c4244e9ae626d63bed42ae4785b90667b885b1535d5a4095e1f63060d12aa9"}, - {file = "Flask_WTF-1.1.1-py3-none-any.whl", hash = "sha256:7887d6f1ebb3e17bf648647422f0944c9a469d0fcf63e3b66fb9a83037e38b2c"}, + {file = "flask_wtf-1.2.1-py3-none-any.whl", hash = "sha256:fa6793f2fb7e812e0fe9743b282118e581fb1b6c45d414b8af05e659bd653287"}, + {file = "flask_wtf-1.2.1.tar.gz", hash = "sha256:8bb269eb9bb46b87e7c8233d7e7debdf1f8b74bf90cc1789988c29b37a97b695"}, ] [package.dependencies] -Flask = "*" +flask = "*" itsdangerous = "*" -WTForms = "*" +wtforms = "*" [package.extras] email = ["email-validator"] [[package]] name = "freezegun" -version = "1.2.2" +version = "1.4.0" description = "Let your Python tests travel through time" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "freezegun-1.2.2-py3-none-any.whl", hash = "sha256:ea1b963b993cb9ea195adbd893a48d573fda951b0da64f60883d7e988b606c9f"}, - {file = "freezegun-1.2.2.tar.gz", hash = "sha256:cd22d1ba06941384410cd967d8a99d5ae2442f57dfafeff2fda5de8dc5c05446"}, + {file = "freezegun-1.4.0-py3-none-any.whl", hash = "sha256:55e0fc3c84ebf0a96a5aa23ff8b53d70246479e9a68863f1fcac5a3e52f19dd6"}, + {file = "freezegun-1.4.0.tar.gz", hash = "sha256:10939b0ba0ff5adaecf3b06a5c2f73071d9678e507c5eaedb23c761d56ac774b"}, ] [package.dependencies] @@ -874,104 +1015,99 @@ python-dateutil = ">=2.7" [[package]] name = "future" -version = "0.18.3" +version = "1.0.0" description = "Clean single-source support for Python 3 and 2" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ - {file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"}, + {file = "future-1.0.0-py3-none-any.whl", hash = "sha256:929292d34f5872e70396626ef385ec22355a1fae8ad29e1a734c3e43f9fbc216"}, + {file = "future-1.0.0.tar.gz", hash = "sha256:bd2968309307861edae1458a4f8a4f3598c03be43b97521076aebf5d94c07b05"}, ] [[package]] name = "greenlet" -version = "2.0.2" +version = "3.0.3" description = "Lightweight in-process concurrent programming" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" -files = [ - {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, - {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, - {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, - {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, - {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, - {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d967650d3f56af314b72df7089d96cda1083a7fc2da05b375d2bc48c82ab3f3c"}, - {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, - {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, - {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, - {file = "greenlet-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4606a527e30548153be1a9f155f4e283d109ffba663a15856089fb55f933e47"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, - {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, - {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, - {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, - {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, - {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, - {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, - {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, - {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, - {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, - {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, - {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, - {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, - {file = "greenlet-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1087300cf9700bbf455b1b97e24db18f2f77b55302a68272c56209d5587c12d1"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, - {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, - {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, - {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8512a0c38cfd4e66a858ddd1b17705587900dd760c6003998e9472b77b56d417"}, - {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, - {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, - {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, - {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, -] - -[package.extras] -docs = ["Sphinx", "docutils (<0.18)"] +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, + {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, + {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, + {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, + {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, + {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, + {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, + {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, + {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, + {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, + {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, + {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, + {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, + {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, + {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, + {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] test = ["objgraph", "psutil"] [[package]] name = "gunicorn" -version = "20.1.0" +version = "21.2.0" description = "WSGI HTTP Server for UNIX" optional = false python-versions = ">=3.5" files = [ - {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, - {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, + {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"}, + {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"}, ] [package.dependencies] -setuptools = ">=3.0" +packaging = "*" [package.extras] eventlet = ["eventlet (>=0.24.1)"] @@ -981,13 +1117,13 @@ tornado = ["tornado (>=0.2)"] [[package]] name = "identify" -version = "2.5.27" +version = "2.5.35" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.27-py2.py3-none-any.whl", hash = "sha256:fdb527b2dfe24602809b2201e033c2a113d7bdf716db3ca8e3243f735dcecaba"}, - {file = "identify-2.5.27.tar.gz", hash = "sha256:287b75b04a0e22d727bc9a41f0d4f3c1bcada97490fa6eabb5b28f0e9097e733"}, + {file = "identify-2.5.35-py2.py3-none-any.whl", hash = "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e"}, + {file = "identify-2.5.35.tar.gz", hash = "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791"}, ] [package.extras] @@ -995,51 +1131,62 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "7.1.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, + {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "importlib-resources" -version = "6.0.1" +version = "6.4.0" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.0.1-py3-none-any.whl", hash = "sha256:134832a506243891221b88b4ae1213327eea96ceb4e407a00d790bb0626f45cf"}, - {file = "importlib_resources-6.0.1.tar.gz", hash = "sha256:4359457e42708462b9626a04657c6208ad799ceb41e5c58c57ffa0e6a098a5d4"}, + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, ] [package.dependencies] zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -1065,13 +1212,13 @@ files = [ [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.3" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, ] [package.dependencies] @@ -1080,15 +1227,26 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "json5" +version = "0.9.24" +description = "A Python implementation of the JSON5 data format." +optional = false +python-versions = ">=3.8" +files = [ + {file = "json5-0.9.24-py3-none-any.whl", hash = "sha256:4ca101fd5c7cb47960c055ef8f4d0e31e15a7c6c48c3b6f1473fc83b6c462a13"}, + {file = "json5-0.9.24.tar.gz", hash = "sha256:0c638399421da959a20952782800e5c1a78c14e08e1dc9738fa10d8ec14d58c8"}, +] + [[package]] name = "kombu" -version = "5.3.1" +version = "5.3.6" description = "Messaging library for Python." optional = false python-versions = ">=3.8" files = [ - {file = "kombu-5.3.1-py3-none-any.whl", hash = "sha256:48ee589e8833126fd01ceaa08f8a2041334e9f5894e5763c8486a550454551e9"}, - {file = "kombu-5.3.1.tar.gz", hash = "sha256:fbd7572d92c0bf71c112a6b45163153dea5a7b6a701ec16b568c27d0fd2370f2"}, + {file = "kombu-5.3.6-py3-none-any.whl", hash = "sha256:49f1e62b12369045de2662f62cc584e7df83481a513db83b01f87b5b9785e378"}, + {file = "kombu-5.3.6.tar.gz", hash = "sha256:f3da5b570a147a5da8280180aa80b03807283d63ea5081fcdb510d18242431d9"}, ] [package.dependencies] @@ -1100,14 +1258,14 @@ vine = "*" [package.extras] azureservicebus = ["azure-servicebus (>=7.10.0)"] azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] -confluentkafka = ["confluent-kafka (==2.1.1)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] consul = ["python-consul2"] librabbitmq = ["librabbitmq (>=2.0.0)"] mongodb = ["pymongo (>=4.1.1)"] msgpack = ["msgpack"] pyro = ["pyro4"] qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] -redis = ["redis (>=4.5.2)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2)"] slmq = ["softlayer-messaging (>=1.0.3)"] sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] @@ -1116,120 +1274,184 @@ zookeeper = ["kazoo (>=2.8.0)"] [[package]] name = "lxml" -version = "4.9.3" +version = "5.2.1" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" -files = [ - {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, - {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, - {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, - {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"}, - {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"}, - {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, - {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, - {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, - {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"}, - {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"}, - {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"}, - {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"}, - {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"}, - {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"}, - {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"}, - {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"}, - {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"}, - {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"}, - {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"}, - {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"}, - {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"}, - {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"}, - {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"}, - {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"}, - {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"}, - {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"}, - {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"}, - {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"}, - {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"}, - {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"}, - {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"}, - {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"}, - {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"}, - {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"}, - {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"}, - {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"}, - {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"}, - {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"}, - {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"}, - {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"}, - {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"}, - {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"}, - {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"}, - {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"}, - {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"}, - {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"}, - {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"}, - {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"}, - {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"}, - {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"}, - {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"}, - {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"}, - {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"}, - {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"}, - {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"}, - {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"}, - {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, - {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, +python-versions = ">=3.6" +files = [ + {file = "lxml-5.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1f7785f4f789fdb522729ae465adcaa099e2a3441519df750ebdccc481d961a1"}, + {file = "lxml-5.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cc6ee342fb7fa2471bd9b6d6fdfc78925a697bf5c2bcd0a302e98b0d35bfad3"}, + {file = "lxml-5.2.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:794f04eec78f1d0e35d9e0c36cbbb22e42d370dda1609fb03bcd7aeb458c6377"}, + {file = "lxml-5.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817d420c60a5183953c783b0547d9eb43b7b344a2c46f69513d5952a78cddf3"}, + {file = "lxml-5.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2213afee476546a7f37c7a9b4ad4d74b1e112a6fafffc9185d6d21f043128c81"}, + {file = "lxml-5.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b070bbe8d3f0f6147689bed981d19bbb33070225373338df755a46893528104a"}, + {file = "lxml-5.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e02c5175f63effbd7c5e590399c118d5db6183bbfe8e0d118bdb5c2d1b48d937"}, + {file = "lxml-5.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:3dc773b2861b37b41a6136e0b72a1a44689a9c4c101e0cddb6b854016acc0aa8"}, + {file = "lxml-5.2.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:d7520db34088c96cc0e0a3ad51a4fd5b401f279ee112aa2b7f8f976d8582606d"}, + {file = "lxml-5.2.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:bcbf4af004f98793a95355980764b3d80d47117678118a44a80b721c9913436a"}, + {file = "lxml-5.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a2b44bec7adf3e9305ce6cbfa47a4395667e744097faed97abb4728748ba7d47"}, + {file = "lxml-5.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1c5bb205e9212d0ebddf946bc07e73fa245c864a5f90f341d11ce7b0b854475d"}, + {file = "lxml-5.2.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2c9d147f754b1b0e723e6afb7ba1566ecb162fe4ea657f53d2139bbf894d050a"}, + {file = "lxml-5.2.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:3545039fa4779be2df51d6395e91a810f57122290864918b172d5dc7ca5bb433"}, + {file = "lxml-5.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a91481dbcddf1736c98a80b122afa0f7296eeb80b72344d7f45dc9f781551f56"}, + {file = "lxml-5.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2ddfe41ddc81f29a4c44c8ce239eda5ade4e7fc305fb7311759dd6229a080052"}, + {file = "lxml-5.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a7baf9ffc238e4bf401299f50e971a45bfcc10a785522541a6e3179c83eabf0a"}, + {file = "lxml-5.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:31e9a882013c2f6bd2f2c974241bf4ba68c85eba943648ce88936d23209a2e01"}, + {file = "lxml-5.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0a15438253b34e6362b2dc41475e7f80de76320f335e70c5528b7148cac253a1"}, + {file = "lxml-5.2.1-cp310-cp310-win32.whl", hash = "sha256:6992030d43b916407c9aa52e9673612ff39a575523c5f4cf72cdef75365709a5"}, + {file = "lxml-5.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:da052e7962ea2d5e5ef5bc0355d55007407087392cf465b7ad84ce5f3e25fe0f"}, + {file = "lxml-5.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:70ac664a48aa64e5e635ae5566f5227f2ab7f66a3990d67566d9907edcbbf867"}, + {file = "lxml-5.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1ae67b4e737cddc96c99461d2f75d218bdf7a0c3d3ad5604d1f5e7464a2f9ffe"}, + {file = "lxml-5.2.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f18a5a84e16886898e51ab4b1d43acb3083c39b14c8caeb3589aabff0ee0b270"}, + {file = "lxml-5.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6f2c8372b98208ce609c9e1d707f6918cc118fea4e2c754c9f0812c04ca116d"}, + {file = "lxml-5.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:394ed3924d7a01b5bd9a0d9d946136e1c2f7b3dc337196d99e61740ed4bc6fe1"}, + {file = "lxml-5.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d077bc40a1fe984e1a9931e801e42959a1e6598edc8a3223b061d30fbd26bbc"}, + {file = "lxml-5.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:764b521b75701f60683500d8621841bec41a65eb739b8466000c6fdbc256c240"}, + {file = "lxml-5.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:3a6b45da02336895da82b9d472cd274b22dc27a5cea1d4b793874eead23dd14f"}, + {file = "lxml-5.2.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:5ea7b6766ac2dfe4bcac8b8595107665a18ef01f8c8343f00710b85096d1b53a"}, + {file = "lxml-5.2.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:e196a4ff48310ba62e53a8e0f97ca2bca83cdd2fe2934d8b5cb0df0a841b193a"}, + {file = "lxml-5.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:200e63525948e325d6a13a76ba2911f927ad399ef64f57898cf7c74e69b71095"}, + {file = "lxml-5.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dae0ed02f6b075426accbf6b2863c3d0a7eacc1b41fb40f2251d931e50188dad"}, + {file = "lxml-5.2.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:ab31a88a651039a07a3ae327d68ebdd8bc589b16938c09ef3f32a4b809dc96ef"}, + {file = "lxml-5.2.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:df2e6f546c4df14bc81f9498bbc007fbb87669f1bb707c6138878c46b06f6510"}, + {file = "lxml-5.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5dd1537e7cc06efd81371f5d1a992bd5ab156b2b4f88834ca852de4a8ea523fa"}, + {file = "lxml-5.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9b9ec9c9978b708d488bec36b9e4c94d88fd12ccac3e62134a9d17ddba910ea9"}, + {file = "lxml-5.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8e77c69d5892cb5ba71703c4057091e31ccf534bd7f129307a4d084d90d014b8"}, + {file = "lxml-5.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a8d5c70e04aac1eda5c829a26d1f75c6e5286c74743133d9f742cda8e53b9c2f"}, + {file = "lxml-5.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c94e75445b00319c1fad60f3c98b09cd63fe1134a8a953dcd48989ef42318534"}, + {file = "lxml-5.2.1-cp311-cp311-win32.whl", hash = "sha256:4951e4f7a5680a2db62f7f4ab2f84617674d36d2d76a729b9a8be4b59b3659be"}, + {file = "lxml-5.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:5c670c0406bdc845b474b680b9a5456c561c65cf366f8db5a60154088c92d102"}, + {file = "lxml-5.2.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:abc25c3cab9ec7fcd299b9bcb3b8d4a1231877e425c650fa1c7576c5107ab851"}, + {file = "lxml-5.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6935bbf153f9a965f1e07c2649c0849d29832487c52bb4a5c5066031d8b44fd5"}, + {file = "lxml-5.2.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d793bebb202a6000390a5390078e945bbb49855c29c7e4d56a85901326c3b5d9"}, + {file = "lxml-5.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afd5562927cdef7c4f5550374acbc117fd4ecc05b5007bdfa57cc5355864e0a4"}, + {file = "lxml-5.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0e7259016bc4345a31af861fdce942b77c99049d6c2107ca07dc2bba2435c1d9"}, + {file = "lxml-5.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:530e7c04f72002d2f334d5257c8a51bf409db0316feee7c87e4385043be136af"}, + {file = "lxml-5.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59689a75ba8d7ffca577aefd017d08d659d86ad4585ccc73e43edbfc7476781a"}, + {file = "lxml-5.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f9737bf36262046213a28e789cc82d82c6ef19c85a0cf05e75c670a33342ac2c"}, + {file = "lxml-5.2.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:3a74c4f27167cb95c1d4af1c0b59e88b7f3e0182138db2501c353555f7ec57f4"}, + {file = "lxml-5.2.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:68a2610dbe138fa8c5826b3f6d98a7cfc29707b850ddcc3e21910a6fe51f6ca0"}, + {file = "lxml-5.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f0a1bc63a465b6d72569a9bba9f2ef0334c4e03958e043da1920299100bc7c08"}, + {file = "lxml-5.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c2d35a1d047efd68027817b32ab1586c1169e60ca02c65d428ae815b593e65d4"}, + {file = "lxml-5.2.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:79bd05260359170f78b181b59ce871673ed01ba048deef4bf49a36ab3e72e80b"}, + {file = "lxml-5.2.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:865bad62df277c04beed9478fe665b9ef63eb28fe026d5dedcb89b537d2e2ea6"}, + {file = "lxml-5.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:44f6c7caff88d988db017b9b0e4ab04934f11e3e72d478031efc7edcac6c622f"}, + {file = "lxml-5.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:71e97313406ccf55d32cc98a533ee05c61e15d11b99215b237346171c179c0b0"}, + {file = "lxml-5.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:057cdc6b86ab732cf361f8b4d8af87cf195a1f6dc5b0ff3de2dced242c2015e0"}, + {file = "lxml-5.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f3bbbc998d42f8e561f347e798b85513ba4da324c2b3f9b7969e9c45b10f6169"}, + {file = "lxml-5.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:491755202eb21a5e350dae00c6d9a17247769c64dcf62d8c788b5c135e179dc4"}, + {file = "lxml-5.2.1-cp312-cp312-win32.whl", hash = "sha256:8de8f9d6caa7f25b204fc861718815d41cbcf27ee8f028c89c882a0cf4ae4134"}, + {file = "lxml-5.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:f2a9efc53d5b714b8df2b4b3e992accf8ce5bbdfe544d74d5c6766c9e1146a3a"}, + {file = "lxml-5.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:70a9768e1b9d79edca17890175ba915654ee1725975d69ab64813dd785a2bd5c"}, + {file = "lxml-5.2.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c38d7b9a690b090de999835f0443d8aa93ce5f2064035dfc48f27f02b4afc3d0"}, + {file = "lxml-5.2.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5670fb70a828663cc37552a2a85bf2ac38475572b0e9b91283dc09efb52c41d1"}, + {file = "lxml-5.2.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:958244ad566c3ffc385f47dddde4145088a0ab893504b54b52c041987a8c1863"}, + {file = "lxml-5.2.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6241d4eee5f89453307c2f2bfa03b50362052ca0af1efecf9fef9a41a22bb4f"}, + {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2a66bf12fbd4666dd023b6f51223aed3d9f3b40fef06ce404cb75bafd3d89536"}, + {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:9123716666e25b7b71c4e1789ec829ed18663152008b58544d95b008ed9e21e9"}, + {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:0c3f67e2aeda739d1cc0b1102c9a9129f7dc83901226cc24dd72ba275ced4218"}, + {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5d5792e9b3fb8d16a19f46aa8208987cfeafe082363ee2745ea8b643d9cc5b45"}, + {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:88e22fc0a6684337d25c994381ed8a1580a6f5ebebd5ad41f89f663ff4ec2885"}, + {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:21c2e6b09565ba5b45ae161b438e033a86ad1736b8c838c766146eff8ceffff9"}, + {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_2_s390x.whl", hash = "sha256:afbbdb120d1e78d2ba8064a68058001b871154cc57787031b645c9142b937a62"}, + {file = "lxml-5.2.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:627402ad8dea044dde2eccde4370560a2b750ef894c9578e1d4f8ffd54000461"}, + {file = "lxml-5.2.1-cp36-cp36m-win32.whl", hash = "sha256:e89580a581bf478d8dcb97d9cd011d567768e8bc4095f8557b21c4d4c5fea7d0"}, + {file = "lxml-5.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:59565f10607c244bc4c05c0c5fa0c190c990996e0c719d05deec7030c2aa8289"}, + {file = "lxml-5.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:857500f88b17a6479202ff5fe5f580fc3404922cd02ab3716197adf1ef628029"}, + {file = "lxml-5.2.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56c22432809085b3f3ae04e6e7bdd36883d7258fcd90e53ba7b2e463efc7a6af"}, + {file = "lxml-5.2.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a55ee573116ba208932e2d1a037cc4b10d2c1cb264ced2184d00b18ce585b2c0"}, + {file = "lxml-5.2.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:6cf58416653c5901e12624e4013708b6e11142956e7f35e7a83f1ab02f3fe456"}, + {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:64c2baa7774bc22dd4474248ba16fe1a7f611c13ac6123408694d4cc93d66dbd"}, + {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:74b28c6334cca4dd704e8004cba1955af0b778cf449142e581e404bd211fb619"}, + {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:7221d49259aa1e5a8f00d3d28b1e0b76031655ca74bb287123ef56c3db92f213"}, + {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3dbe858ee582cbb2c6294dc85f55b5f19c918c2597855e950f34b660f1a5ede6"}, + {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:04ab5415bf6c86e0518d57240a96c4d1fcfc3cb370bb2ac2a732b67f579e5a04"}, + {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:6ab833e4735a7e5533711a6ea2df26459b96f9eec36d23f74cafe03631647c41"}, + {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f443cdef978430887ed55112b491f670bba6462cea7a7742ff8f14b7abb98d75"}, + {file = "lxml-5.2.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:9e2addd2d1866fe112bc6f80117bcc6bc25191c5ed1bfbcf9f1386a884252ae8"}, + {file = "lxml-5.2.1-cp37-cp37m-win32.whl", hash = "sha256:f51969bac61441fd31f028d7b3b45962f3ecebf691a510495e5d2cd8c8092dbd"}, + {file = "lxml-5.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b0b58fbfa1bf7367dde8a557994e3b1637294be6cf2169810375caf8571a085c"}, + {file = "lxml-5.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3e183c6e3298a2ed5af9d7a356ea823bccaab4ec2349dc9ed83999fd289d14d5"}, + {file = "lxml-5.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:804f74efe22b6a227306dd890eecc4f8c59ff25ca35f1f14e7482bbce96ef10b"}, + {file = "lxml-5.2.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:08802f0c56ed150cc6885ae0788a321b73505d2263ee56dad84d200cab11c07a"}, + {file = "lxml-5.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f8c09ed18ecb4ebf23e02b8e7a22a05d6411911e6fabef3a36e4f371f4f2585"}, + {file = "lxml-5.2.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3d30321949861404323c50aebeb1943461a67cd51d4200ab02babc58bd06a86"}, + {file = "lxml-5.2.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:b560e3aa4b1d49e0e6c847d72665384db35b2f5d45f8e6a5c0072e0283430533"}, + {file = "lxml-5.2.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:058a1308914f20784c9f4674036527e7c04f7be6fb60f5d61353545aa7fcb739"}, + {file = "lxml-5.2.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:adfb84ca6b87e06bc6b146dc7da7623395db1e31621c4785ad0658c5028b37d7"}, + {file = "lxml-5.2.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:417d14450f06d51f363e41cace6488519038f940676ce9664b34ebf5653433a5"}, + {file = "lxml-5.2.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a2dfe7e2473f9b59496247aad6e23b405ddf2e12ef0765677b0081c02d6c2c0b"}, + {file = "lxml-5.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bf2e2458345d9bffb0d9ec16557d8858c9c88d2d11fed53998512504cd9df49b"}, + {file = "lxml-5.2.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:58278b29cb89f3e43ff3e0c756abbd1518f3ee6adad9e35b51fb101c1c1daaec"}, + {file = "lxml-5.2.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:64641a6068a16201366476731301441ce93457eb8452056f570133a6ceb15fca"}, + {file = "lxml-5.2.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:78bfa756eab503673991bdcf464917ef7845a964903d3302c5f68417ecdc948c"}, + {file = "lxml-5.2.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:11a04306fcba10cd9637e669fd73aa274c1c09ca64af79c041aa820ea992b637"}, + {file = "lxml-5.2.1-cp38-cp38-win32.whl", hash = "sha256:66bc5eb8a323ed9894f8fa0ee6cb3e3fb2403d99aee635078fd19a8bc7a5a5da"}, + {file = "lxml-5.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:9676bfc686fa6a3fa10cd4ae6b76cae8be26eb5ec6811d2a325636c460da1806"}, + {file = "lxml-5.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cf22b41fdae514ee2f1691b6c3cdeae666d8b7fa9434de445f12bbeee0cf48dd"}, + {file = "lxml-5.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec42088248c596dbd61d4ae8a5b004f97a4d91a9fd286f632e42e60b706718d7"}, + {file = "lxml-5.2.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd53553ddad4a9c2f1f022756ae64abe16da1feb497edf4d9f87f99ec7cf86bd"}, + {file = "lxml-5.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feaa45c0eae424d3e90d78823f3828e7dc42a42f21ed420db98da2c4ecf0a2cb"}, + {file = "lxml-5.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddc678fb4c7e30cf830a2b5a8d869538bc55b28d6c68544d09c7d0d8f17694dc"}, + {file = "lxml-5.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:853e074d4931dbcba7480d4dcab23d5c56bd9607f92825ab80ee2bd916edea53"}, + {file = "lxml-5.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4691d60512798304acb9207987e7b2b7c44627ea88b9d77489bbe3e6cc3bd4"}, + {file = "lxml-5.2.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:beb72935a941965c52990f3a32d7f07ce869fe21c6af8b34bf6a277b33a345d3"}, + {file = "lxml-5.2.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:6588c459c5627fefa30139be4d2e28a2c2a1d0d1c265aad2ba1935a7863a4913"}, + {file = "lxml-5.2.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:588008b8497667f1ddca7c99f2f85ce8511f8f7871b4a06ceede68ab62dff64b"}, + {file = "lxml-5.2.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6787b643356111dfd4032b5bffe26d2f8331556ecb79e15dacb9275da02866e"}, + {file = "lxml-5.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7c17b64b0a6ef4e5affae6a3724010a7a66bda48a62cfe0674dabd46642e8b54"}, + {file = "lxml-5.2.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:27aa20d45c2e0b8cd05da6d4759649170e8dfc4f4e5ef33a34d06f2d79075d57"}, + {file = "lxml-5.2.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d4f2cc7060dc3646632d7f15fe68e2fa98f58e35dd5666cd525f3b35d3fed7f8"}, + {file = "lxml-5.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff46d772d5f6f73564979cd77a4fffe55c916a05f3cb70e7c9c0590059fb29ef"}, + {file = "lxml-5.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:96323338e6c14e958d775700ec8a88346014a85e5de73ac7967db0367582049b"}, + {file = "lxml-5.2.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:52421b41ac99e9d91934e4d0d0fe7da9f02bfa7536bb4431b4c05c906c8c6919"}, + {file = "lxml-5.2.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:7a7efd5b6d3e30d81ec68ab8a88252d7c7c6f13aaa875009fe3097eb4e30b84c"}, + {file = "lxml-5.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ed777c1e8c99b63037b91f9d73a6aad20fd035d77ac84afcc205225f8f41188"}, + {file = "lxml-5.2.1-cp39-cp39-win32.whl", hash = "sha256:644df54d729ef810dcd0f7732e50e5ad1bd0a135278ed8d6bcb06f33b6b6f708"}, + {file = "lxml-5.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:9ca66b8e90daca431b7ca1408cae085d025326570e57749695d6a01454790e95"}, + {file = "lxml-5.2.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9b0ff53900566bc6325ecde9181d89afadc59c5ffa39bddf084aaedfe3b06a11"}, + {file = "lxml-5.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd6037392f2d57793ab98d9e26798f44b8b4da2f2464388588f48ac52c489ea1"}, + {file = "lxml-5.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b9c07e7a45bb64e21df4b6aa623cb8ba214dfb47d2027d90eac197329bb5e94"}, + {file = "lxml-5.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3249cc2989d9090eeac5467e50e9ec2d40704fea9ab72f36b034ea34ee65ca98"}, + {file = "lxml-5.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f42038016852ae51b4088b2862126535cc4fc85802bfe30dea3500fdfaf1864e"}, + {file = "lxml-5.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:533658f8fbf056b70e434dff7e7aa611bcacb33e01f75de7f821810e48d1bb66"}, + {file = "lxml-5.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:622020d4521e22fb371e15f580d153134bfb68d6a429d1342a25f051ec72df1c"}, + {file = "lxml-5.2.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efa7b51824aa0ee957ccd5a741c73e6851de55f40d807f08069eb4c5a26b2baa"}, + {file = "lxml-5.2.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c6ad0fbf105f6bcc9300c00010a2ffa44ea6f555df1a2ad95c88f5656104817"}, + {file = "lxml-5.2.1-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e233db59c8f76630c512ab4a4daf5a5986da5c3d5b44b8e9fc742f2a24dbd460"}, + {file = "lxml-5.2.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6a014510830df1475176466b6087fc0c08b47a36714823e58d8b8d7709132a96"}, + {file = "lxml-5.2.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d38c8f50ecf57f0463399569aa388b232cf1a2ffb8f0a9a5412d0db57e054860"}, + {file = "lxml-5.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5aea8212fb823e006b995c4dda533edcf98a893d941f173f6c9506126188860d"}, + {file = "lxml-5.2.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff097ae562e637409b429a7ac958a20aab237a0378c42dabaa1e3abf2f896e5f"}, + {file = "lxml-5.2.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f5d65c39f16717a47c36c756af0fb36144069c4718824b7533f803ecdf91138"}, + {file = "lxml-5.2.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3d0c3dd24bb4605439bf91068598d00c6370684f8de4a67c2992683f6c309d6b"}, + {file = "lxml-5.2.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e32be23d538753a8adb6c85bd539f5fd3b15cb987404327c569dfc5fd8366e85"}, + {file = "lxml-5.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cc518cea79fd1e2f6c90baafa28906d4309d24f3a63e801d855e7424c5b34144"}, + {file = "lxml-5.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a0af35bd8ebf84888373630f73f24e86bf016642fb8576fba49d3d6b560b7cbc"}, + {file = "lxml-5.2.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8aca2e3a72f37bfc7b14ba96d4056244001ddcc18382bd0daa087fd2e68a354"}, + {file = "lxml-5.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ca1e8188b26a819387b29c3895c47a5e618708fe6f787f3b1a471de2c4a94d9"}, + {file = "lxml-5.2.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c8ba129e6d3b0136a0f50345b2cb3db53f6bda5dd8c7f5d83fbccba97fb5dcb5"}, + {file = "lxml-5.2.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e998e304036198b4f6914e6a1e2b6f925208a20e2042563d9734881150c6c246"}, + {file = "lxml-5.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d3be9b2076112e51b323bdf6d5a7f8a798de55fb8d95fcb64bd179460cdc0704"}, + {file = "lxml-5.2.1.tar.gz", hash = "sha256:3f7765e69bbce0906a7c74d5fe46d2c7a7596147318dbc08e4a2431f3060e306"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml-html-clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=0.29.35)"] +source = ["Cython (>=3.0.10)"] [[package]] name = "mako" -version = "1.2.4" +version = "1.3.2" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Mako-1.2.4-py3-none-any.whl", hash = "sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818"}, - {file = "Mako-1.2.4.tar.gz", hash = "sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34"}, + {file = "Mako-1.3.2-py3-none-any.whl", hash = "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c"}, + {file = "Mako-1.3.2.tar.gz", hash = "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e"}, ] [package.dependencies] @@ -1240,73 +1462,97 @@ babel = ["Babel"] lingua = ["lingua"] testing = ["pytest"] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] @@ -1321,27 +1567,75 @@ files = [ ] [[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." +name = "mdit-py-plugins" +version = "0.4.0" +description = "Collection of plugins for markdown-it-py" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" +files = [ + {file = "mdit_py_plugins-0.4.0-py3-none-any.whl", hash = "sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9"}, + {file = "mdit_py_plugins-0.4.0.tar.gz", hash = "sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b"}, +] + +[package.dependencies] +markdown-it-py = ">=1.0.0,<4.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["myst-parser", "sphinx-book-theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "myst-parser" +version = "2.0.0" +description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," +optional = false +python-versions = ">=3.8" files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, + {file = "myst_parser-2.0.0-py3-none-any.whl", hash = "sha256:7c36344ae39c8e740dad7fdabf5aa6fc4897a813083c6cc9990044eb93656b14"}, + {file = "myst_parser-2.0.0.tar.gz", hash = "sha256:ea929a67a6a0b1683cdbe19b8d2e724cd7643f8aa3e7bb18dd65beac3483bead"}, ] +[package.dependencies] +docutils = ">=0.16,<0.21" +jinja2 = "*" +markdown-it-py = ">=3.0,<4.0" +mdit-py-plugins = ">=0.4,<1.0" +pyyaml = "*" +sphinx = ">=6,<8" + +[package.extras] +code-style = ["pre-commit (>=3.0,<4.0)"] +linkify = ["linkify-it-py (>=2.0,<3.0)"] +rtd = ["ipython", "pydata-sphinx-theme (==v0.13.0rc4)", "sphinx-autodoc2 (>=0.4.2,<0.5.0)", "sphinx-book-theme (==1.0.0rc2)", "sphinx-copybutton", "sphinx-design2", "sphinx-pyscript", "sphinx-tippy (>=0.3.1)", "sphinx-togglebutton", "sphinxext-opengraph (>=0.8.2,<0.9.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] +testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=7,<8)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx-pytest"] +testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4,<0.4.0)"] + [[package]] name = "netaddr" -version = "0.8.0" +version = "1.2.1" description = "A network address manipulation library for Python" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "netaddr-0.8.0-py2.py3-none-any.whl", hash = "sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac"}, - {file = "netaddr-0.8.0.tar.gz", hash = "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243"}, + {file = "netaddr-1.2.1-py3-none-any.whl", hash = "sha256:bd9e9534b0d46af328cf64f0e5a23a5a43fca292df221c85580b27394793496e"}, + {file = "netaddr-1.2.1.tar.gz", hash = "sha256:6eb8fedf0412c6d294d06885c110de945cf4d22d2b510d0404f4e06950857987"}, ] +[package.extras] +nicer-shell = ["ipython"] + [[package]] name = "nodeenv" version = "1.8.0" @@ -1387,65 +1681,68 @@ types = ["types-requests"] [[package]] name = "packaging" -version = "23.1" +version = "24.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, -] - -[[package]] -name = "pathspec" -version = "0.11.2" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] name = "platformdirs" -version = "3.10.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pluggy" -version = "1.2.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "portpicker" +version = "1.6.0" +description = "A library to choose unique available network ports." +optional = false +python-versions = ">=3.6" +files = [ + {file = "portpicker-1.6.0-py3-none-any.whl", hash = "sha256:b2787a41404cf7edbe29b07b9e0ed863b09f2665dcc01c1eb0c2261c1e7d0755"}, + {file = "portpicker-1.6.0.tar.gz", hash = "sha256:bd507fd6f96f65ee02781f2e674e9dc6c99bbfa6e3c39992e3916204c9d431fa"}, +] + +[package.dependencies] +psutil = "*" + [[package]] name = "pre-commit" -version = "3.3.3" +version = "3.5.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.8" files = [ - {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"}, - {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"}, + {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, + {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, ] [package.dependencies] @@ -1457,115 +1754,145 @@ virtualenv = ">=20.10.0" [[package]] name = "prompt-toolkit" -version = "3.0.39" +version = "3.0.43" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, - {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, + {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, + {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, ] [package.dependencies] wcwidth = "*" +[[package]] +name = "psutil" +version = "5.9.8" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + [[package]] name = "psycopg2" -version = "2.9.3" +version = "2.9.9" description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "psycopg2-2.9.3-cp310-cp310-win32.whl", hash = "sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362"}, - {file = "psycopg2-2.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca"}, - {file = "psycopg2-2.9.3-cp36-cp36m-win32.whl", hash = "sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56"}, - {file = "psycopg2-2.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305"}, - {file = "psycopg2-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2"}, - {file = "psycopg2-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461"}, - {file = "psycopg2-2.9.3-cp38-cp38-win32.whl", hash = "sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7"}, - {file = "psycopg2-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf"}, - {file = "psycopg2-2.9.3-cp39-cp39-win32.whl", hash = "sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126"}, - {file = "psycopg2-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c"}, - {file = "psycopg2-2.9.3.tar.gz", hash = "sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981"}, + {file = "psycopg2-2.9.9-cp310-cp310-win32.whl", hash = "sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516"}, + {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"}, + {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"}, + {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"}, + {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"}, + {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"}, + {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"}, + {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"}, + {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"}, + {file = "psycopg2-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e"}, + {file = "psycopg2-2.9.9-cp39-cp39-win32.whl", hash = "sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59"}, + {file = "psycopg2-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913"}, + {file = "psycopg2-2.9.9.tar.gz", hash = "sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156"}, ] [[package]] name = "pycodestyle" -version = "2.11.0" +version = "2.11.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" files = [ - {file = "pycodestyle-2.11.0-py2.py3-none-any.whl", hash = "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"}, - {file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"}, + {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, + {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, ] [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] name = "pycryptodomex" -version = "3.18.0" +version = "3.20.0" description = "Cryptographic library for Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "pycryptodomex-3.18.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:160a39a708c36fa0b168ab79386dede588e62aec06eb505add870739329aecc6"}, - {file = "pycryptodomex-3.18.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c2953afebf282a444c51bf4effe751706b4d0d63d7ca2cc51db21f902aa5b84e"}, - {file = "pycryptodomex-3.18.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:ba95abd563b0d1b88401658665a260852a8e6c647026ee6a0a65589287681df8"}, - {file = "pycryptodomex-3.18.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:192306cf881fe3467dda0e174a4f47bb3a8bb24b90c9cdfbdc248eec5fc0578c"}, - {file = "pycryptodomex-3.18.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:f9ab5ef0718f6a8716695dea16d83b671b22c45e9c0c78fd807c32c0192e54b5"}, - {file = "pycryptodomex-3.18.0-cp27-cp27m-win32.whl", hash = "sha256:50308fcdbf8345e5ec224a5502b4215178bdb5e95456ead8ab1a69ffd94779cb"}, - {file = "pycryptodomex-3.18.0-cp27-cp27m-win_amd64.whl", hash = "sha256:4d9379c684efea80fdab02a3eb0169372bca7db13f9332cb67483b8dc8b67c37"}, - {file = "pycryptodomex-3.18.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5594a125dae30d60e94f37797fc67ce3c744522de7992c7c360d02fdb34918f8"}, - {file = "pycryptodomex-3.18.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:8ff129a5a0eb5ff16e45ca4fa70a6051da7f3de303c33b259063c19be0c43d35"}, - {file = "pycryptodomex-3.18.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:3d9314ac785a5b75d5aaf924c5f21d6ca7e8df442e5cf4f0fefad4f6e284d422"}, - {file = "pycryptodomex-3.18.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:f237278836dda412a325e9340ba2e6a84cb0f56b9244781e5b61f10b3905de88"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac614363a86cc53d8ba44b6c469831d1555947e69ab3276ae8d6edc219f570f7"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:302a8f37c224e7b5d72017d462a2be058e28f7be627bdd854066e16722d0fc0c"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:6421d23d6a648e83ba2670a352bcd978542dad86829209f59d17a3f087f4afef"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84e105787f5e5d36ec6a581ff37a1048d12e638688074b2a00bcf402f9aa1c2"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6875eb8666f68ddbd39097867325bd22771f595b4e2b0149739b5623c8bf899b"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:27072a494ce621cc7a9096bbf60ed66826bb94db24b49b7359509e7951033e74"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:1949e09ea49b09c36d11a951b16ff2a05a0ffe969dda1846e4686ee342fe8646"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6ed3606832987018615f68e8ed716a7065c09a0fe94afd7c9ca1b6777f0ac6eb"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-win32.whl", hash = "sha256:d56c9ec41258fd3734db9f5e4d2faeabe48644ba9ca23b18e1839b3bdf093222"}, - {file = "pycryptodomex-3.18.0-cp35-abi3-win_amd64.whl", hash = "sha256:e00a4bacb83a2627e8210cb353a2e31f04befc1155db2976e5e239dd66482278"}, - {file = "pycryptodomex-3.18.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2dc4eab20f4f04a2d00220fdc9258717b82d31913552e766d5f00282c031b70a"}, - {file = "pycryptodomex-3.18.0-pp27-pypy_73-win32.whl", hash = "sha256:75672205148bdea34669173366df005dbd52be05115e919551ee97171083423d"}, - {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bec6c80994d4e7a38312072f89458903b65ec99bed2d65aa4de96d997a53ea7a"}, - {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d35a8ffdc8b05e4b353ba281217c8437f02c57d7233363824e9d794cf753c419"}, - {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76f0a46bee539dae4b3dfe37216f678769349576b0080fdbe431d19a02da42ff"}, - {file = "pycryptodomex-3.18.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:71687eed47df7e965f6e0bf3cadef98f368d5221f0fb89d2132effe1a3e6a194"}, - {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:73d64b32d84cf48d9ec62106aa277dbe99ab5fbfd38c5100bc7bddd3beb569f7"}, - {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbdcce0a226d9205560a5936b05208c709b01d493ed8307792075dedfaaffa5f"}, - {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58fc0aceb9c961b9897facec9da24c6a94c5db04597ec832060f53d4d6a07196"}, - {file = "pycryptodomex-3.18.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:215be2980a6b70704c10796dd7003eb4390e7be138ac6fb8344bf47e71a8d470"}, - {file = "pycryptodomex-3.18.0.tar.gz", hash = "sha256:3e3ecb5fe979e7c1bb0027e518340acf7ee60415d79295e5251d13c68dde576e"}, + {file = "pycryptodomex-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:645bd4ca6f543685d643dadf6a856cc382b654cc923460e3a10a49c1b3832aeb"}, + {file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ff5c9a67f8a4fba4aed887216e32cbc48f2a6fb2673bb10a99e43be463e15913"}, + {file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8ee606964553c1a0bc74057dd8782a37d1c2bc0f01b83193b6f8bb14523b877b"}, + {file = "pycryptodomex-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7805830e0c56d88f4d491fa5ac640dfc894c5ec570d1ece6ed1546e9df2e98d6"}, + {file = "pycryptodomex-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:bc3ee1b4d97081260d92ae813a83de4d2653206967c4a0a017580f8b9548ddbc"}, + {file = "pycryptodomex-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:8af1a451ff9e123d0d8bd5d5e60f8e3315c3a64f3cdd6bc853e26090e195cdc8"}, + {file = "pycryptodomex-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:cbe71b6712429650e3883dc81286edb94c328ffcd24849accac0a4dbcc76958a"}, + {file = "pycryptodomex-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:76bd15bb65c14900d98835fcd10f59e5e0435077431d3a394b60b15864fddd64"}, + {file = "pycryptodomex-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:653b29b0819605fe0898829c8ad6400a6ccde096146730c2da54eede9b7b8baa"}, + {file = "pycryptodomex-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a5ec91388984909bb5398ea49ee61b68ecb579123694bffa172c3b0a107079"}, + {file = "pycryptodomex-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:108e5f1c1cd70ffce0b68739c75734437c919d2eaec8e85bffc2c8b4d2794305"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91852d4480a4537d169c29a9d104dda44094c78f1f5b67bca76c29a91042b623"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca649483d5ed251d06daf25957f802e44e6bb6df2e8f218ae71968ff8f8edc4"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e186342cfcc3aafaad565cbd496060e5a614b441cacc3995ef0091115c1f6c5"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:25cd61e846aaab76d5791d006497134602a9e451e954833018161befc3b5b9ed"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:9c682436c359b5ada67e882fec34689726a09c461efd75b6ea77b2403d5665b7"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7a7a8f33a1f1fb762ede6cc9cbab8f2a9ba13b196bfaf7bc6f0b39d2ba315a43"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-win32.whl", hash = "sha256:c39778fd0548d78917b61f03c1fa8bfda6cfcf98c767decf360945fe6f97461e"}, + {file = "pycryptodomex-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:2a47bcc478741b71273b917232f521fd5704ab4b25d301669879e7273d3586cc"}, + {file = "pycryptodomex-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:1be97461c439a6af4fe1cf8bf6ca5936d3db252737d2f379cc6b2e394e12a458"}, + {file = "pycryptodomex-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:19764605feea0df966445d46533729b645033f134baeb3ea26ad518c9fdf212c"}, + {file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e497413560e03421484189a6b65e33fe800d3bd75590e6d78d4dfdb7accf3b"}, + {file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48217c7901edd95f9f097feaa0388da215ed14ce2ece803d3f300b4e694abea"}, + {file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d00fe8596e1cc46b44bf3907354e9377aa030ec4cd04afbbf6e899fc1e2a7781"}, + {file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88afd7a3af7ddddd42c2deda43d53d3dfc016c11327d0915f90ca34ebda91499"}, + {file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d3584623e68a5064a04748fb6d76117a21a7cb5eaba20608a41c7d0c61721794"}, + {file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0daad007b685db36d977f9de73f61f8da2a7104e20aca3effd30752fd56f73e1"}, + {file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dcac11031a71348faaed1f403a0debd56bf5404232284cf8c761ff918886ebc"}, + {file = "pycryptodomex-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:69138068268127cd605e03438312d8f271135a33140e2742b417d027a0539427"}, + {file = "pycryptodomex-3.20.0.tar.gz", hash = "sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e"}, ] [[package]] name = "pydantic" -version = "2.2.1" +version = "2.6.4" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.2.1-py3-none-any.whl", hash = "sha256:0c88bd2b63ed7a5109c75ab180d55f58f80a4b559682406812d0684d3f4b9192"}, - {file = "pydantic-2.2.1.tar.gz", hash = "sha256:31b5cada74b2320999fb2577e6df80332a200ff92e7775a52448b6b036fce24a"}, + {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"}, + {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.6.1" +pydantic-core = "2.16.3" typing-extensions = ">=4.6.1" [package.extras] @@ -1573,117 +1900,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.6.1" +version = "2.16.3" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.6.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:f55001a689111a297c0006c46c0589cfd559261baaa9a37bc35eff05b8cae1a6"}, - {file = "pydantic_core-2.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bb6273068e9450c5c91f58dd277fbd406b896ffa30f0ef312edc5519d07f16ae"}, - {file = "pydantic_core-2.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:043212f21c75cb6ee3a92fffbc747410e32b08e1a419ce16a9da98a16d660a7c"}, - {file = "pydantic_core-2.6.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:db0c12f1e9d3bf658634621f3423486803d749fef77a64cfb4252f9d619e1817"}, - {file = "pydantic_core-2.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81424dc05c4342a19fb64323bb9d4468e7407b745c00377ccc4d3dd96d5e02fe"}, - {file = "pydantic_core-2.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c8f3aebaf92f088b1dafd7101d1ccca0459ae0f5b26017411b9969667d289a9"}, - {file = "pydantic_core-2.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd9f14454b4bc89c705ce17951f9c783db82efd2b44a424487c593e2269eef61"}, - {file = "pydantic_core-2.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2effc71653247e76c5b95d15c58d4ca3f591f42f714eb3b32df9d6ec613794a5"}, - {file = "pydantic_core-2.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:56672429f8a89d2a0f4402d912f0dad68c2d05f7c278d3152c6fb4a76c2a429a"}, - {file = "pydantic_core-2.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d0bf1c2545ab253732229c7fe8294d98eb08f99aa25a388267e1bc4d2d7e0a34"}, - {file = "pydantic_core-2.6.1-cp310-none-win32.whl", hash = "sha256:c5be947ad41a7602f941dc834d03e64dd1c7fae65fa85cb4f1004a95c5d50df1"}, - {file = "pydantic_core-2.6.1-cp310-none-win_amd64.whl", hash = "sha256:3d14ae98a8d251402ef8ed017039d2fc3e29fb155f909cd3816ba259fd30fb48"}, - {file = "pydantic_core-2.6.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4a3c20808d3ced90e29439f72a563eadf21d29560935cc818b2dab80b92c114a"}, - {file = "pydantic_core-2.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:da240bbd8191edc6009e7793d5d4d67c55f56225c4788f068d6286c20e5a2038"}, - {file = "pydantic_core-2.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de1a3e56e34264d5216c67d2a48185216ada8f5f35a7f4c96a3971847c0de897"}, - {file = "pydantic_core-2.6.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9b623e09239ed333d14c02c9fcd1a7bb350b95eca8383f6e9b0d8e373d5a14b5"}, - {file = "pydantic_core-2.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a12520a6d502a25f6e47319874e47056b290f1b3c2ed9391444ce81c8cc5b83"}, - {file = "pydantic_core-2.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1141f18414aee8865c7917ae1432e419c1983272f53625152493692ff3d6783"}, - {file = "pydantic_core-2.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7888b3ee7566865cff3e9edab5d6cdf2e7cf793df17fe53d5e7be3e57eae45ec"}, - {file = "pydantic_core-2.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bdf293b6304bc451678b7016c2505b7d97aa85ff13dac4420027b1b69e15d3d"}, - {file = "pydantic_core-2.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7ef56a05bb60336d5e795bf166d6712b2362e6478522c77e8336cb0da8909913"}, - {file = "pydantic_core-2.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3210eb73707e3487c16ef25cfd1663660f4e7d647a181d6c2fb18bc6167985fb"}, - {file = "pydantic_core-2.6.1-cp311-none-win32.whl", hash = "sha256:707e3005e8c129bdac117285b71717c13b9ed81a81eae0b1642f4ddc60028e63"}, - {file = "pydantic_core-2.6.1-cp311-none-win_amd64.whl", hash = "sha256:2b8ccec2189d8a8b83929f79e5bc00c0656f6c2ba4345125c0c82d1b77e15a26"}, - {file = "pydantic_core-2.6.1-cp311-none-win_arm64.whl", hash = "sha256:c1e44b77442fb5b1b6fccea30e3359b14d0a2e5896801243defe54482a591500"}, - {file = "pydantic_core-2.6.1-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:c82fb25f965f6777032fc2f2856c86149f7709c8f7fd0c020a8631b8211f2bab"}, - {file = "pydantic_core-2.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:494b211b12b8fedd184dbba609f6ed582e23561db57c1996fd6773989dbaef9b"}, - {file = "pydantic_core-2.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1281c940f47e5c89b594ef7580045647df1f9ad687edd503bcc0485be94576f4"}, - {file = "pydantic_core-2.6.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2d41701c88d8b678c16c10562949f2d28aceacd767cbe51dac9c8c41e6e609fb"}, - {file = "pydantic_core-2.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6a839c95d5cc91eed053d8dafde4e200c4bc82f56fb1cf7bbfaeb03e2d907929"}, - {file = "pydantic_core-2.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c22e4fbfb5823d0fcb2c20ed164b39c3588554f9635f70765e8c9cff0fef67ad"}, - {file = "pydantic_core-2.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2fed4ad60ccf2698bd04e95dfc3bd84149ced9605a29fd27d624701e1da300c"}, - {file = "pydantic_core-2.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33b9343aa464d60c31937b361abde08d3af9943f3eb09d3216211b6236bd40c4"}, - {file = "pydantic_core-2.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:56e4953cd911293d6d755e2a97c651826aca76201db8f1ee298939e703721390"}, - {file = "pydantic_core-2.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cd163109047ab41ef1ea34258b35beb3ccac90af2012927ee8ab6ff122fef671"}, - {file = "pydantic_core-2.6.1-cp312-none-win32.whl", hash = "sha256:f5b51ec04743c94288c46e3759769611ab7c5ce0f941113363da96d20d345fb6"}, - {file = "pydantic_core-2.6.1-cp312-none-win_amd64.whl", hash = "sha256:ca5606bd82e255b1d704a4334e5ebf05ae966b69686fae02dcd31c057bdcb113"}, - {file = "pydantic_core-2.6.1-cp312-none-win_arm64.whl", hash = "sha256:dfc8f534a21b60b00f87e5a4fc36b8b8945160a6cc9e7b6e67db541c766c9597"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:b1aed20778092f8334c8eaf91550fa2805221d5e9b40ebdd1f46ee7efc159a48"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:64ff7a4b7ee2a56735af28da76c5dacbba6995801080f739d14610f4aa3de35d"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2d8faedb138c704957642fdf154c94f1b3d2a15cbd2472e45665f80463e85ee"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:55aac69d7339a63e37164f0a629c3034becc6746d68d126118a3ee4493514bed"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dfdb1617af455a551be4cc0471f0bf3bfb1e882db71afad0e587c821326bb749"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aadc84f5bd7b1421b5a6b389ceff46062dd4a58c44cfb75990e9ca2d9d8270df"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1a01dce87507b9a8f1b71933ade85c573a22c9bd4649590e28d8a497afb68bd"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd6f05f3e237ed6b3949464e7679e55843645fe0fe8d3b33277c321386836f6a"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:760f8a0aeb43ceeff1e536859e071a72e91075d4d37d51470812c4f49e682702"}, - {file = "pydantic_core-2.6.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a1ad48e77935d7dbbc2d75aeb638abbfbd0df0cfacf774dbe98d52271468f00c"}, - {file = "pydantic_core-2.6.1-cp37-none-win32.whl", hash = "sha256:153a5dd24c09ab7544beda967366afbaae8350b327a4ebd5807ed45ec791baa0"}, - {file = "pydantic_core-2.6.1-cp37-none-win_amd64.whl", hash = "sha256:cc7fc3e81b4ea6bce7e0e1d9797f496e957c5e66adf483f89afdce2d81d19986"}, - {file = "pydantic_core-2.6.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:5482d692ae37857695feccb179022728b275b7bfcc1c85bcdf7b556e76bffcd8"}, - {file = "pydantic_core-2.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:45d248c3c5c5c23a8d048cfdebc8151ae7b32a6dc6d68fbca995521e54692207"}, - {file = "pydantic_core-2.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6dd6c9f47e26779bf1f7da4d6ccd60f66973e63b0a143438f1e20bae296c3fde"}, - {file = "pydantic_core-2.6.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:55701608e60418a423db2486b5c64d790f86eb78a11b9077efb6302c50e62564"}, - {file = "pydantic_core-2.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:420a76a62dd20a6ef08445abf7cf04dcd8a845a5bb15932c2e88a8e518c70d43"}, - {file = "pydantic_core-2.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5f253d20314e53ba0fb2b95541b6ed23f44fbcd927fe7674de341545c3327c3d"}, - {file = "pydantic_core-2.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5127b811c6a26deb85f5b17a06c26c28ce204e51e0a963b75bdf8612b22546d"}, - {file = "pydantic_core-2.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:51ffa985b874ca7d0dc199bb75c67b77907379291c91532a9e2d981f7b681527"}, - {file = "pydantic_core-2.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4902300e763a2fcc49ae14366493ef1fdbd3c7128b9acf37aef505f671aa681f"}, - {file = "pydantic_core-2.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e1c69334bb843c9bff98f52a1fa6c06420081a561fcecb03c6b9376960bd7de2"}, - {file = "pydantic_core-2.6.1-cp38-none-win32.whl", hash = "sha256:e84812b1ca989b2e9f4913d7b75ae0eece2a90154de35b4c5411ad640bfd387c"}, - {file = "pydantic_core-2.6.1-cp38-none-win_amd64.whl", hash = "sha256:775098e3629a959dfec8444667a53e0916839e9fbf6b55e07d6e2aadde006400"}, - {file = "pydantic_core-2.6.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a32ed5a794918a61bf77b967c197eb78f31ad4e3145860193dc381bde040717e"}, - {file = "pydantic_core-2.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:66eda8ac48ac33e9e5c6541c8e30c702924b70a6f2e9732b74230d9b2dd35fb6"}, - {file = "pydantic_core-2.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb5131d75d69b0547ef9a8f46f7b94857411c9badcdd5092de61a3b4943f08c7"}, - {file = "pydantic_core-2.6.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e850f3242d7836a5e15453f798d8569b9754350c8e184ba32d102c515dd507"}, - {file = "pydantic_core-2.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f4327fa6a1ac3da62b27d43bb0f27657ed4e601b141ecbfcf8523814b6c33b6"}, - {file = "pydantic_core-2.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c7b89b2875b967ad5c3c980bf72773851554f80c2529796e815a10c99295d872"}, - {file = "pydantic_core-2.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78eadd8d7d5cd8c3616e363c394d721437c339feaa4c28404e2eda79add69781"}, - {file = "pydantic_core-2.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17ab25bb24e98b61d120b7248c2b49ea56ce754a050d6b348be42015fcb7aa25"}, - {file = "pydantic_core-2.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6ea8dd2854fe6cee5ea0d60304ee7877dffe487cf118f221e85029269dd1235d"}, - {file = "pydantic_core-2.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9bf3ba6b4878ee692f6e24230801f682807fd97356bc2064f630fc0a2ad2ead6"}, - {file = "pydantic_core-2.6.1-cp39-none-win32.whl", hash = "sha256:b974d65692333931b4c7f730e7a3135ff854a1e5384bc260de3327ea364c835a"}, - {file = "pydantic_core-2.6.1-cp39-none-win_amd64.whl", hash = "sha256:f34f26d8a5f1a45366189ec30a57f43b21e2172d0d3b62822638dd885cc8eaab"}, - {file = "pydantic_core-2.6.1-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:f7ec4c6edafa3f0eb1aa461e31ea263736cc541b2459dddfbda7085b30844801"}, - {file = "pydantic_core-2.6.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3679b9a1f41eb1b699e9556f91281d78c416cdc59ae90d5733fbe2017f1effe9"}, - {file = "pydantic_core-2.6.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ff36f945342086ee917d4219dd0e59660a2dfcdb86a07696c2791f5d59c07d"}, - {file = "pydantic_core-2.6.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:734864605d722a6f8db3b9c96371710f7cb591fbfca40cfeaedf5b67df282438"}, - {file = "pydantic_core-2.6.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7188359b95a2b1aef5744a2ee6af2d9cfc733dd823f8840f4c896129477a172b"}, - {file = "pydantic_core-2.6.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:382d40843ae759d43ef65b67dec713390f9417135c1dd730afbf03cf2f450f45"}, - {file = "pydantic_core-2.6.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4525b8498d362e4e324e3e175239b364768f52bd3563ac4ef9750160f5789de8"}, - {file = "pydantic_core-2.6.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e55514a022c768cccf07a675d20d07b847980dcd9250f6b516a86bab5612fc01"}, - {file = "pydantic_core-2.6.1-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:34734d486d059f0f6f5bfa9ba4a41449f666e2abbde002e9fa8b050bc50e3347"}, - {file = "pydantic_core-2.6.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a809498dceb0cd1cd1e57a2bfdc70ea82f424776e0196f4d63c4b6fcdaeb5aab"}, - {file = "pydantic_core-2.6.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:588a5ffd8bbf1b2230611ed1b45221adcf05b981037b2f853b5f20465849b5c1"}, - {file = "pydantic_core-2.6.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:26b81017aeae0d96f776fbce34a3a763d26ac575d8ad3f1202bdfdd2b935954b"}, - {file = "pydantic_core-2.6.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7ddaa2c3c66682f0ff4ebc8c85ef2d8305f32deba79416464c47c93d94ca3740"}, - {file = "pydantic_core-2.6.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d6971131de66d1a37293f2e032206b6984b0dec44f568b453dfe89a84a2de0cc"}, - {file = "pydantic_core-2.6.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:200704f6824f8014bdccb1ce57cbd328666e6de4ecd77f0b8ab472cdea9c49ce"}, - {file = "pydantic_core-2.6.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:6916b27072c957947919fb32551f08486562bb8616f2e3db9e4e9c1d83d36886"}, - {file = "pydantic_core-2.6.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:136de286abf53f326b90389aaaca8a8050c2570adfc74afe06ab1c35d5d242bf"}, - {file = "pydantic_core-2.6.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60a238bb4ab09a81a6b25c9a0bb12756cfab2d9f3a7a471f857a179f83da0df6"}, - {file = "pydantic_core-2.6.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2034d9b83a59b3b74b9dbf97ddb99de86c08863c1c33aabf80bc95791c7d50c3"}, - {file = "pydantic_core-2.6.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7c3a2b4d1636446dc71da1e949d2cf9ac1ee691ca63a640b77fce0360b4b75be"}, - {file = "pydantic_core-2.6.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:09e4ebd11a0b333b1fca75c1004c76dc9719f3aaf83ae38c42358754d8a76148"}, - {file = "pydantic_core-2.6.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:a4536d132a8bbd05bf368fb802a264cb9828f6c85e4029a6a3670bc98ba97323"}, - {file = "pydantic_core-2.6.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6221c97d6d58f2370650cfe3d81408901a1951c99960e1df9f6f9f8482d73d08"}, - {file = "pydantic_core-2.6.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4223e8bdad41d846a84cda400cd538e1cdc63d98eb4d41951396bfdb88fd8ce9"}, - {file = "pydantic_core-2.6.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c07cdb2e02733e5f26b9b004a1a8b99814d175f8953fa9f59e4293de2b8e9787"}, - {file = "pydantic_core-2.6.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8714e958d01342d08e520ffec6c1acf66cdec83ce51302f9a1a6efb2f784d0b6"}, - {file = "pydantic_core-2.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f03541c25a77fb5445055e070b69d292c9818a9195ffbfd3962c0ad0da983e8"}, - {file = "pydantic_core-2.6.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:364c13ef48c9e2f8c2ea8ee0da5ea23db5e218f99e796cbf360a2a7cab511439"}, - {file = "pydantic_core-2.6.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:27ba58bbfd1b2b9da45bfe524e680e2bc747a1ca9738ee5aa18d8cbdcc08e5e6"}, - {file = "pydantic_core-2.6.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:92321582e59da185b76b2eca4488ea95e41800672e57107509d32ebf8ad550f8"}, - {file = "pydantic_core-2.6.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2da1d21a4f2675d5b8a749674993a65c0537e2066e7ab7b1a4a54ef0b3ac8efd"}, - {file = "pydantic_core-2.6.1.tar.gz", hash = "sha256:5b4efa68bcfa6f2b93624c6660b6cf4b7b4336d4225afb314254a0ed9c9f4153"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, + {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, + {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, + {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, + {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, + {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, ] [package.dependencies] @@ -1691,30 +1991,49 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.0.3" +version = "2.2.1" description = "Settings management using Pydantic" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.0.3-py3-none-any.whl", hash = "sha256:ddd907b066622bd67603b75e2ff791875540dc485b7307c4fffc015719da8625"}, - {file = "pydantic_settings-2.0.3.tar.gz", hash = "sha256:962dc3672495aad6ae96a4390fac7e593591e144625e5112d359f8f67fb75945"}, + {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, + {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, ] [package.dependencies] -pydantic = ">=2.0.1" +pydantic = ">=2.3.0" python-dotenv = ">=0.21.0" +[package.extras] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] + [[package]] name = "pyflakes" -version = "3.1.0" +version = "3.2.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" files = [ - {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, - {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + [[package]] name = "pyjwkest" version = "1.4.2" @@ -1731,15 +2050,33 @@ pycryptodomex = "*" requests = "*" six = "*" +[[package]] +name = "pyquery" +version = "2.0.0" +description = "A jquery-like library for python" +optional = false +python-versions = "*" +files = [ + {file = "pyquery-2.0.0-py3-none-any.whl", hash = "sha256:8dfc9b4b7c5f877d619bbae74b1898d5743f6ca248cfd5d72b504dd614da312f"}, + {file = "pyquery-2.0.0.tar.gz", hash = "sha256:963e8d4e90262ff6d8dec072ea97285dc374a2f69cad7776f4082abcf6a1d8ae"}, +] + +[package.dependencies] +cssselect = ">=1.2.0" +lxml = ">=2.1" + +[package.extras] +test = ["pytest", "pytest-cov", "requests", "webob", "webtest"] + [[package]] name = "pytest" -version = "7.4.0" +version = "8.1.1" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, + {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, + {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, ] [package.dependencies] @@ -1747,21 +2084,21 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +pluggy = ">=1.4,<2.0" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" -version = "4.1.0" +version = "5.0.0" description = "Pytest plugin for measuring coverage." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, - {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, ] [package.dependencies] @@ -1769,7 +2106,7 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] [[package]] name = "pytest-dotenv" @@ -1787,50 +2124,66 @@ pytest = ">=5.0.0" python-dotenv = ">=0.9.1" [[package]] -name = "pytest-flask" -version = "1.2.0" -description = "A set of py.test fixtures to test Flask applications." +name = "pytest-iam" +version = "0.0.9" +description = "A fully functional OAUTH2 / OpenID Connect (OIDC) server to be used in your testsuite" optional = false -python-versions = ">=3.5" +python-versions = "<4.0,>=3.8" files = [ - {file = "pytest-flask-1.2.0.tar.gz", hash = "sha256:46fde652f77777bf02dc91205aec4ce20cdf2acbbbd66a918ab91f5c14693d3d"}, - {file = "pytest_flask-1.2.0-py3-none-any.whl", hash = "sha256:fe25b39ad0db09c3d1fe728edecf97ced85e774c775db259a6d25f0270a4e7c9"}, + {file = "pytest_iam-0.0.9-py3-none-any.whl", hash = "sha256:ea20832cb51c3be8a8509ad1bf2524db11444186db0ecee94b8418e838fd28c3"}, + {file = "pytest_iam-0.0.9.tar.gz", hash = "sha256:d043f83ebe7aa0ce10ffabf3849e2f42d76fd47ad47ead9c0b4c91ccc108dd8a"}, ] [package.dependencies] -Flask = "*" -pytest = ">=5.2" -Werkzeug = ">=0.7" - -[package.extras] -docs = ["Sphinx", "sphinx-rtd-theme"] +canaille = {version = "<1", extras = ["oidc"]} +faker = ">=21.0.0" +portpicker = ">=1.6.0" +pytest = ">=7.0.0" [[package]] name = "pytest-mock" -version = "3.11.1" +version = "3.14.0" description = "Thin-wrapper around the mock package for easier use with pytest" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"}, - {file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"}, + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, ] [package.dependencies] -pytest = ">=5.0" +pytest = ">=6.2.5" [package.extras] dev = ["pre-commit", "pytest-asyncio", "tox"] +[[package]] +name = "pytest-smtpd" +version = "0.1.0" +description = "An SMTP server for testing built on aiosmtpd" +optional = false +python-versions = "<4,>=3.7" +files = [ + {file = "pytest_smtpd-0.1.0-py3-none-any.whl", hash = "sha256:1249e4d0ab77120eb53bce5123200b94ab6667b52a6cb5c741a3956a254c2dd8"}, + {file = "pytest_smtpd-0.1.0.tar.gz", hash = "sha256:e80cd7818f45192ebd8ec517a38d20098378e397e664ec0649da5b98a6e3ff09"}, +] + +[package.dependencies] +pytest = "*" +smtpdfix = "*" + +[package.extras] +dev = ["flake8", "isort", "mypy", "tox"] + [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -1838,27 +2191,44 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "1.0.0" +version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.8" files = [ - {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, - {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, ] [package.extras] cli = ["click (>=5.0)"] +[[package]] +name = "python-slugify" +version = "8.0.4" +description = "A Python slugify application that also handles Unicode" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"}, + {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"}, +] + +[package.dependencies] +text-unidecode = ">=1.3" + +[package.extras] +unidecode = ["Unidecode (>=1.1.1)"] + [[package]] name = "pytz" -version = "2023.3" +version = "2024.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, - {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] [[package]] @@ -1886,6 +2256,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1922,17 +2293,17 @@ files = [ [[package]] name = "redis" -version = "4.4.4" +version = "5.0.3" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.4.4-py3-none-any.whl", hash = "sha256:da92a39fec86438d3f1e2a1db33c312985806954fe860120b582a8430e231d8f"}, - {file = "redis-4.4.4.tar.gz", hash = "sha256:68226f7ede928db8302f29ab088a157f41061fa946b7ae865452b6d7838bbffb"}, + {file = "redis-5.0.3-py3-none-any.whl", hash = "sha256:5da9b8fe9e1254293756c16c008e8620b3d15fcc6dde6babde9541850e72a32d"}, + {file = "redis-5.0.3.tar.gz", hash = "sha256:4973bae7444c0fbed64a06b87446f79361cb7e4ec1538c022d696ed7a5015580"}, ] [package.dependencies] -async-timeout = ">=4.0.2" +async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -1961,19 +2332,19 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "setuptools" -version = "68.1.2" +version = "69.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, - {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, + {file = "setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c"}, + {file = "setuptools-69.2.0.tar.gz", hash = "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -1986,115 +2357,347 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "smtpdfix" +version = "0.5.1" +description = "A SMTP server for use as a pytest fixture that implements encryption and authentication for testing." +optional = false +python-versions = ">=3.7" +files = [ + {file = "smtpdfix-0.5.1-py3-none-any.whl", hash = "sha256:fab6c8f9060d1dca4ac6f338dae00f487e59de69a2133e58f03f0fe7ff295f52"}, + {file = "smtpdfix-0.5.1.tar.gz", hash = "sha256:f3cda2d13e84c9267a8f13a0a0cd75314fa16b8d577ca8c30e1523797eeabe9e"}, +] + +[package.dependencies] +aiosmtpd = "*" +cryptography = "*" +portpicker = "*" +pytest = "*" + +[package.extras] +dev = ["flake8", "isort", "pytest-asyncio", "pytest-cov", "pytest-timeout", "tox"] +typing = ["mypy"] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +optional = false +python-versions = "*" +files = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] + [[package]] name = "soupsieve" -version = "2.4.1" +version = "2.5" description = "A modern CSS selector implementation for Beautiful Soup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, +] + +[[package]] +name = "sphinx" +version = "7.1.2" +description = "Python documentation generator" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sphinx-7.1.2-py3-none-any.whl", hash = "sha256:d170a81825b2fcacb6dfd5a0d7f578a053e45d3f2b153fecc948c37344eb4cbe"}, + {file = "sphinx-7.1.2.tar.gz", hash = "sha256:780f4d32f1d7d1126576e0e5ecc19dc32ab76cd24e950228dcf7b1f6d3d9e22f"}, +] + +[package.dependencies] +alabaster = ">=0.7,<0.8" +babel = ">=2.9" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.18.1,<0.21" +imagesize = ">=1.3" +importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.0" +packaging = ">=21.0" +Pygments = ">=2.13" +requests = ">=2.25.0" +snowballstemmer = ">=2.0" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] +test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"] + +[[package]] +name = "sphinx-enum-extend" +version = "0.1.3" +description = "Spinx plugin for documenting enum-extend.AutoEnum" +optional = false +python-versions = ">=3.4.0" +files = [ + {file = "sphinx-enum-extend-0.1.3.tar.gz", hash = "sha256:c0a73ebb106aae3562247244a759c55c731d2204026648501440ceef4166ff97"}, + {file = "sphinx_enum_extend-0.1.3-py3-none-any.whl", hash = "sha256:4f7747119beca6d2408c819b08cadabd26136612bdc9e7aa0f2f8dcd646d689b"}, +] + +[package.dependencies] +enum-extend = ">=0.1.1" + +[[package]] +name = "sphinx-issues" +version = "4.0.0" +description = "A Sphinx extension for linking to your project's issue tracker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sphinx_issues-4.0.0-py3-none-any.whl", hash = "sha256:ce1ee87682eb8e661d2d500672756916f113ac0a37da3678aa474b7d8ce3d039"}, + {file = "sphinx_issues-4.0.0.tar.gz", hash = "sha256:5b8fcc229ffaeaef53fef0dca88dc89bc14b4aa81f221d9682a64ecced02e25d"}, +] + +[package.dependencies] +sphinx = "*" + +[package.extras] +dev = ["pre-commit (>=3.6,<4.0)", "sphinx-issues[tests]", "tox"] +tests = ["pytest"] + +[[package]] +name = "sphinx-rtd-theme" +version = "2.0.0" +description = "Read the Docs theme for Sphinx" +optional = false +python-versions = ">=3.6" +files = [ + {file = "sphinx_rtd_theme-2.0.0-py2.py3-none-any.whl", hash = "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586"}, + {file = "sphinx_rtd_theme-2.0.0.tar.gz", hash = "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b"}, +] + +[package.dependencies] +docutils = "<0.21" +sphinx = ">=5,<8" +sphinxcontrib-jquery = ">=4,<5" + +[package.extras] +dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "1.0.4" +description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, + {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "1.0.2" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +optional = false +python-versions = ">=3.5" +files = [ + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.0.1" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"}, + {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["html5lib", "pytest"] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +description = "Extension to include jQuery on newer Sphinx releases" +optional = false +python-versions = ">=2.7" +files = [ + {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, + {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, +] + +[package.dependencies] +Sphinx = ">=1.8" + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +optional = false +python-versions = ">=3.5" files = [ - {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"}, - {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"}, + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] +[package.extras] +test = ["flake8", "mypy", "pytest"] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.3" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +optional = false +python-versions = ">=3.5" +files = [ + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "1.1.5" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +optional = false +python-versions = ">=3.5" +files = [ + {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, + {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, +] + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + [[package]] name = "sqlalchemy" -version = "1.4.31" +version = "1.4.52" description = "Database Abstraction Library" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.31-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c3abc34fed19fdeaead0ced8cf56dd121f08198008c033596aa6aae7cc58f59f"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8d0949b11681380b4a50ac3cd075e4816afe9fa4a8c8ae006c1ca26f0fa40ad8"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27m-win32.whl", hash = "sha256:f3b7ec97e68b68cb1f9ddb82eda17b418f19a034fa8380a0ac04e8fe01532875"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27m-win_amd64.whl", hash = "sha256:81f2dd355b57770fdf292b54f3e0a9823ec27a543f947fa2eb4ec0df44f35f0d"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4ad31cec8b49fd718470328ad9711f4dc703507d434fd45461096da0a7135ee0"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:05fa14f279d43df68964ad066f653193187909950aa0163320b728edfc400167"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dccff41478050e823271642837b904d5f9bda3f5cf7d371ce163f00a694118d6"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57205844f246bab9b666a32f59b046add8995c665d9ecb2b7b837b087df90639"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8210090a816d48a4291a47462bac750e3bc5c2442e6d64f7b8137a7c3f9ac5"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-win32.whl", hash = "sha256:2e216c13ecc7fcdcbb86bb3225425b3ed338e43a8810c7089ddb472676124b9b"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-win_amd64.whl", hash = "sha256:e3a86b59b6227ef72ffc10d4b23f0fe994bef64d4667eab4fb8cd43de4223bec"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2fd4d3ca64c41dae31228b80556ab55b6489275fb204827f6560b65f95692cf3"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f22c040d196f841168b1456e77c30a18a3dc16b336ddbc5a24ce01ab4e95ae0"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c0c7171aa5a57e522a04a31b84798b6c926234cb559c0939840c3235cf068813"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d046a9aeba9bc53e88a41e58beb72b6205abb9a20f6c136161adf9128e589db5"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-win32.whl", hash = "sha256:d86132922531f0dc5a4f424c7580a472a924dd737602638e704841c9cb24aea2"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-win_amd64.whl", hash = "sha256:ca68c52e3cae491ace2bf39b35fef4ce26c192fd70b4cd90f040d419f70893b5"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:cf2cd387409b12d0a8b801610d6336ee7d24043b6dd965950eaec09b73e7262f"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb4b15fb1f0aafa65cbdc62d3c2078bea1ceecbfccc9a1f23a2113c9ac1191fa"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c317ddd7c586af350a6aef22b891e84b16bff1a27886ed5b30f15c1ed59caeaa"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c7ed6c69debaf6198fadb1c16ae1253a29a7670bbf0646f92582eb465a0b999"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-win32.whl", hash = "sha256:6a01ec49ca54ce03bc14e10de55dfc64187a2194b3b0e5ac0fdbe9b24767e79e"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-win_amd64.whl", hash = "sha256:330eb45395874cc7787214fdd4489e2afb931bc49e0a7a8f9cd56d6e9c5b1639"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:5e9c7b3567edbc2183607f7d9f3e7e89355b8f8984eec4d2cd1e1513c8f7b43f"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de85c26a5a1c72e695ab0454e92f60213b4459b8d7c502e0be7a6369690eeb1a"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:975f5c0793892c634c4920057da0de3a48bbbbd0a5c86f5fcf2f2fedf41b76da"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5c20c8415173b119762b6110af64448adccd4d11f273fb9f718a9865b88a99c"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-win32.whl", hash = "sha256:b35dca159c1c9fa8a5f9005e42133eed82705bf8e243da371a5e5826440e65ca"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-win_amd64.whl", hash = "sha256:b7b20c88873675903d6438d8b33fba027997193e274b9367421e610d9da76c08"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:85e4c244e1de056d48dae466e9baf9437980c19fcde493e0db1a0a986e6d75b4"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79e73d5ee24196d3057340e356e6254af4d10e1fc22d3207ea8342fc5ffb977"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:15a03261aa1e68f208e71ae3cd845b00063d242cbf8c87348a0c2c0fc6e1f2ac"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ddc5e5ccc0160e7ad190e5c61eb57560f38559e22586955f205e537cda26034"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-win32.whl", hash = "sha256:289465162b1fa1e7a982f8abe59d26a8331211cad4942e8031d2b7db1f75e649"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-win_amd64.whl", hash = "sha256:9e4fb2895b83993831ba2401b6404de953fdbfa9d7d4fa6a4756294a83bbc94f"}, - {file = "SQLAlchemy-1.4.31.tar.gz", hash = "sha256:582b59d1e5780a447aada22b461e50b404a9dc05768da1d87368ad8190468418"}, + {file = "SQLAlchemy-1.4.52-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:f68016f9a5713684c1507cc37133c28035f29925c75c0df2f9d0f7571e23720a"}, + {file = "SQLAlchemy-1.4.52-cp310-cp310-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24bb0f81fbbb13d737b7f76d1821ec0b117ce8cbb8ee5e8641ad2de41aa916d3"}, + {file = "SQLAlchemy-1.4.52-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e93983cc0d2edae253b3f2141b0a3fb07e41c76cd79c2ad743fc27eb79c3f6db"}, + {file = "SQLAlchemy-1.4.52-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:84e10772cfc333eb08d0b7ef808cd76e4a9a30a725fb62a0495877a57ee41d81"}, + {file = "SQLAlchemy-1.4.52-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:427988398d2902de042093d17f2b9619a5ebc605bf6372f7d70e29bde6736842"}, + {file = "SQLAlchemy-1.4.52-cp310-cp310-win32.whl", hash = "sha256:1296f2cdd6db09b98ceb3c93025f0da4835303b8ac46c15c2136e27ee4d18d94"}, + {file = "SQLAlchemy-1.4.52-cp310-cp310-win_amd64.whl", hash = "sha256:80e7f697bccc56ac6eac9e2df5c98b47de57e7006d2e46e1a3c17c546254f6ef"}, + {file = "SQLAlchemy-1.4.52-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2f251af4c75a675ea42766880ff430ac33291c8d0057acca79710f9e5a77383d"}, + {file = "SQLAlchemy-1.4.52-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb8f9e4c4718f111d7b530c4e6fb4d28f9f110eb82e7961412955b3875b66de0"}, + {file = "SQLAlchemy-1.4.52-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afb1672b57f58c0318ad2cff80b384e816735ffc7e848d8aa51e0b0fc2f4b7bb"}, + {file = "SQLAlchemy-1.4.52-cp311-cp311-win32.whl", hash = "sha256:6e41cb5cda641f3754568d2ed8962f772a7f2b59403b95c60c89f3e0bd25f15e"}, + {file = "SQLAlchemy-1.4.52-cp311-cp311-win_amd64.whl", hash = "sha256:5bed4f8c3b69779de9d99eb03fd9ab67a850d74ab0243d1be9d4080e77b6af12"}, + {file = "SQLAlchemy-1.4.52-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:49e3772eb3380ac88d35495843daf3c03f094b713e66c7d017e322144a5c6b7c"}, + {file = "SQLAlchemy-1.4.52-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:618827c1a1c243d2540314c6e100aee7af09a709bd005bae971686fab6723554"}, + {file = "SQLAlchemy-1.4.52-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de9acf369aaadb71a725b7e83a5ef40ca3de1cf4cdc93fa847df6b12d3cd924b"}, + {file = "SQLAlchemy-1.4.52-cp312-cp312-win32.whl", hash = "sha256:763bd97c4ebc74136ecf3526b34808c58945023a59927b416acebcd68d1fc126"}, + {file = "SQLAlchemy-1.4.52-cp312-cp312-win_amd64.whl", hash = "sha256:f12aaf94f4d9679ca475975578739e12cc5b461172e04d66f7a3c39dd14ffc64"}, + {file = "SQLAlchemy-1.4.52-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:853fcfd1f54224ea7aabcf34b227d2b64a08cbac116ecf376907968b29b8e763"}, + {file = "SQLAlchemy-1.4.52-cp36-cp36m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f98dbb8fcc6d1c03ae8ec735d3c62110949a3b8bc6e215053aa27096857afb45"}, + {file = "SQLAlchemy-1.4.52-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e135fff2e84103bc15c07edd8569612ce317d64bdb391f49ce57124a73f45c5"}, + {file = "SQLAlchemy-1.4.52-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b5de6af8852500d01398f5047d62ca3431d1e29a331d0b56c3e14cb03f8094c"}, + {file = "SQLAlchemy-1.4.52-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3491c85df263a5c2157c594f54a1a9c72265b75d3777e61ee13c556d9e43ffc9"}, + {file = "SQLAlchemy-1.4.52-cp36-cp36m-win32.whl", hash = "sha256:427c282dd0deba1f07bcbf499cbcc9fe9a626743f5d4989bfdfd3ed3513003dd"}, + {file = "SQLAlchemy-1.4.52-cp36-cp36m-win_amd64.whl", hash = "sha256:ca5ce82b11731492204cff8845c5e8ca1a4bd1ade85e3b8fcf86e7601bfc6a39"}, + {file = "SQLAlchemy-1.4.52-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:29d4247313abb2015f8979137fe65f4eaceead5247d39603cc4b4a610936cd2b"}, + {file = "SQLAlchemy-1.4.52-cp37-cp37m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a752bff4796bf22803d052d4841ebc3c55c26fb65551f2c96e90ac7c62be763a"}, + {file = "SQLAlchemy-1.4.52-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7ea11727feb2861deaa293c7971a4df57ef1c90e42cb53f0da40c3468388000"}, + {file = "SQLAlchemy-1.4.52-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d913f8953e098ca931ad7f58797f91deed26b435ec3756478b75c608aa80d139"}, + {file = "SQLAlchemy-1.4.52-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a251146b921725547ea1735b060a11e1be705017b568c9f8067ca61e6ef85f20"}, + {file = "SQLAlchemy-1.4.52-cp37-cp37m-win32.whl", hash = "sha256:1f8e1c6a6b7f8e9407ad9afc0ea41c1f65225ce505b79bc0342159de9c890782"}, + {file = "SQLAlchemy-1.4.52-cp37-cp37m-win_amd64.whl", hash = "sha256:346ed50cb2c30f5d7a03d888e25744154ceac6f0e6e1ab3bc7b5b77138d37710"}, + {file = "SQLAlchemy-1.4.52-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:4dae6001457d4497736e3bc422165f107ecdd70b0d651fab7f731276e8b9e12d"}, + {file = "SQLAlchemy-1.4.52-cp38-cp38-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5d2e08d79f5bf250afb4a61426b41026e448da446b55e4770c2afdc1e200fce"}, + {file = "SQLAlchemy-1.4.52-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bbce5dd7c7735e01d24f5a60177f3e589078f83c8a29e124a6521b76d825b85"}, + {file = "SQLAlchemy-1.4.52-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bdb7b4d889631a3b2a81a3347c4c3f031812eb4adeaa3ee4e6b0d028ad1852b5"}, + {file = "SQLAlchemy-1.4.52-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c294ae4e6bbd060dd79e2bd5bba8b6274d08ffd65b58d106394cb6abbf35cf45"}, + {file = "SQLAlchemy-1.4.52-cp38-cp38-win32.whl", hash = "sha256:bcdfb4b47fe04967669874fb1ce782a006756fdbebe7263f6a000e1db969120e"}, + {file = "SQLAlchemy-1.4.52-cp38-cp38-win_amd64.whl", hash = "sha256:7d0dbc56cb6af5088f3658982d3d8c1d6a82691f31f7b0da682c7b98fa914e91"}, + {file = "SQLAlchemy-1.4.52-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:a551d5f3dc63f096ed41775ceec72fdf91462bb95abdc179010dc95a93957800"}, + {file = "SQLAlchemy-1.4.52-cp39-cp39-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ab773f9ad848118df7a9bbabca53e3f1002387cdbb6ee81693db808b82aaab0"}, + {file = "SQLAlchemy-1.4.52-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2de46f5d5396d5331127cfa71f837cca945f9a2b04f7cb5a01949cf676db7d1"}, + {file = "SQLAlchemy-1.4.52-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7027be7930a90d18a386b25ee8af30514c61f3852c7268899f23fdfbd3107181"}, + {file = "SQLAlchemy-1.4.52-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99224d621affbb3c1a4f72b631f8393045f4ce647dd3262f12fe3576918f8bf3"}, + {file = "SQLAlchemy-1.4.52-cp39-cp39-win32.whl", hash = "sha256:c124912fd4e1bb9d1e7dc193ed482a9f812769cb1e69363ab68e01801e859821"}, + {file = "SQLAlchemy-1.4.52-cp39-cp39-win_amd64.whl", hash = "sha256:2c286fab42e49db23c46ab02479f328b8bdb837d3e281cae546cc4085c83b680"}, + {file = "SQLAlchemy-1.4.52.tar.gz", hash = "sha256:80e63bbdc5217dad3485059bdf6f65a7d43f33c8bde619df5c220edf03d87296"}, ] [package.dependencies] greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} [package.extras] -aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing-extensions (!=3.10.0.1)"] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] mysql-connector = ["mysql-connector-python"] -oracle = ["cx-oracle (>=7)", "cx-oracle (>=7,<8)"] +oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] postgresql-psycopg2binary = ["psycopg2-binary"] postgresql-psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql", "pymysql (<1)"] -sqlcipher = ["sqlcipher3-binary"] +sqlcipher = ["sqlcipher3_binary"] [[package]] name = "sqlalchemy-json" -version = "0.4.0" +version = "0.7.0" description = "JSON type with nested change tracking for SQLAlchemy" optional = false -python-versions = "*" +python-versions = ">= 3.6" files = [ - {file = "sqlalchemy-json-0.4.0.tar.gz", hash = "sha256:d8e72cac50724a17cc137c98bec5cb5990e9f1e8fc3eb30dd225fb47c087ea27"}, - {file = "sqlalchemy_json-0.4.0-py2.py3-none-any.whl", hash = "sha256:0f52f24301aa3b5ea240b622facc489eff2e7bfddde931ba988bfabc306b1778"}, + {file = "sqlalchemy-json-0.7.0.tar.gz", hash = "sha256:620d0b26f648f21a8fa9127df66f55f83a5ab4ae010e5397a5c6989a08238561"}, + {file = "sqlalchemy_json-0.7.0-py3-none-any.whl", hash = "sha256:27881d662ca18363a4ac28175cc47ea2a6f2bef997ae1159c151026b741818e6"}, ] [package.dependencies] -six = "*" sqlalchemy = ">=0.7" +[package.extras] +dev = ["pytest"] + [[package]] name = "sqlalchemy-utils" -version = "0.38.1" +version = "0.41.2" description = "Various utility functions for SQLAlchemy." optional = false -python-versions = "~=3.4" +python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-Utils-0.38.1.tar.gz", hash = "sha256:7bed3396f4103dc8663f05751065284c2e3d529f20ebd4a80847e1281fccb1fe"}, - {file = "SQLAlchemy_Utils-0.38.1-py3-none-any.whl", hash = "sha256:a484ccfdc7f9298df49d2558a5309691e5e3e51c815a23a33b3355989176cb3e"}, + {file = "SQLAlchemy-Utils-0.41.2.tar.gz", hash = "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990"}, + {file = "SQLAlchemy_Utils-0.41.2-py3-none-any.whl", hash = "sha256:85cf3842da2bf060760f955f8467b87983fb2e30f1764fd0e24a48307dc8ec6e"}, ] [package.dependencies] -six = "*" -SQLAlchemy = ">=1.0" +SQLAlchemy = ">=1.3" [package.extras] arrow = ["arrow (>=0.3.4)"] @@ -2105,11 +2708,22 @@ intervals = ["intervals (>=0.7.1)"] password = ["passlib (>=1.6,<2.0)"] pendulum = ["pendulum (>=2.0.5)"] phone = ["phonenumbers (>=5.9.2)"] -test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "mock (==2.0.0)", "pg8000 (>=1.12.4)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] -test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "mock (==2.0.0)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] timezone = ["python-dateutil"] url = ["furl (>=0.4.1)"] +[[package]] +name = "text-unidecode" +version = "1.3" +description = "The most basic Text::Unidecode port" +optional = false +python-versions = "*" +files = [ + {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, + {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, +] + [[package]] name = "tomli" version = "2.0.1" @@ -2123,98 +2737,98 @@ files = [ [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.10.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, + {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, ] [[package]] name = "tzdata" -version = "2023.3" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] name = "urllib3" -version = "2.0.4" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, - {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "vine" -version = "5.0.0" -description = "Promises, promises, promises." +version = "5.1.0" +description = "Python promises." optional = false python-versions = ">=3.6" files = [ - {file = "vine-5.0.0-py2.py3-none-any.whl", hash = "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30"}, - {file = "vine-5.0.0.tar.gz", hash = "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"}, + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, ] [[package]] name = "virtualenv" -version = "20.24.3" +version = "20.25.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.3-py3-none-any.whl", hash = "sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02"}, - {file = "virtualenv-20.24.3.tar.gz", hash = "sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc"}, + {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, + {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<4" +platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "waitress" -version = "2.1.2" +version = "3.0.0" description = "Waitress WSGI server" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "waitress-2.1.2-py3-none-any.whl", hash = "sha256:7500c9625927c8ec60f54377d590f67b30c8e70ef4b8894214ac6e4cad233d2a"}, - {file = "waitress-2.1.2.tar.gz", hash = "sha256:780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba"}, + {file = "waitress-3.0.0-py3-none-any.whl", hash = "sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669"}, + {file = "waitress-3.0.0.tar.gz", hash = "sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1"}, ] [package.extras] docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.9)"] -testing = ["coverage (>=5.0)", "pytest", "pytest-cover"] +testing = ["coverage (>=5.0)", "pytest", "pytest-cov"] [[package]] name = "wcwidth" -version = "0.2.6" +version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, - {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] [[package]] @@ -2269,54 +2883,74 @@ tests = ["PasteDeploy", "WSGIProxy2", "coverage", "pyquery", "pytest", "pytest-c [[package]] name = "werkzeug" -version = "2.2.3" +version = "3.0.2" description = "The comprehensive WSGI web application library." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.2.3-py3-none-any.whl", hash = "sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612"}, - {file = "Werkzeug-2.2.3.tar.gz", hash = "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe"}, + {file = "werkzeug-3.0.2-py3-none-any.whl", hash = "sha256:3aac3f5da756f93030740bc235d3e09449efcf65f2f55e3602e1d851b8f48795"}, + {file = "werkzeug-3.0.2.tar.gz", hash = "sha256:e39b645a6ac92822588e7b39a692e7828724ceae0b0d702ef96701f90e70128d"}, ] [package.dependencies] MarkupSafe = ">=2.1.1" [package.extras] -watchdog = ["watchdog"] +watchdog = ["watchdog (>=2.3)"] + +[[package]] +name = "wsgidav" +version = "4.3.2" +description = "Generic and extendable WebDAV server based on WSGI" +optional = false +python-versions = "*" +files = [ + {file = "WsgiDAV-4.3.2-py3-none-any.whl", hash = "sha256:9645fdb799332840c3646dddbf0750624166da719285113e5d17c1f2d1ccd40a"}, + {file = "WsgiDAV-4.3.2.tar.gz", hash = "sha256:4c3c24ac01b656a9edcb0014f31717ca8b9a3ec7d7cd9adc39d9ce1b00bfe759"}, +] + +[package.dependencies] +defusedxml = "*" +Jinja2 = "*" +json5 = "*" +PyYAML = "*" + +[package.extras] +pam = ["python-pam"] [[package]] name = "wtforms" -version = "3.0.1" +version = "3.1.2" description = "Form validation and rendering for Python web development." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "WTForms-3.0.1-py3-none-any.whl", hash = "sha256:837f2f0e0ca79481b92884962b914eba4e72b7a2daaf1f939c890ed0124b834b"}, - {file = "WTForms-3.0.1.tar.gz", hash = "sha256:6b351bbb12dd58af57ffef05bc78425d08d1914e0fd68ee14143b7ade023c5bc"}, + {file = "wtforms-3.1.2-py3-none-any.whl", hash = "sha256:bf831c042829c8cdbad74c27575098d541d039b1faa74c771545ecac916f2c07"}, + {file = "wtforms-3.1.2.tar.gz", hash = "sha256:f8d76180d7239c94c6322f7990ae1216dae3659b7aa1cee94b6318bdffb474b9"}, ] [package.dependencies] -MarkupSafe = "*" +markupsafe = "*" [package.extras] email = ["email-validator"] [[package]] name = "zipp" -version = "3.16.2" +version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, - {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "cc1af9cf28e12423b98cd67f7f2171260c9ea720dccda8f613e88c8a838cf29f" +content-hash = "83bdc5f44aac2ddc4e08a7856fb5f8d1a60cf1ecd726cabd34c25619ed3d4780" diff --git a/pyproject.toml b/pyproject.toml index 62819441..cc62512e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,67 +1,127 @@ +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + [tool.poetry] -name = "b3desk" -version = "1.1.6" +version = "1.2.0" description = "Outil de visioconférence pour les agents de l'Education Nationale et de l'Etat en général." authors = ["Your Name "] readme = "README.md" [tool.poetry.dependencies] python = ">=3.8.1,<4.0" -flask-pyoidc = "^3.14.2" -flask-sqlalchemy = "^3.0.3" -flask-uploads = "0.2.1" -flask-migrate = "3.1.0" -gunicorn = "20.1.0" -netaddr = "0.8.0" -sqlalchemy = "1.4.31" -sqlalchemy-json = "0.4.0" -sqlalchemy-utils = "0.38.1" -psycopg2 = "2.9.3" -webdavclient3 = "3.14.6" +celery = "^5.2.7" filetype = "^1.2.0" -flask-babel = "2.0.0" -celery = "5.2.7" -flask = "<2.3" +flask = "^3.0.0" +flask-babel = "^4.0.0" flask-caching = "^2.0.2" -flask-wtf = "^1.1.1" -redis = "4.4.4" +flask-uploads = "0.2.1" +flask-migrate = "^4.0.5" +flask-pyoidc = "^3.14.2" +flask-sqlalchemy = "^3.0.3" +flask-wtf = "^1.2.1" +gunicorn = "21.2.0" +netaddr = "^1.2.1" +psycopg2 = "^2.9.3" +pydantic-settings = "^2.1.0" +python-slugify = "^8.0.4" +redis = "^5.0.1" requests = "^2.27.1" -werkzeug = "<2.3" +sqlalchemy = "^1.4.31" +sqlalchemy-json = "^0.7.0" +sqlalchemy-utils = "^0.41.1" +webdavclient3 = "3.14.6" [tool.poetry.group.dev] optional = true [tool.poetry.group.dev.dependencies] -pytest = "^7.4.0" -pytest-mock = "^3.11.1" +coverage = "^7.2.2" +flake8 = "^7.0.0" Flask-WebTest = "^0.1.3" freezegun = "^1.2.2" -black = "^23.1.0" -flake8 = "^6.0.0" pre-commit = "^3.1.1" -pytest-cov = "^4.1.0" +pytest = "^8.0.0" +pytest-cov = "^5.0.0" pytest-dotenv = "^0.5.2" -pytest-flask = "^1.2.0" -coverage = "^7.2.2" +pytest-iam = "^0.0.9" +pytest-mock = "^3.11.1" +wsgidav = "^4.3.1" +pytest-smtpd = "^0.1.0" +pyquery = "^2.0.0" -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +[tool.poetry.group.doc] +optional = true -[tool.black] -extend-exclude = ''' -( - postgres/data -) -''' +[tool.poetry.group.doc.dependencies] +autodoc-pydantic = "^2.0.1" +myst-parser = "^2.0.0" +sphinx = "^7.0.0" +sphinx-rtd-theme = "^2.0.0" +sphinx-issues = "^4.0.0" [tool.pytest.ini_options] -env_files = ["web.env"] testpaths = "web" +markers = [ + "secure: cloud auth responds with a https url", + "no_scheme: cloud auth responds without any scheme for url", +] -[tool.ruff] +[tool.ruff.lint] ignore = [ "E501", # line too long "E722", # bare expect "E402", # import not at the top of the file ] + +[tool.tox] +legacy_tox_ini = """ +[tox] +isolated_build = true +skipsdist = true +envlist = + style + py38 + py39 + py310 + py311 + coverage + doc + +[testenv] +allowlist_externals = poetry +commands = + poetry install --with dev + poetry run pytest {posargs} + +[testenv:style] +commands = + pip install pre-commit + pre-commit run --all-files + +[testenv:coverage] +commands = + poetry install --with dev + poetry run pytest --cov --cov-report term:skip-covered {posargs} + poetry run coverage html + +[testenv:doc] +commands = + poetry install --with doc + poetry run sphinx-build documentation build/sphinx/html +""" + +[tool.coverage.run] +branch = true + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "raise NotImplementedError", + "except ImportError", +] +partial_branches = [ + "pragma: no branch", + "if app.debug", + "if app.testing", +] diff --git a/web.env.example b/web.env.example index fb61a312..18e510e6 100644 --- a/web.env.example +++ b/web.env.example @@ -1,9 +1,9 @@ # App Configuration -FLASK_APP=flaskr FLASK_DEBUG=True SECRET_KEY=SomethingNotEntirelySecret TITLE=BBB-Visio -SERVER_FQDN=http://localhost:5000 +SERVER_NAME=localhost:5000 +PREFERRED_URL_SCHEME=http WTF_CSRF_TIME_LIMIT=3600 STATS_URL=http://localhost:5000/static/local/stats.csv @@ -43,7 +43,7 @@ OIDC_USERINFO_HTTP_METHOD=POST OIDC_REDIRECT_URI=http://localhost:5000/oidc_callback # Attendee OIDC Configuration (back to default if empty) -OIDC_ATTENDEE_ENABLED= +OIDC_ATTENDEE_ENABLED=true OIDC_ATTENDEE_ISSUER= OIDC_ATTENDEE_CLIENT_ID= OIDC_ATTENDEE_CLIENT_SECRET= @@ -62,9 +62,9 @@ SMTP_HOST=0.0.0.0 SMTP_PORT=1025 SMTP_USERNAME= SMTP_PASSWORD= -SMTP_SSL= +SMTP_SSL=false EMAIL_WHITELIST=.*@(.*\.|)gouv\.fr -RIE_NETWORK_IPS=192.168.0.0/16,172.16.0.0/12,192.168.1.97/16,127.0.0.0/16 +RIE_NETWORK_IPS=192.168.0.0/16,172.16.0.0/12,127.0.0.0/16 BIGBLUEBUTTON_ANALYTICS_CALLBACK_URL=https://bbb-analytics-staging.osc-fr1.scalingo.io/v1/post_events # Nextcloud and meeting Files connection configuration @@ -76,6 +76,7 @@ TMP_DOWNLOAD_DIR=/tmp/download/ # used when retrieving files from remote Nextcl MAX_SIZE_UPLOAD=20000000 TIME_FORMAT=%Y-%m-%d UPLOAD_DIR=/tmp/b3desk/ # used by dropzone to upload files +FORCE_HTTPS_ON_EXTERNAL_URLS=off NC_LOGIN_API_URL=http://tokenmock:80/index.php # nextcloud token provider endpoint (currently pointing toward related service in docker network) NC_LOGIN_API_KEY=MY-TOTALLY-COOL-API-KEY # SHARED between web and tokenmock services as nextcloud credentials NEXTCLOUD_SESSIONTOKEN_KEY=megatokengeneratedatleast64long # SHARED between nextcloud (sessiontoken app) and tokenmock services @@ -83,3 +84,6 @@ REDIS_URL=broker:6379 # SHARED between worker and web services, used for backgr # Feature flags FILE_SHARING=on + +MATOMO_URL= +MATOMO_SITE_ID= diff --git a/web/Dockerfile b/web/Dockerfile index 1e2387c7..40c9d373 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8-bullseye +FROM python:3.11-bullseye # Install. RUN \ @@ -13,8 +13,7 @@ COPY misc/wsgi.py misc/gunicorn.py misc/run_webserver.sh /opt/bbb-visio/ COPY misc/delete_uploaded_files.cron /etc/cron.d/delete_uploaded_files RUN chmod u+x /opt/bbb-visio/run_webserver.sh COPY migrations /opt/bbb-visio/migrations -COPY instance/config.py /opt/bbb-visio/instance/config.py -COPY flaskr /opt/bbb-visio/flaskr +COPY b3desk /opt/bbb-visio/b3desk WORKDIR /opt/bbb-visio/ ENTRYPOINT ["/opt/bbb-visio/run_webserver.sh"] diff --git a/web/Dockerfile-celery b/web/Dockerfile-celery index 43062dda..6d823a9d 100644 --- a/web/Dockerfile-celery +++ b/web/Dockerfile-celery @@ -1,4 +1,4 @@ -FROM python:3.8-bullseye +FROM python:3.11-bullseye # Install. RUN \ diff --git a/web/Dockerfile-tests b/web/Dockerfile-tests index 9109ad27..9c4083d8 100644 --- a/web/Dockerfile-tests +++ b/web/Dockerfile-tests @@ -1,4 +1,4 @@ -FROM python:3.8-bullseye +FROM python:3.11-bullseye # Install. RUN \ @@ -11,7 +11,5 @@ RUN pip install -r /tmp/requirements.txt COPY requirements.dev.txt /tmp/requirements.dev.txt RUN pip install -r /tmp/requirements.dev.txt -COPY instance/config.py /opt/bbb-visio/instance/config.py - WORKDIR /opt/bbb-visio ENTRYPOINT ["pytest"] diff --git a/web/b3desk/__init__.py b/web/b3desk/__init__.py new file mode 100644 index 00000000..3bb75fc6 --- /dev/null +++ b/web/b3desk/__init__.py @@ -0,0 +1,258 @@ +# +----------------------------------------------------------------------------+ +# | BBB-VISIO | +# +----------------------------------------------------------------------------+ +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the European Union Public License 1.2 version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. +import logging +import os + +from flask import Flask +from flask import render_template +from flask import request +from flask import url_for +from flask_babel import Babel +from flask_caching import Cache +from flask_migrate import Migrate +from flask_pyoidc import OIDCAuthentication +from flask_wtf.csrf import CSRFError +from flask_wtf.csrf import CSRFProtect +from jinja2 import StrictUndefined + +from b3desk.settings import MainSettings +from b3desk.utils import is_rie + +from .utils import enum_converter +from .utils import model_converter + +__version__ = "1.2.0" + +LANGUAGES = ["en", "fr"] + +babel = Babel() +cache = Cache() +csrf = CSRFProtect() +auth = OIDCAuthentication({"default": None, "attendee": None}) +migrate = Migrate() + + +def setup_configuration(app, config=None): + if config: + app.config.from_mapping(config) + + config_obj = MainSettings.model_validate(config or {}) + app.config.from_object(config_obj) + + +def setup_celery(app): + from b3desk.tasks import celery + + celery.conf.task_always_eager = app.testing + + +def setup_cache(app): + if app.config.get("CACHE_TYPE"): + config = None + + elif app.config.get("REDIS_URL"): + host, port = app.config.get("REDIS_URL").split(":") + config = { + "CACHE_TYPE": "RedisCache", + "CACHE_REDIS_HOST": host, + "CACHE_REDIS_PORT": port, + } + + else: + config = { + "CACHE_TYPE": "FileSystemCache", + "CACHE_DIR": "/tmp/flask-caching", + } + + cache.init_app(app, config=config) + + +def setup_logging(app, gunicorn_logging=False): + if gunicorn_logging: + gunicorn_logger = logging.getLogger("gunicorn.error") + app.logger.handlers = gunicorn_logger.handlers + app.logger.setLevel(gunicorn_logger.level) + + +def setup_i18n(app): + from flask import session + + def locale_selector(): + if request.args.get("lang"): + session["lang"] = request.args["lang"] + return session.get("lang", "fr") + + babel.init_app(app, locale_selector=locale_selector) + + +def setup_csrf(app): + csrf.init_app(app) + + @app.errorhandler(CSRFError) + def bad_request(error): + app.logger.warning(f"CSRF Error: {error}") + return render_template("errors/400.html", error=error), 400 + + +def setup_database(app): + from .models import db + + db.init_app(app) + migrate.init_app(app, db, compare_type=True) + + +def setup_jinja(app): + from b3desk.models.roles import Role + from b3desk.session import get_current_user + from b3desk.session import has_user_session + + if app.debug or app.testing: + app.jinja_env.undefined = StrictUndefined + + @app.context_processor + def global_processor(): + if has_user_session(): + user = get_current_user() + session_dict = { + "user": user, + "fullname": user.fullname, + } + else: + session_dict = { + "user": None, + "fullname": "", + } + + return { + "config": app.config, + "beta": app.config["BETA"], + "documentation_link": app.config["DOCUMENTATION_LINK"], + "is_rie": is_rie(), + "version": __version__, + "LANGUAGES": LANGUAGES, + "Role": Role, + **app.config["WORDINGS"], + **session_dict, + } + + +def setup_flask(app): + with app.app_context(): + from b3desk.models.meetings import Meeting + from b3desk.models.roles import Role + from b3desk.models.users import User + + for model in (Meeting, User): + app.url_map.converters[model.__name__.lower()] = model_converter(model) + + for enum in (Role,): + app.url_map.converters[enum.__name__.lower()] = enum_converter(enum) + + +def setup_error_pages(app): + @app.errorhandler(400) + def bad_request(error): + return render_template("errors/400.html", error=error), 400 + + @app.errorhandler(403) + def not_authorized(error): + return render_template("errors/403.html", error=error), 403 + + @app.errorhandler(404) + def not_found(error): + return render_template("errors/404.html", error=error), 404 + + @app.errorhandler(500) + def internal_error(error): + return render_template("errors/500.html", error=error), 500 + + +def setup_endpoints(app): + with app.app_context(): + import b3desk.endpoints.api + import b3desk.endpoints.join + import b3desk.endpoints.meeting_files + import b3desk.endpoints.meetings + import b3desk.endpoints.public + + app.register_blueprint(b3desk.endpoints.public.bp) + app.register_blueprint(b3desk.endpoints.join.bp) + app.register_blueprint(b3desk.endpoints.meetings.bp) + app.register_blueprint(b3desk.endpoints.api.bp) + app.register_blueprint(b3desk.endpoints.meeting_files.bp) + + +def setup_oidc(app): + from flask_pyoidc.provider_configuration import ClientMetadata + from flask_pyoidc.provider_configuration import ProviderConfiguration + + with app.app_context(): + logout_url = url_for("public.logout", _external=True) + + user_provider_configuration = ProviderConfiguration( + issuer=app.config["OIDC_ISSUER"], + userinfo_http_method=app.config["OIDC_USERINFO_HTTP_METHOD"], + client_metadata=ClientMetadata( + client_id=app.config["OIDC_CLIENT_ID"], + client_secret=app.config["OIDC_CLIENT_SECRET"], + token_endpoint_auth_method=app.config["OIDC_CLIENT_AUTH_METHOD"], + introspection_endpoint_auth_method=app.config[ + "OIDC_INTROSPECTION_AUTH_METHOD" + ], + post_logout_redirect_uris=[logout_url], + ), + auth_request_params={"scope": app.config["OIDC_SCOPES"]}, + ) + attendee_provider_configuration = ProviderConfiguration( + issuer=app.config.get("OIDC_ATTENDEE_ISSUER"), + userinfo_http_method=app.config.get("OIDC_ATTENDEE_USERINFO_HTTP_METHOD"), + client_metadata=ClientMetadata( + client_id=app.config.get("OIDC_ATTENDEE_CLIENT_ID"), + client_secret=app.config.get("OIDC_ATTENDEE_CLIENT_SECRET"), + token_endpoint_auth_method=app.config.get( + "OIDC_ATTENDEE_CLIENT_AUTH_METHOD" + ), + introspection_endpoint_auth_method=app.config.get( + "OIDC_ATTENDEE_INTROSPECTION_AUTH_METHOD" + ), + post_logout_redirect_uris=[logout_url], + ), + auth_request_params={"scope": app.config["OIDC_ATTENDEE_SCOPES"]}, + ) + + # This is a hack to be able to initialize flask-oidc in two steps + # https://github.com/zamzterz/Flask-pyoidc/issues/171 + auth._provider_configurations = { + "default": user_provider_configuration, + "attendee": attendee_provider_configuration, + } + auth.init_app(app) + + +def create_app(test_config=None, gunicorn_logging=False): + app = Flask(__name__) + setup_configuration(app, test_config) + setup_celery(app) + setup_cache(app) + setup_logging(app, gunicorn_logging) + setup_i18n(app) + setup_csrf(app) + setup_database(app) + setup_jinja(app) + setup_flask(app) + setup_error_pages(app) + setup_endpoints(app) + setup_oidc(app) + + # ensure the instance folder exists + os.makedirs(app.instance_path, exist_ok=True) + + return app diff --git a/web/b3desk/constants.py b/web/b3desk/constants.py new file mode 100644 index 00000000..2e601adf --- /dev/null +++ b/web/b3desk/constants.py @@ -0,0 +1,281 @@ +DEFAULT_EMAIL_WHITELIST = [ + r".*@(.*\.|)ac-aix-marseille\.fr$", + r".*@(.*\.|)ac-amiens\.fr$", + r".*@(.*\.|)ac-besancon\.fr$", + r".*@(.*\.|)ac-bordeaux\.fr$", + r".*@(.*\.|)ac-caen\.fr$", + r".*@(.*\.|)ac-clermont\.fr$", + r".*@(.*\.|)ac-cned\.fr$", + r".*@(.*\.|)ac-corse\.fr$", + r".*@(.*\.|)ac-creteil\.fr$", + r".*@(.*\.|)ac-dijon\.fr$", + r".*@(.*\.|)ac-grenoble\.fr$", + r".*@(.*\.|)ac-guadeloupe\.fr$", + r".*@(.*\.|)ac-guyane\.fr$", + r".*@(.*\.|)ac-lille\.fr$", + r".*@(.*\.|)ac-limoges\.fr$", + r".*@(.*\.|)ac-lyon\.fr$", + r".*@(.*\.|)ac-martinique\.fr$", + r".*@(.*\.|)ac-mayotte\.fr$", + r".*@(.*\.|)ac-montpellier\.fr$", + r".*@(.*\.|)ac-nancy-metz\.fr$", + r".*@(.*\.|)ac-nantes\.fr$", + r".*@(.*\.|)ac-nice\.fr$", + r".*@(.*\.|)ac-normandie\.fr$", + r".*@(.*\.|)ac-noumea\.nc$", + r".*@(.*\.|)ac-orleans-tours\.fr$", + r".*@(.*\.|)ac-paris\.fr$", + r".*@(.*\.|)ac-poitiers\.fr$", + r".*@(.*\.|)ac-polynesie\.pf$", + r".*@(.*\.|)ac-reims\.fr$", + r".*@(.*\.|)ac-rennes\.fr$", + r".*@(.*\.|)ac-reunion\.fr$", + r".*@(.*\.|)ac-rouen\.fr$", + r".*@(.*\.|)ac-spm\.fr$", + r".*@(.*\.|)ac-strasbourg\.fr$", + r".*@(.*\.|)ac-toulouse\.fr$", + r".*@(.*\.|)ac-versailles\.fr$", + r".*@(.*\.|)ac-wf\.wf$", + r".*@(.*\.|)acnusa\.fr$", + r".*@(.*\.|)acte-etat-civil\.fr$", + r".*@(.*\.|)ademe\.fr$", + r".*@(.*\.|)aefe\.fr$", + r".*@(.*\.|)afd\.fr$", + r".*@(.*\.|)agencebio\.org$", + r".*@(.*\.|)agence-regionale-sante\.fr$", + r".*@(.*\.|)anfr\.fr$", + r".*@(.*\.|)anses\.fr$", + r".*@(.*\.|)ansm\.sante\.fr$", + r".*@(.*\.|)aphp\.fr$", + r".*@(.*\.|)apij-justice\.fr$", + r".*@(.*\.|)arcep\.fr$", + r".*@(.*\.|)ars\.sante\.fr$", + r".*@(.*\.|)asi-aeroports\.fr$", + r".*@(.*\.|)asn\.fr$", + r".*@(.*\.|)asp-public\.fr$", + r".*@(.*\.|)assemblee-afe\.fr$", + r".*@(.*\.|)assurance-maladie\.fr$", + r".*@(.*\.|)attachefiscal\.org$", + r".*@(.*\.|)autorite-statistique-publique\.fr$", + r".*@(.*\.|)autoritedelaconcurrence\.fr$", + r".*@(.*\.|)bea\.aero$", + r".*@(.*\.|)biomedecine\.fr$", + r".*@(.*\.|)bnf\.fr$", + r".*@bnu\.fr$", + r".*@(.*\.|)businessfrance\.fr$", + r".*@(.*\.|)cabinet\.education\.fr$", + r".*@(.*\.|)cades\.fr$", + r".*@(.*\.|)ccomptes\.fr$", + r".*@(.*\.|)ccsp\.fr$", + r".*@cea\.fr$", + r".*@(.*\.|)cerema\.fr$", + r".*@(.*\.|)ch-bagneres\.fr$", + r".*@(.*\.|)ch-fidesien\.fr$", + r".*@(.*\.|)ch-lannemezan\.fr$", + r".*@(.*\.|)ch-lourdes\.fr$", + r".*@(.*\.|)ch-tarbes-vic\.fr$", + r".*@(.*\.|)chateauversailles\.fr$", + r".*@(.*\.|)chr-metz-thionville\.fr$", + r".*@chu-amiens\.fr$", + r".*@chu-montpellier\.fr$", + r".*@(.*\.|)chu-nimes\.fr$", + r".*@(.*\.|)cirad\.fr$", + r".*@(.*\.|)cnccep\.fr$", + r".*@(.*\.|)cncdh\.fr$", + r".*@(.*\.|)cnctr\.fr$", + r".*@(.*\.|)cndaspe\.fr$", + r".*@cne2\.fr$", + r".*@(.*\.|)cnil\.fr$", + r".*@(.*\.|)cnis\.fr$", + r".*@(.*\.|)cnpf\.fr$", + r".*@(.*\.|)cnr-elysee\.fr$", + r".*@(.*\.|)comite-du-label\.fr$", + r".*@(.*\.|)comite-du-secret\.fr$", + r".*@(.*\.|)commission-refugies\.fr$", + r".*@(.*\.|)conseil-concurrence\.fr$", + r".*@(.*\.|)conseil-etat\.fr$", + r".*@(.*\.|)cor-retraites\.fr$", + r".*@cre\.fr$", + r".*@crenau\.archi\.fr$", + r".*@(.*\.|)csa\.fr$", + r".*@(.*\.|)csnp\.fr$", + r".*@(.*\.|)culture\.fr$", + r".*@(.*\.|)debatpublic\.fr$", + r".*@(.*\.|)defenseurdesdroits\.fr$", + r".*@(.*\.|)dialogue-trianon\.fr$", + r".*@(.*\.|)ecoledulouvre\.fr$", + r".*@(.*\.|)efs\.sante\.fr$", + r".*@(.*\.|)elysee\.fr$", + r".*@(.*\.|)enac\.fr$", + r".*@(.*\.|)enim\.eu$", + r".*@ensai\.fr$", + r".*@(.*\.|)enssib\.fr$", + r".*@(.*\.|)ensta-paristech\.fr$", + r".*@(.*\.|)epaf\.asso\.fr$", + r".*@(.*\.|)epms-le-littoral\.net$", + r".*@(.*\.|)epms-le-littoral\.org$", + r".*@(.*\.|)erafp\.fr$", + r".*@(.*\.|)espace.gouv\.fr$", + r".*@(.*\.|)europol\.europa\.eu$", + r".*@(.*\.|)europolhq\.net$", + r".*@(.*\.|)fete-gastronomie\.fr$", + r".*@(.*\.|)fnap-logement\.fr$", + r".*@(.*\.|)fr\.europol\.net$", + r".*@(.*\.|)franceagrimer\.fr$", + r".*@(.*\.|)francemobilites\.fr$", + r".*@(.*\.|)frenchmobility\.fr$", + r".*@fun-mooc\.fr$", + r".*@(.*\.|)gouv\.fr$", + r".*@(.*\.|)guimet\.fr$", + r".*@(.*\.|)granddebat\.fr$", + r".*@(.*\.|)has-sante\.fr$", + r".*@(.*\.|)hautconseilclimat\.fr$", + r".*@(.*\.|)hautconseildesbiotechnologies\.fr$", + r".*@(.*\.|)hceres\.fr$", + r".*@(.*\.|)hcf-famille\.fr$", + r".*@(.*\.|)hcfp\.fr$", + r".*@(.*\.|)hebergement2\.interieur-gouv\.fr$", + r".*@(.*\.|)hebergement\.interieur-gouv\.fr$", + r".*@(.*\.|)hopital-le-montaigu\.com$", + r".*@(.*\.|)i-carre\.net$", + r".*@ibcp\.fr$", + r".*@(.*\.|)idda13\.fr$", + r".*@(.*\.|)ifce\.fr$", + r".*@(.*\.|)ign\.fr$", + r".*@ihedn\.fr$", + r".*@(.*\.|)ihest\.fr$", + r".*@(.*\.|)inha\.fr$", + r".*@(.*\.|)inhesj\.fr$", + r".*@(.*\.|)injep\.fr$", + r".*@(.*\.|)inp\.fr$", + r".*@(.*\.|)inpi\.fr$", + r".*@(.*\.|)inra\.fr$", + r".*@(.*\.|)inrae\.fr$", + r".*@(.*\.|)inrap\.fr$", + r".*@(.*\.|)inria\.fr$", + r".*@(.*\.|)insee\.fr$", + r".*@(.*\.|)insep\.fr$", + r".*@(.*\.|)institutcancer\.fr$", + r".*@(.*\.|)ints\.fr$", + r".*@iralille\.fr$", + r".*@ira-lille\.fr$", + r".*@(.*\.|)irisa\.fr$", + r".*@(.*\.|)irstea\.fr$", + r".*@(.*\.|)juradm\.fr$", + r".*@(.*\.|)justice\.fr$", + r".*@(.*\.|)ladocumentationfrancaise\.fr$", + r".*@(.*\.|)loria\.fr$", + r".*@(.*\.|)louvre\.fr$", + r".*@(.*\.|)medecine-de-proximite\.fr$", + r".*@(.*\.|)meteofrance\.fr$", + r".*@(.*\.|)mrccfr\.eu$", + r".*@(.*\.|)mrscfr\.eu$", + r".*@(.*\.|)mucem\.org$", + r".*@(.*\.|)musee-orangerie\.fr$", + r".*@(.*\.|)musee-orsay\.fr$", + r".*@(.*\.|)museepicassoparis.fr$", + r".*@(.*\.|)musee-rodin\.fr$", + r".*@(.*\.|)nancy\.archi\.fr$", + r".*@nantes\.archi$", + r".*@nantes\.archi\.fr$", + r".*@(.*\.|)notification\.service-public\.fr$", + r".*@(.*\.|)odeadom\.fr$", + r".*@(.*\.|)ofgl\.fr$", + r".*@(.*\.|)ofii\.fr$", + r".*@(.*\.|)onf\.fr$", + r".*@(.*\.|)oniam\.fr$", + r".*@parcoursup\.fr$", + r".*@(.*\.|)pibude\.com$", + r".*@(.*\.|)point-info-famille\.fr$", + r".*@(.*\.|)pointinfofamille\.fr$", + r".*@(.*\.|)region-academique-aura\.fr$", + r".*@(.*\.|)region-academique-auvergne-rhone-alpes\.fr$", + r".*@(.*\.|)region-academique-bfc\.fr$", + r".*@(.*\.|)region-academique-bourgogne-franche-comte\.fr$", + r".*@(.*\.|)region-academique-bretagne\.fr$", + r".*@(.*\.|)region-academique-centre-val-de-loire\.fr$", + r".*@(.*\.|)region-academique-corse\.fr$", + r".*@(.*\.|)region-academique-grand-est\.fr$", + r".*@(.*\.|)region-academique-guadeloupe\.fr$", + r".*@(.*\.|)region-academique-guyane\.fr$", + r".*@(.*\.|)region-academique-hauts-de-france\.fr$", + r".*@(.*\.|)region-academique-idf\.fr$", + r".*@(.*\.|)region-academique-ile-de-france\.fr$", + r".*@(.*\.|)region-academique-martinique\.fr$", + r".*@(.*\.|)region-academique-mayotte\.fr$", + r".*@(.*\.|)region-academique-normandie\.fr$", + r".*@(.*\.|)region-academique-nouvelle-aquitaine\.fr$", + r".*@(.*\.|)region-academique-occitanie\.fr$", + r".*@(.*\.|)region-academique-paca\.fr$", + r".*@(.*\.|)region-academique-pays-de-la-loire\.fr$", + r".*@(.*\.|)region-academique-provence-alpes-cote-dazur\.fr$", + r".*@(.*\.|)region-academique-reunion\.fr$", + r".*@(.*\.|)regis-dgac\.net$", + r".*@renater\.fr$", + r".*@(.*\.|)santepubliquefrance\.fr$", + r".*@(.*\.|)service-eco\.fr$", + r".*@(.*\.|)service-public\.fr$", + r".*@(.*\.|)service-public\.fr\.preprod\.ext\.dila\.fr$", + r".*@(.*\.|)service-public\.fr\.qualif\.ext\.dila\.fr$", + r".*@(.*\.|)sevresciteceramique\.fr$", + r".*@(.*\.|)shom\.fr$", + r".*@societedugrandparis\.fr$", + r".*@(.*\.|)taaf\.fr$", + r".*@(.*\.|)telerecours\.fr$", + r".*@(.*\.|)theatre-odeon\.fr$", + r".*@(.*\.|)ugap\.fr$", + r".*@(.*\.|)unedic\.fr$", + r".*@univ-orleans\.fr$", + r".*@(.*\.|)univ-paris13\.fr$", + r".*@univ-perp\.fr$", + r".*@(.*\.|)vie-publique\.fr$", + r".*@(.*\.|)vnf\.fr$", + r".*@univ-ubs\.fr$", + r".*@sdis(?!00|20|69|75|96|97|98|99)[0-9]{2}.fr$", + r".*@sdis-vendee.fr$", + r".*@sdis21.org$", + r".*@sdis36.org$", + r".*@sdis67.com$", + r".*@sdis86.net$", + r".*@sdis97[1-3].fr$", + r".*@sdis976.fr$", + r".*@sdis974.re$", + r".*@(.*\.|)intranet-sdis11\.fr$", + r".*@pompiersparis\.fr$", + r".*@chu-angers\.fr$", + r".*@ensc-rennes\.fr$", + r".*@educagri\.fr$", + r".*@fiva\.fr$", + r".*@assurance-maladie\.fr$", + r".*@crous-aix-marseille\.fr$", + r".*@crous-amiens\.fr$", + r".*@crous-antillesguyane\.fr$", + r".*@crous-bordeaux\.fr$", + r".*@crous-bfc\.fr$", + r".*@crous-clermont\.fr$", + r".*@crous-corse\.fr$", + r".*@crous-creteil\.fr$", + r".*@crous-grenoble\.fr$", + r".*@crous-reunion\.fr$", + r".*@crous-lille\.fr$", + r".*@crous-limoges\.fr$", + r".*@crous-lorraine\.fr$", + r".*@crous-lyon\.fr$", + r".*@crous-montpellier\.fr$", + r".*@crous-nantes\.fr$", + r".*@crous-nice\.fr$", + r".*@crous-normandie\.fr$", + r".*@crous-orleans-tours\.fr$", + r".*@crous-paris\.fr$", + r".*@crous-poitiers\.fr$", + r".*@crous-reims\.fr$", + r".*@crous-strasbourg\.fr$", + r".*@crous-versailles\.fr$", + r".*@crous-rennes\.fr$", + r".*@crous-toulouse\.fr$", + r".*@(.*\.|)assemblee-nationale\.fr$", + r".*@(.*\.|)senat\.fr$", + r".*@ird.fr$", + r".*@ch-chatillon.fr$", + r".*@ch-buzancais.fr$", +] diff --git a/web/flaskr/static/presentation/js/all.js b/web/b3desk/endpoints/__init__.py similarity index 100% rename from web/flaskr/static/presentation/js/all.js rename to web/b3desk/endpoints/__init__.py diff --git a/web/b3desk/endpoints/api.py b/web/b3desk/endpoints/api.py new file mode 100644 index 00000000..b611ccb8 --- /dev/null +++ b/web/b3desk/endpoints/api.py @@ -0,0 +1,29 @@ +from flask import Blueprint +from flask import request + +from b3desk.models.roles import Role +from b3desk.models.users import get_or_create_user + +from .. import auth + +bp = Blueprint("api", __name__) + + +@bp.route("/api/meetings") +@auth.token_auth("default", scopes_required=["profile", "email"]) +def api_meetings(): + client = auth.clients["default"] + access_token = auth._parse_access_token(request) + userinfo = client.userinfo_request(access_token).to_dict() + user = get_or_create_user(userinfo) + + return { + "meetings": [ + { + "name": meeting.name, + "moderator_url": meeting.get_signin_url(Role.moderator), + "attendee_url": meeting.get_signin_url(Role.attendee), + } + for meeting in user.meetings + ] + } diff --git a/web/b3desk/endpoints/join.py b/web/b3desk/endpoints/join.py new file mode 100644 index 00000000..2f99d99b --- /dev/null +++ b/web/b3desk/endpoints/join.py @@ -0,0 +1,246 @@ +from datetime import datetime + +from flask import Blueprint +from flask import abort +from flask import current_app +from flask import flash +from flask import redirect +from flask import render_template +from flask import request +from flask import url_for +from flask_babel import lazy_gettext as _ + +from b3desk.forms import JoinMailMeetingForm +from b3desk.forms import JoinMeetingForm +from b3desk.models import db +from b3desk.models.meetings import Meeting +from b3desk.models.meetings import get_mail_meeting +from b3desk.models.meetings import get_meeting_from_meeting_id_and_user_id +from b3desk.models.roles import Role +from b3desk.models.users import User + +from .. import auth +from ..session import get_authenticated_attendee_fullname +from ..session import get_current_user +from ..session import has_user_session +from ..session import meeting_owner_needed + +bp = Blueprint("join", __name__) + + +@bp.route( + "/meeting/signinmail//expiration//hash/", +) +def signin_mail_meeting(meeting_fake_id, expiration, h): + meeting = get_mail_meeting(meeting_fake_id) + wordings = current_app.config["WORDINGS"] + + if meeting is None: + flash( + _( + "Aucune %(meeting_label)s ne correspond à ces paramètres", + meeting_label=wordings["meeting_label"], + ), + "success", + ) + return redirect(url_for("public.index")) + + hash_matches = meeting.get_mail_signin_hash(meeting_fake_id, expiration) == h + if not hash_matches: + flash(_("Lien invalide"), "error") + return redirect(url_for("public.index")) + + is_expired = datetime.fromtimestamp(float(expiration)) < datetime.now() + if is_expired: + flash(_("Lien expiré"), "error") + return redirect(url_for("public.index")) + + return render_template( + "meeting/joinmail.html", + meeting=meeting, + meeting_fake_id=meeting.fake_id, + expiration=expiration, + user_id="fakeuserId", + h=h, + role=Role.moderator, + ) + + +# The role needs to appear in the URL, even if it is unused, so user won't +# mix up invitation links. +# https://github.com/numerique-gouv/b3desk/issues/93 +@bp.route( + "/meeting/signin///creator//hash/" +) +@bp.route("/meeting/signin//creator//hash/") +def signin_meeting(meeting_fake_id, creator: User, h, role: Role = None): + meeting = get_meeting_from_meeting_id_and_user_id(meeting_fake_id, creator.id) + wordings = current_app.config["WORDINGS"] + if meeting is None: + flash( + _( + "Aucune %(meeting_label)s ne correspond à ces paramètres", + meeting_label=wordings["meeting_label"], + ), + "success", + ) + return redirect(url_for("public.index")) + + current_user_id = get_current_user().id if has_user_session() else None + role = meeting.get_role(h, current_user_id) + + if role == Role.authenticated: + return redirect( + url_for("join.join_meeting_as_authenticated", meeting_id=meeting_fake_id) + ) + elif not role: + return redirect(url_for("public.index")) + + return render_template( + "meeting/join.html", + meeting=meeting, + meeting_fake_id=meeting_fake_id, + creator=creator, + h=h, + role=role, + ) + + +@bp.route("/meeting/auth//creator//hash/") +@auth.oidc_auth("default") +def authenticate_then_signin_meeting(meeting_fake_id, creator: User, h): + return redirect( + url_for( + "join.signin_meeting", + meeting_fake_id=meeting_fake_id, + creator=creator, + h=h, + ) + ) + + +@bp.route( + "/meeting/wait//creator//hash//fullname/fullname_suffix/", +) +@bp.route( + "/meeting/wait//creator//hash//fullname//fullname_suffix/", +) +@bp.route( + "/meeting/wait//creator//hash//fullname/fullname_suffix/", +) +@bp.route( + "/meeting/wait//creator//hash//fullname//fullname_suffix/", +) +def waiting_meeting(meeting_fake_id, creator: User, h, fullname="", fullname_suffix=""): + meeting = get_meeting_from_meeting_id_and_user_id(meeting_fake_id, creator.id) + if meeting is None: + return redirect(url_for("public.index")) + + current_user_id = get_current_user().id if has_user_session() else None + role = meeting.get_role(h, current_user_id) + if not role: + return redirect(url_for("public.index")) + + return render_template( + "meeting/wait.html", + meeting=meeting, + meeting_fake_id=meeting_fake_id, + creator=creator, + h=h, + role=role, + fullname=fullname, + fullname_suffix=fullname_suffix, + ) + + +@bp.route("/meeting/join", methods=["POST"]) +def join_meeting(): + form = JoinMeetingForm(request.form) + if not form.validate(): + return redirect(url_for("public.index")) + + fullname = form["fullname"].data + meeting_fake_id = form["meeting_fake_id"].data + user_id = form["user_id"].data + h = form["h"].data + meeting = get_meeting_from_meeting_id_and_user_id(meeting_fake_id, user_id) + if meeting is None: + return redirect(url_for("public.index")) + + current_user_id = get_current_user().id if has_user_session() else None + role = meeting.get_role(h, current_user_id) + fullname_suffix = form["fullname_suffix"].data + if role == Role.authenticated: + fullname = get_authenticated_attendee_fullname() + elif not role: + return redirect(url_for("public.index")) + + return redirect( + meeting.get_join_url( + role, fullname, fullname_suffix=fullname_suffix, create=True + ) + ) + + +@bp.route("/meeting/joinmail", methods=["POST"]) +def join_mail_meeting(): + form = JoinMailMeetingForm(request.form) + if not form.validate(): + flash("Lien invalide", "error") + return redirect(url_for("public.index")) + + fullname = form["fullname"].data + meeting_fake_id = form["meeting_fake_id"].data + form["user_id"].data + expiration = form["expiration"].data + h = form["h"].data + + meeting = get_mail_meeting(meeting_fake_id) + if meeting is None: + flash( + _( + "%(meeting_label)s inexistante", + meeting_label=current_app.config["WORDINGS"][ + "meeting_label" + ].capitalize(), + ), + "error", + ) + return redirect(url_for("public.index")) + + hash_matches = meeting.get_mail_signin_hash(meeting_fake_id, expiration) == h + if not hash_matches: + flash(_("Lien invalide"), "error") + return redirect(url_for("public.index")) + + is_expired = datetime.fromtimestamp(expiration) < datetime.now() + if is_expired: + flash(_("Lien expiré"), "error") + return redirect(url_for("public.index")) + + return redirect(meeting.get_join_url(Role.moderator, fullname, create=True)) + + +# Cannot use a flask converter here because sometimes 'meeting_id' is a 'fake_id' +@bp.route("/meeting/join//authenticated") +@auth.oidc_auth("attendee") +def join_meeting_as_authenticated(meeting_id): + meeting = db.session.get(Meeting, meeting_id) or abort(404) + role = Role.authenticated + fullname = get_authenticated_attendee_fullname() + return redirect( + url_for( + "join.waiting_meeting", + meeting_fake_id=meeting_id, + creator=meeting.user, + h=meeting.get_hash(role), + fullname=fullname, + ) + ) + + +@bp.route("/meeting/join//") +@auth.oidc_auth("default") +@meeting_owner_needed +def join_meeting_as_role(meeting: Meeting, role: Role, owner: User): + return redirect(meeting.get_join_url(role, owner.fullname, create=True)) diff --git a/web/b3desk/endpoints/meeting_files.py b/web/b3desk/endpoints/meeting_files.py new file mode 100644 index 00000000..4ac10e90 --- /dev/null +++ b/web/b3desk/endpoints/meeting_files.py @@ -0,0 +1,610 @@ +import hashlib +import os +import secrets +import uuid +from datetime import date +from pathlib import Path + +import filetype +import requests +from flask import Blueprint +from flask import abort +from flask import current_app +from flask import flash +from flask import jsonify +from flask import make_response +from flask import redirect +from flask import render_template +from flask import request +from flask import send_file +from flask import send_from_directory +from flask import url_for +from flask_babel import lazy_gettext as _ +from sqlalchemy import exc +from webdav3.client import Client as webdavClient +from webdav3.exceptions import WebDavException +from werkzeug.utils import secure_filename + +from b3desk.forms import MeetingFilesForm +from b3desk.models import db +from b3desk.models.meetings import Meeting +from b3desk.models.meetings import MeetingFiles +from b3desk.models.meetings import MeetingFilesExternal +from b3desk.models.users import User + +from .. import auth +from ..session import get_current_user +from ..session import meeting_owner_needed + +bp = Blueprint("meeting_files", __name__) + + +@bp.route("/meeting/files/") +@auth.oidc_auth("default") +@meeting_owner_needed +def edit_meeting_files(meeting: Meeting, owner: User): + form = MeetingFilesForm() + + if not current_app.config["FILE_SHARING"]: + flash(_("Vous ne pouvez pas modifier cet élément"), "warning") + return redirect(url_for("public.welcome")) + + # we test webdav connection here, with a simple 'list' command + if owner.nc_login and owner.nc_token and owner.nc_locator: + options = { + "webdav_root": f"/remote.php/dav/files/{owner.nc_login}/", + "webdav_hostname": owner.nc_locator, + "webdav_verbose": True, + "webdav_token": owner.nc_token, + } + try: + client = webdavClient(options) + client.list() + except WebDavException as exception: + current_app.logger.warning( + "WebDAV error, owner data disabled: %s", exception + ) + owner.disable_nextcloud() + + return render_template( + "meeting/filesform.html", + meeting=meeting, + form=form, + ) + + +@bp.route("/meeting/files/", methods=["POST"]) +@auth.oidc_auth("default") +@meeting_owner_needed +def add_meeting_files(meeting: Meeting, owner: User): + data = request.get_json() + is_default = False + if len(meeting.files) == 0: + is_default = True + + if data["from"] == "nextcloud": + return add_meeting_file_nextcloud(data["value"], meeting.id, is_default) + + if data["from"] == "URL": + return add_meeting_file_URL(data["value"], meeting.id, is_default) + + # This is called by the JS after uploading a file on the 'add_dropzone_files' + # TODO: do everything in one single request? + if data["from"] == "dropzone": + return add_meeting_file_dropzone( + secure_filename(data["value"]), meeting.id, is_default + ) + + return jsonify("no file provided") + + +@bp.route("/meeting/files//") +@bp.route("/meeting/files//") +@auth.oidc_auth("default") +@meeting_owner_needed +def download_meeting_files(meeting: Meeting, owner: User, file_id=None): + TMP_DOWNLOAD_DIR = current_app.config["TMP_DOWNLOAD_DIR"] + Path(TMP_DOWNLOAD_DIR).mkdir(parents=True, exist_ok=True) + tmp_name = f'{current_app.config["TMP_DOWNLOAD_DIR"]}{secrets.token_urlsafe(32)}' + file_to_send = None + + for current_file in meeting.files: + if current_file.id == file_id: + file_to_send = current_file + break + + if not file_to_send: + return jsonify(status=404, msg="file not found") + + if current_file.url: + response = requests.get(current_file.url) + open(tmp_name, "wb").write(response.content) + return send_file(tmp_name, as_attachment=True, download_name=current_file.title) + + # get file from nextcloud WEBDAV and send it + try: + dav_user = { + "nc_locator": owner.nc_locator, + "nc_login": owner.nc_login, + "nc_token": owner.nc_token, + } + options = { + "webdav_root": f"/remote.php/dav/files/{dav_user['nc_login']}/", + "webdav_hostname": dav_user["nc_locator"], + "webdav_verbose": True, + "webdav_token": dav_user["nc_token"], + } + client = webdavClient(options) + kwargs = { + "remote_path": current_file.nc_path, + "local_path": f"{tmp_name}", + } + client.download_sync(**kwargs) + return send_file(tmp_name, as_attachment=True, download_name=current_file.title) + + except WebDavException as exception: + owner.disable_nextcloud() + current_app.logger.warning( + "webdav call encountered following exception : %s", exception + ) + flash("Le fichier ne semble pas accessible", "error") + return redirect(url_for("public.welcome")) + + +# called by NextcloudfilePicker when documents should be added to a running room: +@bp.route("/meeting/files//insertDocuments", methods=["POST"]) +@auth.oidc_auth("default") +def insertDocuments(meeting: Meeting): + from flask import request + + files_title = request.get_json() + secret_key = current_app.config["SECRET_KEY"] + + xml_beg = " " + xml_end = " " + xml_mid = "" + # @FIX We ONLY send the documents that have been uploaded NOW, not ALL of them for this meetingid ;) + for cur_file in files_title: + id = add_external_meeting_file_nextcloud(cur_file, meeting.id) + filehash = hashlib.sha1( + f"{secret_key}-1-{id}-{secret_key}".encode() + ).hexdigest() + url = url_for( + "meeting_files.ncdownload", + isexternal=1, + mfid=id, + mftoken=filehash, + _external=True, + ) + xml_mid += f"" + + bbb_endpoint = current_app.config["BIGBLUEBUTTON_ENDPOINT"] + xml = xml_beg + xml_mid + xml_end + params = {"meetingID": meeting.meetingID} + request = requests.Request( + "POST", + "{}/{}".format(current_app.config["BIGBLUEBUTTON_ENDPOINT"], "insertDocument"), + params=params, + ) + pr = request.prepare() + bigbluebutton_secret = current_app.config["BIGBLUEBUTTON_SECRET"] + s = "{}{}".format( + pr.url.replace("?", "").replace( + current_app.config["BIGBLUEBUTTON_ENDPOINT"] + "/", "" + ), + bigbluebutton_secret, + ) + params["checksum"] = hashlib.sha1(s.encode("utf-8")).hexdigest() + requests.post( + f"{bbb_endpoint}/insertDocument", + headers={"Content-Type": "application/xml"}, + data=xml, + params=params, + ) + return jsonify(status=200, msg="SUCCESS") + + +@bp.route("/meeting/files//toggledownload", methods=["POST"]) +@auth.oidc_auth("default") +@meeting_owner_needed +def toggledownload(meeting: Meeting, owner: User): + data = request.get_json() + meeting_file = db.session.get(MeetingFiles, data["id"]) + if not meeting_file: + abort(404) + + meeting_file.is_downloadable = data["value"] + meeting_file.save() + + return jsonify(status=200, id=data["id"]) + + +@bp.route("/meeting/files//default", methods=["POST"]) +@auth.oidc_auth("default") +@meeting_owner_needed +def set_meeting_default_file(meeting: Meeting, owner: User): + data = request.get_json() + + actual_default_file = meeting.default_file + if actual_default_file: + actual_default_file.is_default = False + + meeting_file = MeetingFiles.query.get(data["id"]) + meeting_file.is_default = True + + if actual_default_file: + actual_default_file.save() + meeting_file.save() + + return jsonify(status=200, id=data["id"]) + + +def remove_dropzone_file(absolutePath): + os.remove(absolutePath) + + +# called when a file has been uploaded : send it to nextcloud +def add_meeting_file_dropzone(title, meeting_id, is_default): + user = get_current_user() + # should be in /tmp/visioagent/dropzone/USER_ID-TITLE + DROPZONE_DIR = os.path.join(current_app.config["UPLOAD_DIR"], "dropzone") + Path(DROPZONE_DIR).mkdir(parents=True, exist_ok=True) + dropzone_path = os.path.join(DROPZONE_DIR, f"{user.id}-{meeting_id}-{title}") + metadata = os.stat(dropzone_path) + if int(metadata.st_size) > current_app.config["MAX_SIZE_UPLOAD"]: + return jsonify( + status=500, + isfrom="dropzone", + msg=f"Fichier {title} TROP VOLUMINEUX, ne pas dépasser 20Mo", + ) + + options = { + "webdav_root": f"/remote.php/dav/files/{user.nc_login}/", + "webdav_hostname": user.nc_locator, + "webdav_verbose": True, + "webdav_token": user.nc_token, + } + try: + client = webdavClient(options) + client.mkdir("visio-agents") # does not fail if dir already exists + # Upload resource + nc_path = os.path.join("/visio-agents/" + title) + kwargs = { + "remote_path": nc_path, + "local_path": dropzone_path, + } + client.upload_sync(**kwargs) + + meeting_file = MeetingFiles( + nc_path=nc_path, + title=title, + created_at=date.today(), + meeting_id=meeting_id, + ) + + except WebDavException as exception: + user.disable_nextcloud() + current_app.logger.warning("WebDAV error: %s", exception) + return jsonify( + status=500, isfrom="dropzone", msg="La connexion avec Nextcloud est rompue" + ) + + try: + # test for is_default-file absence at the latest time possible + meeting = db.session.get(Meeting, meeting_id) + meeting_file.is_default = len(meeting.files) == 0 and not meeting.default_file + meeting_file.save() + + # file has been associated AND uploaded to nextcloud, we can safely remove it from visio-agent tmp directory + remove_dropzone_file(dropzone_path) + return jsonify( + status=200, + isfrom="dropzone", + isDefault=is_default, + title=meeting_file.short_title, + id=meeting_file.id, + created_at=meeting_file.created_at.strftime( + current_app.config["TIME_FORMAT"] + ), + ) + + except exc.SQLAlchemyError as exception: + current_app.logger.error("SQLAlchemy error: %s", exception) + return jsonify( + status=500, isfrom="dropzone", msg="Le fichier a déjà été mis en ligne" + ) + + +def add_meeting_file_URL(url, meeting_id, is_default): + title = url.rsplit("/", 1)[-1] + + # test MAX_SIZE_UPLOAD for 20Mo + metadata = requests.head(url) + if not metadata.ok: + return jsonify( + status=404, + isfrom="url", + msg=f"Fichier {title} NON DISPONIBLE, veuillez vérifier l'URL proposée", + ) + + if int(metadata.headers["content-length"]) > current_app.config["MAX_SIZE_UPLOAD"]: + return jsonify( + status=500, + isfrom="url", + msg=f"Fichier {title} TROP VOLUMINEUX, ne pas dépasser 20Mo", + ) + + meeting_file = MeetingFiles( + title=title, + created_at=date.today(), + meeting_id=meeting_id, + url=url, + is_default=is_default, + ) + requests.get(url) + + try: + meeting_file.save() + return jsonify( + status=200, + isfrom="url", + isDefault=is_default, + title=meeting_file.short_title, + id=meeting_file.id, + created_at=meeting_file.created_at.strftime( + current_app.config["TIME_FORMAT"] + ), + ) + + except exc.SQLAlchemyError as exception: + current_app.logger.error("SQLAlchemy error: %s", exception) + return jsonify( + status=500, isfrom="url", msg="Le fichier a déjà été mis en ligne" + ) + + +def add_meeting_file_nextcloud(path, meeting_id, is_default): + user = get_current_user() + + options = { + "webdav_root": f"/remote.php/dav/files/{user.nc_login}/", + "webdav_hostname": user.nc_locator, + "webdav_verbose": True, + "webdav_token": user.nc_token, + } + try: + client = webdavClient(options) + metadata = client.info(path) + + except WebDavException: + user.disable_nextcloud() + return jsonify( + status=500, + isfrom="nextcloud", + msg="La connexion avec Nextcloud semble rompue", + ) + + if int(metadata["size"]) > current_app.config["MAX_SIZE_UPLOAD"]: + return jsonify( + status=500, + isfrom="nextcloud", + msg=f"Fichier {path} TROP VOLUMINEUX, ne pas dépasser 20Mo", + ) + + meeting_file = MeetingFiles( + title=path, + created_at=date.today(), + meeting_id=meeting_id, + nc_path=path, + is_default=is_default, + ) + + try: + meeting_file.save() + return jsonify( + status=200, + isfrom="nextcloud", + isDefault=is_default, + title=meeting_file.short_title, + id=meeting_file.id, + created_at=meeting_file.created_at.strftime( + current_app.config["TIME_FORMAT"] + ), + ) + except exc.SQLAlchemyError as exception: + current_app.logger.error("SQLAlchemy error: %s", exception) + return jsonify( + status=500, isfrom="nextcloud", msg="Le fichier a déjà été mis en ligne" + ) + + +def add_external_meeting_file_nextcloud(path, meeting_id): + externalMeetingFile = MeetingFilesExternal( + title=path, meeting_id=meeting_id, nc_path=path + ) + externalMeetingFile.save() + return externalMeetingFile.id + + +# for dropzone multiple files uploading at once +@bp.route("/meeting/files//dropzone", methods=["POST"]) +@auth.oidc_auth("default") +@meeting_owner_needed +def add_dropzone_files(meeting: Meeting, owner: User): + file = request.files["dropzoneFiles"] + # for dropzone chunk file by file validation + # shamelessly taken from https://stackoverflow.com/questions/44727052/handling-large-file-uploads-with-flask + DROPZONE_DIR = os.path.join(current_app.config["UPLOAD_DIR"], "dropzone") + Path(DROPZONE_DIR).mkdir(parents=True, exist_ok=True) + save_path = os.path.join( + DROPZONE_DIR, secure_filename(f"{owner.id}-{meeting.id}-{file.filename}") + ) + current_chunk = int(request.form["dzchunkindex"]) + + # If the file already exists it's ok if we are appending to it, + # but not if it's new file that would overwrite the existing one + if os.path.exists(save_path) and current_chunk == 0: + # 400 and 500s will tell dropzone that an error occurred and show an error + return make_response(("Le fichier a déjà été mis en ligne", 500)) + + try: + with open(save_path, "ab") as f: + f.seek(int(request.form["dzchunkbyteoffset"])) + f.write(file.stream.read()) + + except OSError: + return make_response( + ("Not sure why, but we couldn't write the file to disk", 500) + ) + + total_chunks = int(request.form["dztotalchunkcount"]) + + if current_chunk + 1 == total_chunks: + # This was the last chunk, the file should be complete and the size we expect + mimetype = filetype.guess(save_path) + if mimetype.mime not in current_app.config["ALLOWED_MIME_TYPES_SERVER_SIDE"]: + return make_response(("Filetype not allowed", 500)) + if os.path.getsize(save_path) != int(request.form["dztotalfilesize"]): + return make_response(("Size mismatch", 500)) + + current_app.logger.debug(f"Wrote a chunk at {save_path}") + return make_response(("Chunk upload successful", 200)) + + +@bp.route("/meeting/files/delete", methods=["POST"]) +@auth.oidc_auth("default") +def delete_meeting_file(): + user = get_current_user() + data = request.get_json() + meeting_file_id = data["id"] + meeting_file = MeetingFiles.query.get(meeting_file_id) + cur_meeting = Meeting.query.get(meeting_file.meeting_id) + + if cur_meeting.user_id != user.id: + return jsonify( + status=500, id=data["id"], msg="Vous ne pouvez pas supprimer cet élément" + ) + + db.session.delete(meeting_file) + db.session.commit() + new_default_id = None + if meeting_file.is_default: + cur_meeting = Meeting.query.get(meeting_file.meeting_id) + if len(cur_meeting.files) > 0: + cur_meeting.files[0].is_default = True + new_default_id = cur_meeting.files[0].id + cur_meeting.save() + + return jsonify( + status=200, + newDefaultId=new_default_id, + id=data["id"], + msg="Fichier supprimé avec succès", + ) + + +# draft for insertDocument calls to BBB API +# @TODO: can we remove this def entirely? +@bp.route("/insertDoc/") +def insertDoc(token): + # select good file from token + # get file through NC credentials - HOW POSSIBLE ? + # return file as response to BBB server + + meeting_file = MeetingFiles.query.filter_by(download_hash=token).one() + secret_key = current_app.config["SECRET_KEY"] + if ( + meeting_file + or meeting_file.token + != hashlib.sha1( + f"{secret_key}{meeting_file.id}{secret_key}".encode() + ).hexdigest() + ): + make_response("NOT OK", 500) + + params = {"meetingID": meeting_file.meeting.meetingID} + action = "insertDocument" + req = requests.Request( + "POST", + "{}/{}".format(current_app.config["BIGBLUEBUTTON_ENDPOINT"], action), + params=params, + ) + headers = {"Content-Type": "application/xml"} + pr = req.prepare() + bigbluebutton_secret = current_app.config["BIGBLUEBUTTON_SECRET"] + s = "{}{}".format( + pr.url.replace("?", "").replace( + current_app.config["BIGBLUEBUTTON_ENDPOINT"] + "/", "" + ), + bigbluebutton_secret, + ) + params["checksum"] = hashlib.sha1(s.encode("utf-8")).hexdigest() + + # xml now use + url = url_for( + "meeting_files.ncdownload", + isexternal=0, + mfid=meeting_file.id, + mftoken=meeting_file.download_hash, + _external=True, + ) + xml = f" " + + requests.post( + f"{current_app.config['BIGBLUEBUTTON_ENDPOINT']}/insertDocument", + data=xml, + headers=headers, + params=params, + ) + + return make_response("ok", 200) + + +@bp.route("/ncdownload///") +# @auth.token_auth(provider_name="default") - must be accessible by BBB server, so no auth +def ncdownload(isexternal, mfid, mftoken): + secret_key = current_app.config["SECRET_KEY"] + # select good file from token + # get file through NC credentials - HOW POSSIBLE ? + # return file as response to BBB server + # isexternal tells if the file has been chosen earlier from the visio-agent interface (0) or if it has been uploaded from BBB itself (1) + model = MeetingFiles if isexternal == 0 else MeetingFilesExternal + meeting_file = model.query.filter_by(id=mfid).one_or_none() + + if not meeting_file: + abort(404, "Bad token provided, no file matching") + + # the hash token consist of the sha1 of "secret key - 0/1 (internal/external) - id in the DB - secret key" + if ( + mftoken + != hashlib.sha1( + f"{secret_key}-{isexternal}-{mfid}-{secret_key}".encode() + ).hexdigest() + ): + abort(404, "Bad token provided, no file matching") + + # download the file using webdavClient from the Nextcloud to a temporary folder (that will need cleaning) + options = { + "webdav_root": f"/remote.php/dav/files/{meeting_file.meeting.user.nc_login}/", + "webdav_hostname": meeting_file.meeting.user.nc_locator, + "webdav_verbose": True, + "webdav_token": meeting_file.meeting.user.nc_token, + } + try: + client = webdavClient(options) + TMP_DOWNLOAD_DIR = current_app.config["TMP_DOWNLOAD_DIR"] + Path(TMP_DOWNLOAD_DIR).mkdir(parents=True, exist_ok=True) + uniqfile = str(uuid.uuid4()) + tmp_name = f"{TMP_DOWNLOAD_DIR}{uniqfile}" + kwargs = { + "remote_path": meeting_file.nc_path, + "local_path": tmp_name, + } + client.download_sync(**kwargs) + + except WebDavException: + meeting_file.meeting.user.disable_nextcloud() + return jsonify(status=500, msg="La connexion avec Nextcloud semble rompue") + + # send the downloaded file to the BBB: + return send_from_directory(TMP_DOWNLOAD_DIR, uniqfile) diff --git a/web/b3desk/endpoints/meetings.py b/web/b3desk/endpoints/meetings.py new file mode 100644 index 00000000..a36e367a --- /dev/null +++ b/web/b3desk/endpoints/meetings.py @@ -0,0 +1,328 @@ +# +----------------------------------------------------------------------------+ +# | BBB-VISIO | +# +----------------------------------------------------------------------------+ +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the European Union Public License 1.2 version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. +from flask import Blueprint +from flask import abort +from flask import current_app +from flask import flash +from flask import redirect +from flask import render_template +from flask import request +from flask import url_for +from flask_babel import lazy_gettext as _ + +from b3desk.forms import EndMeetingForm +from b3desk.forms import MeetingForm +from b3desk.forms import MeetingWithRecordForm +from b3desk.forms import RecordingForm +from b3desk.forms import ShowMeetingForm +from b3desk.models import db +from b3desk.models.meetings import Meeting +from b3desk.models.meetings import get_quick_meeting_from_user_and_random_string +from b3desk.models.roles import Role +from b3desk.models.users import User + +from .. import auth +from ..session import get_current_user +from ..session import meeting_owner_needed +from ..utils import is_accepted_email +from ..utils import is_valid_email +from ..utils import send_quick_meeting_mail + +bp = Blueprint("meetings", __name__) + + +def meeting_mailto_params(meeting: Meeting, role: Role): + if role == Role.moderator: + return render_template( + "meeting/mailto/mail_href.txt", meeting=meeting, role=role + ).replace("\n", "%0D%0A") + elif role == Role.attendee: + return render_template( + "meeting/mailto/mail_href.txt", meeting=meeting, role=role + ).replace("\n", "%0D%0A") + + +@bp.route("/meeting/mail", methods=["POST"]) +def quick_mail_meeting(): + #### Almost the same as quick meeting but we do not redirect to join + email = request.form.get("mail") + if not is_valid_email(email): + flash( + _( + "Courriel invalide. Avez vous bien tapé votre email ? Vous pouvez réessayer." + ), + "error_login", + ) + return redirect(url_for("public.index")) + if not is_accepted_email(email): + flash( + _( + "Ce courriel ne correspond pas à un service de l'État. Si vous appartenez à un service de l'État mais votre courriel n'est pas reconnu par Webinaire, contactez-nous pour que nous le rajoutions !" + ), + "error_login", + ) + return redirect(url_for("public.index")) + user = User( + id=email + ) # this user can probably be removed if we created adock function + meeting = get_quick_meeting_from_user_and_random_string(user) + send_quick_meeting_mail(meeting, email) + flash(_("Vous avez reçu un courriel pour vous connecter"), "success_login") + return redirect(url_for("public.index")) + + +@bp.route("/meeting/quick") +@auth.oidc_auth("default") +def quick_meeting(): + user = get_current_user() + meeting = get_quick_meeting_from_user_and_random_string(user) + return redirect(meeting.get_join_url(Role.moderator, user.fullname, create=True)) + + +@bp.route("/meeting/show/") +@auth.oidc_auth("default") +@meeting_owner_needed +def show_meeting(meeting: Meeting, owner: User): + # TODO: appears unused + + form = ShowMeetingForm(data={"meeting_id": meeting.id}) + if not form.validate(): + flash( + _("Vous ne pouvez pas voir cet élément (identifiant incorrect)"), + "warning", + ) + return redirect(url_for("public.welcome")) + + return render_template( + "meeting/show.html", + meeting_mailto_params=meeting_mailto_params, + meeting=meeting, + ) + + +@bp.route("/meeting/recordings/") +@auth.oidc_auth("default") +@meeting_owner_needed +def show_meeting_recording(meeting: Meeting, owner: User): + form = RecordingForm() + return render_template( + "meeting/recordings.html", + meeting_mailto_params=meeting_mailto_params, + meeting=meeting, + form=form, + ) + + +@bp.route("/meeting//recordings/", methods=["POST"]) +@auth.oidc_auth("default") +@meeting_owner_needed +def update_recording_name(meeting: Meeting, recording_id, owner: User): + form = RecordingForm(request.form) + if not form.validate(): + abort(403) + + result = meeting.update_recording_name(recording_id, form.data["name"]) + return_code = result.get("returncode") + if return_code == "SUCCESS": + flash("Enregistrement renommé", "success") + else: + message = result.get("message", "") + flash( + "Nous n'avons pas pu modifier cet enregistrement : {code}, {message}".format( + code=return_code, message=message + ), + "error", + ) + return redirect(url_for("meetings.show_meeting_recording", meeting=meeting)) + + +@bp.route("/meeting/new") +@auth.oidc_auth("default") +def new_meeting(): + user = get_current_user() + if not user.can_create_meetings: + return redirect(url_for("public.welcome")) + + form = MeetingWithRecordForm() if current_app.config["RECORDING"] else MeetingForm() + + return render_template( + "meeting/wizard.html", + meeting=None, + form=form, + recording=current_app.config["RECORDING"], + ) + + +@bp.route("/meeting/edit/") +@auth.oidc_auth("default") +@meeting_owner_needed +def edit_meeting(meeting: Meeting, owner: User): + form = ( + MeetingWithRecordForm(obj=meeting) + if current_app.config["RECORDING"] + else MeetingForm(obj=meeting) + ) + return render_template( + "meeting/wizard.html", + meeting=meeting, + form=form, + recording=current_app.config["RECORDING"], + ) + + +@bp.route("/meeting/save", methods=["POST"]) +@auth.oidc_auth("default") +def save_meeting(): + user = get_current_user() + form = ( + MeetingWithRecordForm(request.form) + if current_app.config["RECORDING"] + else MeetingForm(request.form) + ) + + is_new_meeting = not form.data["id"] + if not user.can_create_meetings and is_new_meeting: + return redirect(url_for("public.welcome")) + + if not form.validate(): + flash("Le formulaire contient des erreurs", "error") + return render_template( + "meeting/wizard.html", + meeting=None if is_new_meeting else db.session.get(Meeting, form.id.data), + form=form, + recording=current_app.config["RECORDING"], + ) + + if is_new_meeting: + meeting = Meeting() + meeting.user = user + else: + meeting_id = form.data["id"] + meeting = db.session.get(Meeting, meeting_id) + del form.id + del form.name + + meeting.record = bool( + form.data.get("allowStartStopRecording") or form.data.get("autoStartRecording") + ) + form.populate_obj(meeting) + meeting.save() + flash( + _("%(meeting_name)s modifications prises en compte", meeting_name=meeting.name), + "success", + ) + + if meeting.is_running(): + return render_template( + "meeting/end.html", + meeting=meeting, + form=EndMeetingForm(data={"meeting_id": meeting_id}), + ) + return redirect(url_for("public.welcome")) + + +@bp.route("/meeting/end", methods=["POST"]) +@auth.oidc_auth("default") +def end_meeting(): + user = get_current_user() + form = EndMeetingForm(request.form) + + meeting_id = form.data["meeting_id"] + meeting = db.session.get(Meeting, meeting_id) or abort(404) + + if user == meeting.user: + meeting.end_bbb() + flash( + f"{current_app.config['WORDING_MEETING'].capitalize()} « {meeting.name} » terminé(e)", + "success", + ) + return redirect(url_for("public.welcome")) + + +@bp.route("/meeting/create/") +@auth.oidc_auth("default") +@meeting_owner_needed +def create_meeting(meeting: Meeting, owner: User): + meeting.create_bbb() + meeting.save() + return redirect(url_for("public.welcome")) + + +@bp.route("/meeting//externalUpload") +@auth.oidc_auth("default") +@meeting_owner_needed +def externalUpload(meeting: Meeting, owner: User): + if meeting.is_running(): + return render_template("meeting/externalUpload.html", meeting=meeting) + return redirect(url_for("public.welcome")) + + +@bp.route("/meeting/delete", methods=["POST", "GET"]) +@auth.oidc_auth("default") +def delete_meeting(): + if request.method == "POST": + user = get_current_user() + meeting_id = request.form["id"] + meeting = db.session.get(Meeting, meeting_id) + + if meeting.user_id == user.id: + for meeting_file in meeting.files: + db.session.delete(meeting_file) + for meeting_file_external in meeting.externalFiles: + db.session.delete(meeting_file_external) + + data = meeting.delete_all_recordings() + return_code = data.get("returncode", "SUCCESS") + if return_code != "SUCCESS": + message = data.get("message", "") + flash( + "Nous n'avons pas pu supprimer les vidéos de cette " + + current_app.config["WORDINGS"]["meeting_label"] + + f" : {message}", + "error", + ) + else: + db.session.delete(meeting) + db.session.commit() + flash(_("Élément supprimé"), "success") + else: + flash(_("Vous ne pouvez pas supprimer cet élément"), "error") + return redirect(url_for("public.welcome")) + + +@bp.route("/meeting/video/delete", methods=["POST"]) +@auth.oidc_auth("default") +def delete_video_meeting(): + user = get_current_user() + meeting_id = request.form["id"] + meeting = db.session.get(Meeting, meeting_id) + if meeting.user_id == user.id: + recordID = request.form["recordID"] + data = meeting.delete_recordings(recordID) + return_code = data.get("returncode") + if return_code == "SUCCESS": + flash(_("Vidéo supprimée"), "success") + else: + message = data.get("message", "") + flash( + _( + "Nous n'avons pas pu supprimer cette vidéo : %(code)s, %(message)s", + code=return_code, + message=message, + ), + "error", + ) + else: + flash( + _("Vous ne pouvez pas supprimer cette enregistrement"), + "error", + ) + return redirect(url_for("public.welcome")) diff --git a/web/b3desk/endpoints/public.py b/web/b3desk/endpoints/public.py new file mode 100644 index 00000000..7f82f4b1 --- /dev/null +++ b/web/b3desk/endpoints/public.py @@ -0,0 +1,143 @@ +import requests +from flask import Blueprint +from flask import current_app +from flask import redirect +from flask import render_template +from flask import url_for + +from .. import auth +from .. import cache +from ..session import get_current_user +from ..session import has_user_session +from ..templates.content import FAQ_CONTENT +from .meetings import meeting_mailto_params + +bp = Blueprint("public", __name__) + + +@cache.cached( + timeout=current_app.config["STATS_CACHE_DURATION"], key_prefix="meetings_stats" +) +def get_meetings_stats(): + # TODO: do this asynchroneously + # Currently, the page needs to wait another network request in get_meetings_stats + # before it can be rendered. This is mitigated by caching though. + + if not current_app.config["STATS_URL"]: + return None + + response = requests.get(current_app.config["STATS_URL"]) + if response.status_code != 200: + return None + + try: + stats_array = response.content.decode(encoding="utf-8").split("\n") + stats_array = [row.split(",") for row in stats_array] + participant_count = int(stats_array[current_app.config["STATS_INDEX"]][1]) + running_count = int(stats_array[current_app.config["STATS_INDEX"]][2]) + except Exception: + return None + + result = {"participantCount": participant_count, "runningCount": running_count} + return result + + +@bp.route("/") +def index(): + if has_user_session(): + return redirect(url_for("public.welcome")) + else: + return redirect(url_for("public.home")) + + +@bp.route("/home") +def home(): + if has_user_session(): + return redirect(url_for("public.welcome")) + + stats = get_meetings_stats() + return render_template( + "index.html", + stats=stats, + mail_meeting=current_app.config["MAIL_MEETING"], + max_participants=current_app.config["MAX_PARTICIPANTS"], + ) + + +@bp.route("/welcome") +@auth.oidc_auth("default") +def welcome(): + user = get_current_user() + stats = get_meetings_stats() + + return render_template( + "welcome.html", + stats=stats, + max_participants=current_app.config["MAX_PARTICIPANTS"], + can_create_meetings=user.can_create_meetings, + max_meetings_per_user=current_app.config["MAX_MEETINGS_PER_USER"], + meeting_mailto_params=meeting_mailto_params, + mailto=current_app.config["MAILTO_LINKS"], + quick_meeting=current_app.config["QUICK_MEETING"], + file_sharing=current_app.config["FILE_SHARING"], + clipboard=current_app.config["CLIPBOARD"], + ) + + +@bp.route("/mentions_legales") +def mentions_legales(): + return render_template( + "footer/mentions_legales.html", + service_title=current_app.config["SERVICE_TITLE"], + service_tagline=current_app.config["SERVICE_TAGLINE"], + ) + + +@bp.route("/cgu") +def cgu(): + return render_template( + "footer/cgu.html", + service_title=current_app.config["SERVICE_TITLE"], + service_tagline=current_app.config["SERVICE_TAGLINE"], + ) + + +@bp.route("/donnees_personnelles") +def donnees_personnelles(): + return render_template( + "footer/donnees_personnelles.html", + service_title=current_app.config["SERVICE_TITLE"], + service_tagline=current_app.config["SERVICE_TAGLINE"], + ) + + +@bp.route("/accessibilite") +def accessibilite(): + return render_template( + "footer/accessibilite.html", + service_title=current_app.config["SERVICE_TITLE"], + service_tagline=current_app.config["SERVICE_TAGLINE"], + ) + + +@bp.route("/documentation") +def documentation(): + if current_app.config["DOCUMENTATION_LINK"]["is_external"]: + return redirect(current_app.config["DOCUMENTATION_LINK"]["url"]) + return render_template( + "footer/documentation.html", + ) + + +@bp.route("/logout") +@auth.oidc_logout +def logout(): + return redirect(url_for("public.index")) + + +@bp.route("/faq") +def faq(): + return render_template( + "faq.html", + contents=FAQ_CONTENT, + ) diff --git a/web/flaskr/forms.py b/web/b3desk/forms.py similarity index 65% rename from web/flaskr/forms.py rename to web/b3desk/forms.py index 41f8e95f..7099b1df 100644 --- a/web/flaskr/forms.py +++ b/web/b3desk/forms.py @@ -1,21 +1,15 @@ from flask import current_app -from flask_babel import lazy_gettext +from flask_babel import lazy_gettext as _ from flask_wtf import FlaskForm from wtforms import BooleanField from wtforms import Form from wtforms import HiddenField from wtforms import IntegerField -from wtforms import SelectField from wtforms import StringField from wtforms import TextAreaField from wtforms import validators -class JoinMeetingAsRoleForm(Form): - role = SelectField(choices=["attendee", "moderator"]) - meeting_id = IntegerField() - - class JoinMeetingForm(FlaskForm): fullname = StringField() meeting_fake_id = StringField() @@ -51,45 +45,41 @@ class MeetingFilesForm(FlaskForm): class MeetingForm(FlaskForm): id = IntegerField() name = StringField( - label=lazy_gettext( + label=_( "Titre %(of_the_meeting)s", of_the_meeting=current_app.config["WORDING_OF_THE_MEETING"], ), - description=lazy_gettext( + description=_( "Créer %(a_meeting)s dont le titre est :", a_meeting=current_app.config["WORDING_A_MEETING"], ), - default=lazy_gettext( + default=_( "%(my_meeting)s", my_meeting=current_app.config["WORDING_MY_MEETING"].title(), ), validators=[validators.DataRequired()], ) welcome = TextAreaField( - label=lazy_gettext("Texte de bienvenue"), - description=lazy_gettext( + label=_("Texte de bienvenue"), + description=_( "Ce texte apparait comme message de bienvenue sur le tchat public" ), - default=lazy_gettext( + default=_( "Bienvenue dans %(this_meeting)s %(meeting_name)s.", this_meeting=current_app.config["WORDING_THIS_MEETING"], meeting_name=" %%CONFNAME%% ", ), render_kw={"rows": 3}, - validators=[ - validators.length(max=150, message=lazy_gettext("Le texte est trop long")) - ], + validators=[validators.length(max=150, message=_("Le texte est trop long"))], ) maxParticipants = IntegerField( - label=lazy_gettext("Nombre maximal de participants"), - description=lazy_gettext( - "Limitez vos salons à 250 personnes pour plus de confort" - ), + label=_("Nombre maximal de participants"), + description=_("Limitez vos salons à 250 personnes pour plus de confort"), default=100, ) duration = IntegerField( - label=lazy_gettext("Durée maximale en minutes"), - description=lazy_gettext( + label=_("Durée maximale en minutes"), + description=_( "Après laquelle %(the_meeting)s stoppe automatiquement", the_meeting=current_app.config["WORDING_THE_MEETING"], ), @@ -97,77 +87,69 @@ class MeetingForm(FlaskForm): validators=[validators.NumberRange(min=1, max=999)], ) guestPolicy = BooleanField( - label=lazy_gettext("Salle d'attente"), - description=lazy_gettext( + label=_("Salle d'attente"), + description=_( "Placer les participants dans une salle d'attente lorsqu'ils rejoignent %(the_meeting)s. L'organisateur ou le modérateur devra les accepter individuellement.", the_meeting=current_app.config["WORDING_THE_MEETING"], ), default=False, ) webcamsOnlyForModerator = BooleanField( - label=lazy_gettext( + label=_( "Seul les modérateurs peuvent voir les webcams des autres participants" ), - description=lazy_gettext( + description=_( "Les participants ne verront pas la diffusion de la caméra des autres" ), default=False, ) muteOnStart = BooleanField( - label=lazy_gettext("Micros fermés au démarrage"), - description=lazy_gettext( - "Les micros sont clos à la connexion des utilisateurs" - ), + label=_("Micros fermés au démarrage"), + description=_("Les micros sont clos à la connexion des utilisateurs"), default=True, ) lockSettingsDisableCam = BooleanField( - label=lazy_gettext("Verrouillage caméra"), - description=lazy_gettext( - "Les participants ne pourront pas activer leur caméra" - ), + label=_("Verrouillage caméra"), + description=_("Les participants ne pourront pas activer leur caméra"), default=False, ) lockSettingsDisableMic = BooleanField( - label=lazy_gettext("Verrouillage micro"), - description=lazy_gettext("Les participants ne pourront pas activer leur micro"), + label=_("Verrouillage micro"), + description=_("Les participants ne pourront pas activer leur micro"), default=False, ) lockSettingsDisablePrivateChat = BooleanField( - label=lazy_gettext("Désactivation de la discussion privée"), - description=lazy_gettext( - "Interdit les échanges textes directs entre participants" - ), + label=_("Désactivation de la discussion privée"), + description=_("Interdit les échanges textes directs entre participants"), default=False, ) lockSettingsDisablePublicChat = BooleanField( - label=lazy_gettext("Désactivation de la discussion publique"), - description=lazy_gettext("Pas de tchat"), + label=_("Désactivation de la discussion publique"), + description=_("Pas de tchat"), default=False, ) lockSettingsDisableNote = BooleanField( - label=lazy_gettext("Désactivation de la prise de notes"), - description=lazy_gettext("Pas de prise de notes collaborative"), + label=_("Désactivation de la prise de notes"), + description=_("Pas de prise de notes collaborative"), default=False, ) moderatorOnlyMessage = TextAreaField( - label=lazy_gettext("Message à l'attention des modérateurs"), - description=lazy_gettext("150 caractères max"), - default=lazy_gettext("Bienvenue aux modérateurs"), - validators=[ - validators.length(max=150, message=lazy_gettext("Le message est trop long")) - ], + label=_("Message à l'attention des modérateurs"), + description=_("150 caractères max"), + default=_("Bienvenue aux modérateurs"), + validators=[validators.length(max=150, message=_("Le message est trop long"))], render_kw={"rows": 3}, ) logoutUrl = StringField( - label=lazy_gettext( + label=_( "Url de redirection après %(the_meeting)s", the_meeting=current_app.config["WORDING_THE_MEETING"], ), default=current_app.config["MEETING_LOGOUT_URL"], ) moderatorPW = StringField( - label=lazy_gettext("Renouveler le lien modérateur"), - description=lazy_gettext( + label=_("Renouveler le lien modérateur"), + description=_( "Ce code vous permet si vous le changez de bloquer les anciens liens" ), default="Pa55W0rd1", @@ -175,8 +157,8 @@ class MeetingForm(FlaskForm): validators=[validators.DataRequired()], ) attendeePW = StringField( - label=lazy_gettext("Renouveler le lien participants"), - description=lazy_gettext( + label=_("Renouveler le lien participants"), + description=_( "Ce code vous permet si vous le changez de bloquer les anciens liens" ), default="Pa55W0rd2", @@ -191,15 +173,15 @@ def __init__(self, *args, **kwargs): class MeetingWithRecordForm(MeetingForm): allowStartStopRecording = BooleanField( - label=lazy_gettext("Enregistrement manuel"), - description=lazy_gettext( + label=_("Enregistrement manuel"), + description=_( "Autoriser le démarrage et l'arrêt de l'enregistrement par le modérateur" ), default=False, ) autoStartRecording = BooleanField( - label=lazy_gettext("Enregistrement automatique"), - description=lazy_gettext("Démarrage automatique"), + label=_("Enregistrement automatique"), + description=_("Démarrage automatique"), default=False, ) diff --git a/web/b3desk/models/__init__.py b/web/b3desk/models/__init__.py new file mode 100644 index 00000000..ec0a7985 --- /dev/null +++ b/web/b3desk/models/__init__.py @@ -0,0 +1,13 @@ +# +----------------------------------------------------------------------------+ +# | BBB-VISIO | +# +----------------------------------------------------------------------------+ +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the European Union Public License 1.2 version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() diff --git a/web/b3desk/models/bbb.py b/web/b3desk/models/bbb.py new file mode 100644 index 00000000..4a260a9c --- /dev/null +++ b/web/b3desk/models/bbb.py @@ -0,0 +1,323 @@ +# +----------------------------------------------------------------------------+ +# | BBB-VISIO | +# +----------------------------------------------------------------------------+ +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the European Union Public License 1.2 version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. +import hashlib +from datetime import datetime +from datetime import timezone +from urllib.parse import urlparse +from xml.etree import ElementTree + +import requests +from flask import current_app +from flask import render_template +from flask import url_for + +from b3desk.tasks import background_upload + +from .. import cache +from .roles import Role + + +def cache_key(func, caller, prepped, *args, **kwargs): + return prepped.url + + +def caching_exclusion(func, caller, prepped, *args, **kwargs): + """Only read-only methods should be cached.""" + url = urlparse(prepped.url) + endpoint_name = url.path.split("/")[-1] + return prepped.method != "GET" or endpoint_name not in ( + "isMeetingRunning", + "getMeetingInfo", + "getMeetings", + "getRecordings", + "getRecordingTextTracks", + ) + + +class BBB: + """Interface to BBB API.""" + + def __init__(self, meeting): + self.meeting = meeting + + def bbb_request(self, action, method="GET", **kwargs): + request = requests.Request( + method=method, + url="{}/{}".format(current_app.config["BIGBLUEBUTTON_ENDPOINT"], action), + **kwargs, + ) + prepped = request.prepare() + bigbluebutton_secret = current_app.config["BIGBLUEBUTTON_SECRET"] + secret = "{}{}".format( + prepped.url.replace("?", "").replace( + f'{current_app.config["BIGBLUEBUTTON_ENDPOINT"]}/', "" + ), + bigbluebutton_secret, + ) + checksum = hashlib.sha1(secret.encode("utf-8")).hexdigest() + prepped.prepare_url(prepped.url, params={"checksum": checksum}) + return prepped + + @cache.memoize( + unless=caching_exclusion, + timeout=current_app.config["BIGBLUEBUTTON_API_CACHE_DURATION"], + ) + def bbb_response(self, request): + session = requests.Session() + current_app.logger.debug("BBB API request %s: %s", request.method, request.url) + response = session.send(request) + return {c.tag: c.text for c in ElementTree.fromstring(response.content)} + + bbb_response.make_cache_key = cache_key + + def is_meeting_running(self): + """https://docs.bigbluebutton.org/development/api/#ismeetingrunning""" + request = self.bbb_request( + "isMeetingRunning", params={"meetingID": self.meeting.meetingID} + ) + return self.bbb_response(request) + + def create(self): + """https://docs.bigbluebutton.org/development/api/#create""" + + params = { + "meetingID": self.meeting.meetingID, + "name": self.meeting.name, + "uploadExternalUrl": url_for( + "meetings.externalUpload", meeting=self.meeting, _external=True + ), + "uploadExternalDescription": current_app.config[ + "EXTERNAL_UPLOAD_DESCRIPTION" + ], + } + if (param := self.meeting.record) is not None: + params["record"] = str(param).lower() + if (param := self.meeting.autoStartRecording) is not None: + params["autoStartRecording"] = str(param).lower() + if (param := self.meeting.allowStartStopRecording) is not None: + params["allowStartStopRecording"] = str(param).lower() + if (param := self.meeting.webcamsOnlyForModerator) is not None: + params["webcamsOnlyForModerator"] = str(param).lower() + if (param := self.meeting.muteOnStart) is not None: + params["muteOnStart"] = str(param).lower() + if (param := self.meeting.lockSettingsDisableCam) is not None: + params["lockSettingsDisableCam"] = str(param).lower() + if (param := self.meeting.lockSettingsDisableMic) is not None: + params["lockSettingsDisableMic"] = str(param).lower() + if (param := self.meeting.allowModsToUnmuteUsers) is not None: + params["allowModsToUnmuteUsers"] = str(param).lower() + if (param := self.meeting.lockSettingsDisablePrivateChat) is not None: + params["lockSettingsDisablePrivateChat"] = str(param).lower() + if (param := self.meeting.lockSettingsDisablePublicChat) is not None: + params["lockSettingsDisablePublicChat"] = str(param).lower() + if (param := self.meeting.lockSettingsDisableNote) is not None: + params["lockSettingsDisableNote"] = str(param).lower() + if param := self.meeting.attendeePW: + params["attendeePW"] = param + if param := self.meeting.moderatorPW: + params["moderatorPW"] = param + if param := self.meeting.welcome: + params["welcome"] = param + if param := self.meeting.maxParticipants: + params["maxParticipants"] = str(param) + if param := self.meeting.logoutUrl: + params["logoutURL"] = str(param) + if param := self.meeting.duration: + params["duration"] = str(param) + + # Pass the academy for statisticts purpose + # https://github.com/numerique-gouv/b3desk/issues/80 + if self.meeting.user and self.meeting.user.mail_domain: + params["meta_academy"] = self.meeting.user.mail_domain + + bigbluebutton_analytics_callback_url = current_app.config[ + "BIGBLUEBUTTON_ANALYTICS_CALLBACK_URL" + ] + if bigbluebutton_analytics_callback_url: + # bbb will call this endpoint when meeting ends + params.update( + { + "meetingKeepEvents": "true", + "meta_analytics-callback-url": str( + bigbluebutton_analytics_callback_url + ), + } + ) + if self.meeting.attendeePW is None: + # if no attendeePW it a meeting create with a mail (not logged in) + params["moderatorOnlyMessage"] = render_template( + "meeting/signin_mail_link.html", + main_message=self.meeting.moderatorOnlyMessage, + link=self.meeting.get_mail_signin_url(), + ) + else: + quick_meeting_moderator_link_introduction = current_app.config[ + "QUICK_MEETING_MODERATOR_LINK_INTRODUCTION" + ] + quick_meeting_attendee_link_introduction = current_app.config[ + "QUICK_MEETING_ATTENDEE_LINK_INTRODUCTION" + ] + params["moderatorOnlyMessage"] = render_template( + "meeting/signin_links.html", + moderator_message=self.meeting.moderatorOnlyMessage, + moderator_link_introduction=quick_meeting_moderator_link_introduction, + moderator_signin_url=self.meeting.get_signin_url(Role.moderator), + attendee_link_introduction=quick_meeting_attendee_link_introduction, + attendee_signin_url=self.meeting.get_signin_url(Role.attendee), + ) + params["guestPolicy"] = ( + "ASK_MODERATOR" if self.meeting.guestPolicy else "ALWAYS_ACCEPT" + ) + + if not current_app.config["FILE_SHARING"]: + request = self.bbb_request("create", params=params) + return self.bbb_response(request) + + # default file is sent right away since it is need as the background + # image for the meeting + xml = ( + self.meeting_file_addition_xml([self.meeting.default_file]) + if self.meeting.default_file + else None + ) + request = self.bbb_request("create", "POST", params=params, data=xml) + data = self.bbb_response(request) + + # non default files are sent later + if self.meeting.non_default_files: + xml = self.meeting_file_addition_xml(self.meeting.non_default_files) + request = self.bbb_request( + "insertDocument", params={"meetingID": self.meeting.meetingID} + ) + background_upload.delay(request.url, xml) + + return data + + def delete_recordings(self, recording_ids): + """https://docs.bigbluebutton.org/dev/api.html#deleterecordings""" + request = self.bbb_request( + "deleteRecordings", params={"recordID": recording_ids} + ) + return self.bbb_response(request) + + def get_meeting_info(self): + """https://docs.bigbluebutton.org/development/api/#getmeetinginfo""" + request = self.bbb_request( + "getMeetingInfo", params={"meetingID": self.meeting.meetingID} + ) + return self.bbb_response(request) + + @cache.memoize(timeout=current_app.config["BIGBLUEBUTTON_API_CACHE_DURATION"]) + def get_recordings(self): + """https://docs.bigbluebutton.org/development/api/#getrecordings""" + request = self.bbb_request( + "getRecordings", params={"meetingID": self.meeting.meetingID} + ) + current_app.logger.debug("BBB API request %s: %s", request.method, request.url) + response = requests.Session().send(request) + + root = ElementTree.fromstring(response.content) + return_code = root.find("returncode").text + recordings = root.find("recordings") + result = [] + if return_code != "FAILED" and recordings: + try: + for recording in recordings.iter("recording"): + data = {} + data["recordID"] = recording.find("recordID").text + name = recording.find("metadata").find("name") + data["name"] = name.text if name is not None else None + data["participants"] = int(recording.find("participants").text) + data["start_date"] = datetime.fromtimestamp( + int(recording.find("startTime").text) / 1000.0, tz=timezone.utc + ).replace(microsecond=0) + data["end_date"] = datetime.fromtimestamp( + int(recording.find("endTime").text) / 1000.0, tz=timezone.utc + ).replace(microsecond=0) + + data["playbacks"] = {} + playback = recording.find("playback") + if not playback: + continue + + for format in playback.iter("format"): + images = [] + preview = format.find("preview") + if preview is not None: + for i in ( + format.find("preview").find("images").iter("image") + ): + image = {k: v for k, v in i.attrib.items()} + image["url"] = i.text + images.append(image) + type = format.find("type").text + if type in ("presentation", "video"): + data["playbacks"][type] = { + "url": format.find("url").text, + "images": images, + } + result.append(data) + except Exception as exception: + current_app.logger.error(exception) + return result + + def update_recordings(self, recording_ids, metadata): + """https://docs.bigbluebutton.org/dev/api.html#updaterecordings""" + meta = {f"meta_{key}": value for (key, value) in metadata.items()} + request = self.bbb_request( + "updateRecordings", params={"recordID": ",".join(recording_ids), **meta} + ) + return self.bbb_response(request) + + def prepare_request_to_join_bbb(self, meeting_role, fullname): + """https://docs.bigbluebutton.org/dev/api.html#join""" + + params = { + "fullName": fullname, + "meetingID": self.meeting.meetingID, + "redirect": "true", + } + if meeting_role == Role.attendee: + params["role"] = "viewer" + params["guest"] = "true" + elif meeting_role == Role.authenticated: + params["role"] = "viewer" + elif meeting_role == Role.moderator: + params["role"] = "moderator" + + return self.bbb_request("join", params=params) + + def end(self): + """https://docs.bigbluebutton.org/development/api/#end""" + request = self.bbb_request("end", params={"meetingID": self.meeting.meetingID}) + return self.bbb_response(request) + + def meeting_file_addition_xml(self, meeting_files): + xml_beg = " " + xml_end = " " + xml_mid = "" + for meeting_file in meeting_files: + if meeting_file.url: + xml_mid += f"" + else: # file is not URL nor NC hence it was uploaded + filehash = hashlib.sha1( + f"{current_app.config['SECRET_KEY']}-0-{meeting_file.id}-{current_app.config['SECRET_KEY']}".encode() + ).hexdigest() + url = url_for( + "meeting_files.ncdownload", + isexternal=0, + mfid=meeting_file.id, + mftoken=filehash, + _external=True, + ) + xml_mid += f"" + + return xml_beg + xml_mid + xml_end diff --git a/web/b3desk/models/meetings.py b/web/b3desk/models/meetings.py new file mode 100644 index 00000000..fe1fd71c --- /dev/null +++ b/web/b3desk/models/meetings.py @@ -0,0 +1,342 @@ +# +----------------------------------------------------------------------------+ +# | BBB-VISIO | +# +----------------------------------------------------------------------------+ +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the European Union Public License 1.2 version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. +import hashlib +from datetime import datetime +from datetime import timedelta +from typing import Optional + +from flask import current_app +from flask import url_for +from sqlalchemy_utils import StringEncryptedType + +from b3desk.utils import get_random_alphanumeric_string +from b3desk.utils import secret_key + +from . import db +from .roles import Role +from .users import User + +MODERATOR_ONLY_MESSAGE_MAXLENGTH = 150 + + +class MeetingFiles(db.Model): + id = db.Column(db.Integer, primary_key=True) + title = db.Column(db.Unicode(4096)) + url = db.Column(db.Unicode(4096)) + nc_path = db.Column(db.Unicode(4096)) + meeting_id = db.Column(db.Integer, db.ForeignKey("meeting.id"), nullable=False) + is_default = db.Column(db.Boolean, default=False) + is_downloadable = db.Column(db.Boolean, default=False) + created_at = db.Column(db.Date) + + meeting = db.relationship("Meeting", back_populates="files") + + @property + def short_title(self): + return ( + self.title + if len(self.title) < 70 + else f"{self.title[:30]}...{self.title[-30:]}" + ) + + def update(self): + db.session.commit() + + def save(self): + db.session.add(self) + db.session.commit() + + +class MeetingFilesExternal(db.Model): + id = db.Column(db.Integer, primary_key=True) + title = db.Column(db.Unicode(4096)) + nc_path = db.Column(db.Unicode(4096)) + meeting_id = db.Column(db.Integer, db.ForeignKey("meeting.id"), nullable=False) + + meeting = db.relationship("Meeting", back_populates="externalFiles") + + def update(self): + db.session.commit() + + def save(self): + db.session.add(self) + db.session.commit() + + +class Meeting(db.Model): + id = db.Column(db.Integer, primary_key=True) + user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) + + user = db.relationship("User", back_populates="meetings") + files = db.relationship("MeetingFiles", back_populates="meeting") + externalFiles = db.relationship("MeetingFilesExternal", back_populates="meeting") + + # BBB params + name = db.Column(db.Unicode(150)) + attendeePW = db.Column(StringEncryptedType(db.Unicode(50), secret_key())) + moderatorPW = db.Column(StringEncryptedType(db.Unicode(50), secret_key())) + welcome = db.Column(db.UnicodeText()) + dialNumber = db.Column(db.Unicode(50)) + voiceBridge = db.Column(db.Unicode(50)) + maxParticipants = db.Column(db.Integer) + logoutUrl = db.Column(db.Unicode(250)) + record = db.Column(db.Boolean, unique=False, default=True) + duration = db.Column(db.Integer) + moderatorOnlyMessage = db.Column(db.Unicode(MODERATOR_ONLY_MESSAGE_MAXLENGTH)) + autoStartRecording = db.Column(db.Boolean, unique=False, default=True) + allowStartStopRecording = db.Column(db.Boolean, unique=False, default=True) + webcamsOnlyForModerator = db.Column(db.Boolean, unique=False, default=True) + muteOnStart = db.Column(db.Boolean, unique=False, default=True) + lockSettingsDisableCam = db.Column(db.Boolean, unique=False, default=True) + lockSettingsDisableMic = db.Column(db.Boolean, unique=False, default=True) + allowModsToUnmuteUsers = db.Column(db.Boolean, unique=False, default=False) + lockSettingsDisablePrivateChat = db.Column(db.Boolean, unique=False, default=True) + lockSettingsDisablePublicChat = db.Column(db.Boolean, unique=False, default=True) + lockSettingsDisableNote = db.Column(db.Boolean, unique=False, default=True) + guestPolicy = db.Column(db.Boolean, unique=False, default=True) + logo = db.Column(db.Unicode(200)) + user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) + + user = db.relationship("User") + + _bbb = None + + @property + def bbb(self): + from .bbb import BBB + + if not self._bbb: + self._bbb = BBB(self) + return self._bbb + + @property + def default_file(self): + for mfile in self.files: + if mfile.is_default: + return mfile + return None + + @property + def non_default_files(self): + return [ + meeting_file for meeting_file in self.files if not meeting_file.is_default + ] + + @property + def meetingID(self): + if self.id is not None: + fid = "meeting-persistent-%i" % (self.id) + else: + fid = "meeting-vanish-%s" % (self.fake_id) + return "{}--{}".format(fid, self.user.hash if self.user else "") + + @property + def fake_id(self): + if self.id is not None: + return self.id + else: + try: + return self._fake_id + except: + return None + + @fake_id.setter + def fake_id(self, fake_value): + self._fake_id = fake_value + + @fake_id.deleter + def fake_id(self): + del self._fake_id + + def get_hash(self, role: Role): + s = f"{self.meetingID}|{self.attendeePW}|{self.name}|{role}" + return hashlib.sha1(s.encode("utf-8")).hexdigest() + + def is_running(self): + data = self.bbb.is_meeting_running() + return data and data["returncode"] == "SUCCESS" and data["running"] == "true" + + def create_bbb(self): + result = self.bbb.create() + if result and result["returncode"] == "SUCCESS": + if self.id is None: + self.attendeePW = result["attendeePW"] + self.moderatorPW = result["moderatorPW"] + return result if result else {} + + def save(self): + db.session.add(self) + db.session.commit() + + def delete_recordings(self, recording_ids): + return self.bbb.delete_recordings(recording_ids) + + def delete_all_recordings(self): + recordings = self.get_recordings() + if not recordings: + return {} + recording_ids = ",".join( + [recording.get("recordID", "") for recording in recordings] + ) + return self.delete_recordings(recording_ids) + + def get_recordings(self): + return self.bbb.get_recordings() + + def update_recording_name(self, recording_id, name): + return self.bbb.update_recordings( + recording_ids=[recording_id], metadata={"name": name} + ) + + def get_join_url( + self, meeting_role: Role, fullname, fullname_suffix="", create=False + ): + is_meeting_available = self.is_running() + should_create_room = ( + not is_meeting_available and (meeting_role == Role.moderator) and create + ) + if should_create_room: + data = self.create_bbb() + if "returncode" in data and data["returncode"] == "SUCCESS": + is_meeting_available = True + + if is_meeting_available: + nickname = ( + f"{fullname} - {fullname_suffix}" if fullname_suffix else fullname + ) + return self.bbb.prepare_request_to_join_bbb(meeting_role, nickname).url + + return url_for( + "join.waiting_meeting", + meeting_fake_id=self.fake_id, + creator=self.user, + h=self.get_hash(meeting_role), + fullname=fullname, + fullname_suffix=fullname_suffix, + ) + + def get_signin_url(self, meeting_role: Role): + return url_for( + "join.signin_meeting", + meeting_fake_id=self.fake_id, + creator=self.user, + h=self.get_hash(meeting_role), + role=meeting_role, + _external=True, + ) + + def get_mail_signin_hash(self, meeting_id, expiration_epoch): + s = f"{meeting_id}-{expiration_epoch}" + return hashlib.sha256( + s.encode("utf-8") + secret_key().encode("utf-8") + ).hexdigest() + + def get_mail_signin_url(self): + expiration = str((datetime.now() + timedelta(weeks=1)).timestamp()).split(".")[ + 0 + ] # remove milliseconds + hash_param = self.get_mail_signin_hash(self.fake_id, expiration) + return url_for( + "join.signin_mail_meeting", + meeting_fake_id=self.fake_id, + expiration=expiration, + h=hash_param, + _external=True, + ) + + def get_role(self, hashed_role, user_id=None) -> Optional[Role]: + if user_id and self.user.id == user_id: + return Role.moderator + elif self.get_hash(Role.attendee) == hashed_role: + role = Role.attendee + elif self.get_hash(Role.moderator) == hashed_role: + role = Role.moderator + elif self.get_hash(Role.authenticated) == hashed_role: + role = ( + Role.authenticated + if current_app.config["OIDC_ATTENDEE_ENABLED"] + else Role.attendee + ) + else: + role = None + return role + + def end_bbb(self): + data = self.bbb.end() + return data and data["returncode"] == "SUCCESS" + + +def get_quick_meeting_from_user_and_random_string(user, random_string=None): + if random_string is None: + random_string = get_random_alphanumeric_string(8) + + meeting = Meeting( + duration=current_app.config["DEFAULT_MEETING_DURATION"], + user=user, + name=current_app.config["QUICK_MEETING_DEFAULT_NAME"], + moderatorPW=f"{user.hash}-{random_string}", + attendeePW=f"{random_string}-{random_string}", + moderatorOnlyMessage=current_app.config[ + "QUICK_MEETING_MODERATOR_WELCOME_MESSAGE" + ], + logoutUrl=( + current_app.config["QUICK_MEETING_LOGOUT_URL"] + or url_for("public.index", _external=True) + ), + ) + meeting.fake_id = random_string + return meeting + + +def get_meeting_from_meeting_id_and_user_id(meeting_fake_id, user_id): + if meeting_fake_id.isdigit(): + try: + meeting = db.session.get(Meeting, meeting_fake_id) + except: + try: + user = db.session.get(User, user_id) + meeting = get_quick_meeting_from_user_and_random_string( + user, random_string=meeting_fake_id + ) + except: + meeting = None + else: + try: + user = db.session.get(User, user_id) + meeting = get_quick_meeting_from_user_and_random_string( + user, random_string=meeting_fake_id + ) + except: + meeting = None + + return meeting + + +def get_mail_meeting(random_string=None): + # only used for mail meeting + if random_string is None: + random_string = get_random_alphanumeric_string(8) + + meeting = Meeting( + duration=current_app.config["DEFAULT_MEETING_DURATION"], + name=current_app.config["QUICK_MEETING_DEFAULT_NAME"], + moderatorPW="{}-{}".format( + random_string, + random_string, + ), # it is only usefull for bbb + moderatorOnlyMessage=current_app.config["MAIL_MODERATOR_WELCOME_MESSAGE"], + logoutUrl=( + current_app.config["QUICK_MEETING_LOGOUT_URL"] + or url_for("public.index", _external=True) + ), + ) + meeting.fake_id = random_string + return meeting diff --git a/web/b3desk/models/roles.py b/web/b3desk/models/roles.py new file mode 100644 index 00000000..a6573a2b --- /dev/null +++ b/web/b3desk/models/roles.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class Role(Enum): + attendee = "invité" + moderator = "modérateur" + authenticated = "authentifié" diff --git a/web/b3desk/models/users.py b/web/b3desk/models/users.py new file mode 100644 index 00000000..6c9d11bb --- /dev/null +++ b/web/b3desk/models/users.py @@ -0,0 +1,198 @@ +# +----------------------------------------------------------------------------+ +# | BBB-VISIO | +# +----------------------------------------------------------------------------+ +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the European Union Public License 1.2 version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. +import hashlib +from datetime import date +from datetime import datetime +from urllib.parse import urlparse +from urllib.parse import urlunparse + +import requests +from flask import current_app + +from b3desk.utils import secret_key + +from . import db + + +def make_nextcloud_credentials_request(url, payload, headers): + try: + response = requests.post(url, json=payload, headers=headers) + data = response.json() + if current_app.config.get("FORCE_HTTPS_ON_EXTERNAL_URLS"): + valid_nclocator = ( + f'//{data["nclocator"]}' + if not ( + data["nclocator"].startswith("//") + or data["nclocator"].startswith("http://") + or data["nclocator"].startswith("https://") + ) + else data["nclocator"] + ) + parsed_url = urlparse(valid_nclocator) + if parsed_url.scheme != "https": + data["nclocator"] = urlunparse(parsed_url._replace(scheme="https")) + return data + + except requests.exceptions.RequestException: + return None + + +def get_user_nc_credentials(username): + if ( + not current_app.config["NC_LOGIN_API_KEY"] + or not current_app.config["NC_LOGIN_API_URL"] + or not current_app.config["FILE_SHARING"] + or not username + ): + current_app.logger.debug( + "File sharing deactivated or unable to perform, no connection to Nextcloud instance" + ) + return {"nctoken": None, "nclocator": None, "nclogin": None} + + payload = {"username": username} + headers = {"X-API-KEY": current_app.config["NC_LOGIN_API_KEY"]} + current_app.logger.info( + "Retrieve NC credentials from NC_LOGIN_API_URL %s " + % current_app.config["NC_LOGIN_API_URL"] + ) + result = make_nextcloud_credentials_request( + current_app.config["NC_LOGIN_API_URL"], payload, headers + ) + if not result: + current_app.logger.error( + "Cannot contact NC %s, returning None values", + current_app.config["NC_LOGIN_API_URL"], + ) + return {"nctoken": None, "nclocator": None, "nclogin": None} + return result + + +def update_user_nc_credentials(user, user_info): + # preferred_username is login from keycloak, REQUIRED for nc_login connexion + # data is conveyed like following : + # user logs in to keycloak + # visio-agent retrives preferred_username from keycloack ( aka keycloak LOGIN, which is immutable ) + # visio-agent calls EDNAT API for NC_DATA retrieval, passing LOGIN as postData + # visio-agent can now connect to remote NC with NC_DATA + if ( + user.nc_last_auto_enroll + and user.nc_locator + and user.nc_token + and ( + (datetime.now() - user.nc_last_auto_enroll).days + <= current_app.config["NC_LOGIN_TIMEDELTA_DAYS"] + ) + ): + return False + + preferred_username = ( + user_info.get("preferred_username") + if current_app.config["FILE_SHARING"] + else None + ) + data = get_user_nc_credentials(preferred_username) + if ( + preferred_username is None + or data["nclocator"] is None + or data["nctoken"] is None + ): + nc_last_auto_enroll = None + else: + nc_last_auto_enroll = datetime.now() + + user.nc_locator = data["nclocator"] + user.nc_token = data["nctoken"] + user.nc_login = preferred_username + user.nc_last_auto_enroll = nc_last_auto_enroll + return True + + +def get_or_create_user(user_info): + given_name = user_info["given_name"] + family_name = user_info["family_name"] + email = user_info["email"].lower() + + user = User.query.filter_by(email=email).first() + + if user is None: + user = User( + email=email, + given_name=given_name, + family_name=family_name, + last_connection_utc_datetime=datetime.utcnow(), + ) + update_user_nc_credentials(user, user_info) + user.save() + + else: + user_has_changed = update_user_nc_credentials(user, user_info) + + if user.given_name != given_name: + user.given_name = given_name + user_has_changed = True + + if user.family_name != family_name: + user.family_name = family_name + user_has_changed = True + + if ( + not user.last_connection_utc_datetime + or user.last_connection_utc_datetime.date() < date.today() + ): + user.last_connection_utc_datetime = datetime.utcnow() + user_has_changed = True + + if user_has_changed: + user.save() + + return user + + +class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + email = db.Column(db.Unicode(150), unique=True) + given_name = db.Column(db.Unicode(50)) + family_name = db.Column(db.Unicode(50)) + nc_locator = db.Column(db.Unicode(255)) + nc_login = db.Column(db.Unicode(255)) + nc_token = db.Column(db.Unicode(255)) + nc_last_auto_enroll = db.Column(db.DateTime) + last_connection_utc_datetime = db.Column(db.DateTime) + + meetings = db.relationship("Meeting", back_populates="user") + + @property + def fullname(self): + return f"{self.given_name} {self.family_name}" + + @property + def hash(self): + s = f"{self.email}|{secret_key()}" + return hashlib.sha1(s.encode("utf-8")).hexdigest() + + @property + def can_create_meetings(self): + return len(self.meetings) < current_app.config["MAX_MEETINGS_PER_USER"] + + @property + def mail_domain(self): + return self.email.split("@")[1] if self.email and "@" in self.email else None + + def save(self): + db.session.add(self) + db.session.commit() + + def disable_nextcloud(self): + self.nc_login = None + self.nc_locator = None + self.nc_token = None + self.nc_last_auto_enroll = None + self.save() diff --git a/web/b3desk/session.py b/web/b3desk/session.py new file mode 100644 index 00000000..2394e9b7 --- /dev/null +++ b/web/b3desk/session.py @@ -0,0 +1,49 @@ +from functools import wraps + +from flask import abort +from flask import current_app +from flask import g +from flask import session +from flask_pyoidc.user_session import UserSession + +from b3desk.models.users import get_or_create_user + + +def get_current_user(): + if "user" not in g: + user_session = UserSession(session) + info = user_session.userinfo + g.user = get_or_create_user(info) + current_app.logger.debug( + f"User authenticated with token: {user_session.access_token}" + ) + return g.user + + +def has_user_session(): + user_session = UserSession(dict(session), "default") + return user_session.is_authenticated() + + +def get_authenticated_attendee_fullname(): + attendee_session = UserSession(session) + attendee_info = attendee_session.userinfo + given_name = attendee_info.get("given_name", "").title() + family_name = attendee_info.get("family_name", "").title() + fullname = f"{given_name} {family_name}".strip() + return fullname + + +def meeting_owner_needed(view_function): + @wraps(view_function) + def decorator(*args, **kwargs): + if not has_user_session(): + abort(403) + + user = get_current_user() + if not user or kwargs["meeting"].user != user: + abort(403) + + return view_function(*args, owner=user, **kwargs) + + return decorator diff --git a/web/b3desk/settings.py b/web/b3desk/settings.py new file mode 100644 index 00000000..df22b93d --- /dev/null +++ b/web/b3desk/settings.py @@ -0,0 +1,1029 @@ +import datetime +import json +from typing import Any +from typing import Dict +from typing import List +from typing import Optional + +from flask_babel import lazy_gettext as _ +from pydantic import ValidationInfo +from pydantic import computed_field +from pydantic import field_validator +from pydantic_settings import BaseSettings +from pydantic_settings import SettingsConfigDict + +from b3desk.constants import DEFAULT_EMAIL_WHITELIST + +AVAILABLE_WORDINGS = { + "MEETING": {"cours": "cours", "reunion": "réunion", "seminaire": "séminaire"}, + "MEETINGS": {"cours": "cours", "reunion": "réunions", "seminaire": "séminaires"}, + "A_MEETING": { + "cours": "un cours", + "reunion": "une réunion", + "seminaire": "un séminaire", + }, + "MY_MEETING": { + "cours": "mon cours", + "reunion": "ma réunion", + "seminaire": "mon séminaire", + }, + "THE_MEETING": { + "cours": "le cours", + "reunion": "la réunion", + "seminaire": "le séminaire", + }, + "OF_THE_MEETING": { + "cours": "du cours", + "reunion": "de la réunion", + "seminaire": "du séminaire", + }, + "THIS_MEETING": { + "cours": "ce cours", + "reunion": "cette réunion", + "seminaire": "ce séminaire", + }, + "TO_THE_MEETING": { + "cours": "au cours", + "reunion": "à la réunion", + "seminaire": "au séminaire", + }, + "IMPROVISED_MEETING": { + "cours": "cours improvisé", + "reunion": "réunion improvisée", + "seminaire": "séminaire improvisé", + }, + "AN_IMPROVISED_MEETING": { + "cours": "un cours improvisé", + "reunion": _("une réunion improvisée"), + "seminaire": "un séminaire improvisé", + }, + "A_QUICK_MEETING": { + "cours": "un cours immédiat", + "reunion": _("une réunion immédiate"), + "seminaire": "un séminaire immédiat", + }, + "PRIVATE_MEETINGS": { + "cours": "cours privés", + "reunion": _("réunions privées"), + "seminaire": "séminaires privés", + }, + "GOOD_MEETING": { + "cours": "bon cours", + "reunion": _("bonne réunion"), + "seminaire": "bon séminaire", + }, + "MEETING_UNDEFINED_ARTICLE": { + "cours": "un", + "reunion": _("une"), + "seminaire": "un", + }, + "A_MEETING_TO_WHICH": { + "cours": "un cours auquel", + "reunion": _("une réunion à laquelle"), + "seminaire": "un séminaire auquel", + }, + "WELCOME_PAGE_SUBTITLE": { + "cours": _( + "Créez en un clic un cours aux réglages standards. Il ne sera pas enregistré dans votre liste de salles." + ), + "reunion": _( + "Créez en un clic une réunion aux réglages standards. Elle ne sera pas enregistrée dans votre liste de salles." + ), + "seminaire": _( + "Créez en un clic un séminaire aux réglages standards. Il ne sera pas enregistré dans votre liste de salles." + ), + }, + "MEETING_MAIL_SUBJECT": { + "cours": _("Invitation à un cours en ligne immédiat du Webinaire de l’Etat"), + "reunion": _( + "Invitation à une réunion en ligne immédiat du Webinaire de l’Etat" + ), + "seminaire": _( + "Invitation à un séminaire en ligne immédiat du Webinaire de l’Etat" + ), + }, +} + + +class MainSettings(BaseSettings): + """Paramètres de configuration du frontal B3Desk.""" + + model_config = SettingsConfigDict(extra="allow") + + SECRET_KEY: str + """Clé secrète utilisée notamment pour la signature des cookies. Cette clé + DOIT être différente pour TOUTES les instances de B3Desk, et être tenue + secrète. Peut être générée avec ``python -c 'import secrets; + print(secrets.token_hex())'`` + + Plus d'infos sur + https://flask.palletsprojects.com/en/3.0.x/config/#SECRET_KEY + """ + + SERVER_NAME: str + """Le nom de domaine sur lequel est déployé l'instance B3Desk. + + Par exemple ``b3desk.example.org``, sans `https://`. + + Plus d'infos sur https://flask.palletsprojects.com/en/3.0.x/config/#SERVER_NAME. + """ + + PREFERRED_URL_SCHEME: str = "https" + """La méthode préférée utilisée pour générer des URL. Peut être `http` ou + `https`. + + Plus d'infos sur + https://flask.palletsprojects.com/en/3.0.x/config/#PREFERRED_URL_SCHEME. + """ + + REDIS_URL: Optional[str] = None + """L’URL du serveur redis utilisé pour les tâches asynchrones. + + Par exemple ``localhost:6379``. + """ + + NC_LOGIN_TIMEDELTA_DAYS: int = 30 + """Durée en jours avant l’expiration des autorisations Nextcloud.""" + + NC_LOGIN_API_URL: Optional[str] = None + """URL du fournisseur d'accès utilisé par Nextcloud. + + Par exemple ``https://auth.example.org``. + """ + + NC_LOGIN_API_KEY: Optional[str] = None + """Clé d'API Nextcloud.""" + + FORCE_HTTPS_ON_EXTERNAL_URLS: bool = False + """Force le protocole https pour les URLs Nextcloud.""" + + UPLOAD_DIR: str + """Chemin vers le dossier dans lequel seront stockés les fichiers + téléversés par les utilisateurs.""" + + TMP_DOWNLOAD_DIR: str + """Chemin vers un dossier qui servira de stockage temporaire de fichiers + entre Nextcloud et BBB.""" + + MAX_SIZE_UPLOAD: int = 20000000 + """Taille maximum des fichiers téléversés, en octets.""" + + TIME_FORMAT: str = "%Y-%m-%d" + """Format des dates utilisées lors des échanges avec l’API de Nextcloud. + + Plus d’informations sur + https://docs.python.org/fr/3/library/datetime.html#strftime-and-strptime-format-codes + """ + + TESTING: bool = False + """Mode tests unitaires, à ne surtout pas utiliser en production. + + Plus d’informations sur + https://flask.palletsprojects.com/en/3.0.x/config/#TESTING + """ + + DEBUG: bool = False + """Mode debug, à ne surtout pas utiliser en production. + + Plus d’informations sur + https://flask.palletsprojects.com/en/3.0.x/config/#DEBUG + """ + + TITLE: str = "BBB-Visio" + """Titre HTML par défaut pour les pages HTML.""" + + EXTERNAL_UPLOAD_DESCRIPTION: str = "Fichiers depuis votre Nextcloud" + """Description dans BBB des fichiers téléversés dans Nextcloud.""" + + WTF_CSRF_TIME_LIMIT: int = 3600 * 24 + """Indique en secondes la durée de validité des jetons CSRF. + + Il est nécessaire de mettre une valeur plus élevée que le délai de + mise en cache des pages par le serveur web. Sans quoi les + navigateurs des utilisateurs serviront des pages en caches contenant + des jetons CSRF expirés. + + Plus d'infos sur + https://flask-wtf.readthedocs.io/en/1.2.x/config/ + """ + + BABEL_TRANSLATION_DIRECTORIES: str = "/opt/bbb-visio/translations" + """Un ou plusieurs chemins vers les répertoires des catalogues de + traduction, séparés par des « ; ». + + Plus d’infos sur + https://python-babel.github.io/flask-babel/#configuration + """ + + MAX_MEETINGS_PER_USER: int = 50 + """Le nombre maximum de séminaires que peut créer un utilisateur.""" + + ALLOWED_MIME_TYPES_SERVER_SIDE: Optional[List[str]] = [ + "application/pdf", + "image/vnd.dwg", + "image/x-xcf", + "image/jpeg", + "image/jpx", + "image/png", + "image/apng", + "image/gif", + "image/webp", + "image/x-canon-cr2", + "image/tiff", + "image/bmp", + "image/vnd.ms-photo", + "image/vnd.adobe.photoshop", + "image/x-icon", + "image/heic", + "image/avif", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/vnd.oasis.opendocument.text", + "application/vnd.ms-excel", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "application/vnd.oasis.opendocument.spreadsheet", + "application/vnd.ms-powerpoint", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "application/vnd.oasis.opendocument.presentation", + ] + """Liste de mime-types acceptés par le serveur pour le téléversement de + fichiers. + + Si non renseigné, tous les fichiers sont autorisés. + """ + + @field_validator("ALLOWED_MIME_TYPES_SERVER_SIDE", mode="before") + def get_allowed_mime_types_server_side( + cls, + allowed_mime_types_server_side: Optional[List[str]], + info: ValidationInfo, + ) -> List[str]: + if not allowed_mime_types_server_side: + return [] + + if isinstance(allowed_mime_types_server_side, str): + return json.loads(allowed_mime_types_server_side) + + return allowed_mime_types_server_side + + ACCEPTED_FILES_CLIENT_SIDE: Optional[str] = ( + "image/*,.pdf,.doc,.docx,.htm,.html,.odp,.ods,.odt,.ppt,.pptx,.xls,.xlsx" + ) + """Liste de mime-types autorisés par le navigateur pour le téléversement + des fichiers, séparés par des virgules. + + Passé en paramètre ``acceptedFiles`` de *Dropzone*. + + Plus d’infos sur https://docs.dropzone.dev/configuration/basics/configuration-options + """ + + OIDC_ID_TOKEN_COOKIE_SECURE: bool = False + """Probablement un relicat de flask-oidc, semble inutilisé.""" + + OIDC_REQUIRE_VERIFIED_EMAIL: bool = False + """Probablement un relicat de flask-oidc, semble inutilisé.""" + + OIDC_USER_INFO_ENABLED: bool = True + """Probablement un relicat de flask-oidc, semble inutilisé.""" + + OIDC_OPENID_REALM: str = "apps" + """Probablement un relicat de flask-oidc, semble inutilisé.""" + + OIDC_SCOPES: List[str] = ["openid", "email", "profile"] + """Liste des scopes OpenID Connect pour lesquels une autorisation sera + demandée au serveur d’identité, séparés par des virgules. + + Passé en paramètre ``auth_request_params`` de flask-pyoidc. + Plus d’infos sur https://flask-pyoidc.readthedocs.io/en/latest/api.html#module-flask_pyoidc.provider_configuration + """ + + @field_validator("OIDC_SCOPES", mode="before") + def get_oidc_scopes(cls, oidc_scopes: List[str], info: ValidationInfo) -> str: + return oidc_scopes.split(",") if isinstance(oidc_scopes, str) else oidc_scopes + + OIDC_USERINFO_HTTP_METHOD: str = "POST" + """Méthode ``GET`` ou ``POST`` à utiliser pour les requêtes sur le point + d’entrée *UserInfo* du serveur d’identité. + + Plus d’infos sur + https://flask-pyoidc.readthedocs.io/en/latest/api.html?highlight=userinfo_http_method#flask_pyoidc.provider_configuration.ProviderConfiguration + """ + + OIDC_INFO_REQUESTED_FIELDS: List[str] = ["email", "given_name", "family_name"] + """Probablement un relicat de flask-oidc, semble inutilisé.""" + + OIDC_ISSUER: Optional[str] = None + """URL du serveur d’identité des organisateurs de réunion. + + Par exemple : https://auth.example.com + """ + + OIDC_AUTH_URI: Optional[str] = None + """Probablement un relicat de flask-oidc, semble inutilisé.""" + + OIDC_USERINFO_URI: Optional[str] = None + """Probablement un relicat de flask-oidc, semble inutilisé.""" + + OIDC_TOKEN_URI: Optional[str] = None + """Probablement un relicat de flask-oidc, semble inutilisé.""" + + OIDC_CLIENT_ID: Optional[str] = None + """ID du client auprès du serveur d’identité des organisateurs.""" + + OIDC_CLIENT_SECRET: Optional[str] = None + """Secret permettant d’identifier le client auprès du serveur d’identité + des organisateurs.""" + + OIDC_CLIENT_AUTH_METHOD: Optional[str] = "client_secret_post" + """Méthode de communication avec le point d’entrée ``token_endpoint`` du + serveur d’identité des organisateurs.""" + + OIDC_INTROSPECTION_AUTH_METHOD: str = "client_secret_basic" + """Méthode de communication avec le point d’entrée d’introspection + ``token_introspection`` du serveur d’identité des organisateurs.""" + + # TODO: replace by OIDCAuthentication.redirect_uri_config + OIDC_REDIRECT_URI: Optional[str] = None + """URL de B3Desk vers laquelle le serveur d’identité redirige les + utilisateurs après authentification. + + Par exemple ``http://localhost:5000/oidc_callback`` + + Plus d’infos sur https://flask-pyoidc.readthedocs.io/en/latest/configuration.html?highlight=OIDC_REDIRECT_URI#static-client-registration + """ + + OIDC_SERVICE_NAME: Optional[str] = None + """Probablement un relicat de flask-oidc, semble inutilisé à part en valeur + par défaut de ``OIDC_ATTENDEE_SERVICE_NAME``.""" + + # Attendee OIDC Configuration (back to default if empty) + OIDC_ATTENDEE_ENABLED: Optional[bool] = True + """Indique si le serveur d’authentification des participants est activé ou + non. + + Si le serveur est KO, en passant cette variable à ``False``, + l’authentification ne sera plus nécessaire pour les liens d’invitation authentifiés, ce qui permet de faire en sorte que les liens restent valides. + """ + + OIDC_ATTENDEE_ISSUER: Optional[str] = None + """URL du serveur d’identité des participants authentifiés. + + Si non renseigné, prend la valeur de ``OIDC_ISSUER``. + """ + + OIDC_ATTENDEE_CLIENT_ID: Optional[str] = None + """ID du client auprès du serveur d’identité des participants authentifiés. + + Si non renseigné, prend la valeur de ``OIDC_CLIENT_ID``. + """ + + OIDC_ATTENDEE_CLIENT_SECRET: Optional[str] = None + """Secret permettant d’identifier le client auprès du serveur d’identité + des participants authentifiés. + + Si non renseigné, prend la valeur de ``OIDC_CLIENT_ID``. + """ + + OIDC_ATTENDEE_CLIENT_AUTH_METHOD: Optional[str] = None + """Méthode de communication avec le point d’entrée ``token_endpoint`` du + serveur d’identité des participants authentifiés. + + Si non renseigné, prend la valeur de ``OIDC_CLIENT_AUTH_METHOD``. + """ + + OIDC_ATTENDEE_INTROSPECTION_AUTH_METHOD: str = "client_secret_basic" + """Méthode de communication avec le point d’entrée d’introspection + ``token_introspection`` du serveur d’identité des participants + authentifiés. + + Si non renseigné, prend la valeur de ``OIDC_INTROSPECTION_AUTH_METHOD``. + """ + + OIDC_ATTENDEE_USERINFO_HTTP_METHOD: Optional[str] = None + """Méthode ``GET`` ou ``POST`` à utiliser pour les requêtes sur le point + d’entrée *UserInfo* du serveur d’identité. + + Si non renseigné, prend la valeur de ``OIDC_USERINFO_HTTP_METHOD``. + + Plus d’infos sur https://flask-pyoidc.readthedocs.io/en/latest/api.html?highlight=userinfo_http_method#flask_pyoidc.provider_configuration.ProviderConfiguration + """ + + OIDC_ATTENDEE_SERVICE_NAME: Optional[str] = None + """Nom du service d’authentification des participants authentifiés. Utilisé + pour l’affichage dans la modale d’invitation de participants authentifés. + + Si non renseigné, prend la valeur de ``OIDC_SERVICE_NAME``. + """ + + OIDC_ATTENDEE_SCOPES: Optional[List[str]] = None + """Liste des scopes OpenID Connect pour lesquels une autorisation sera + demandée au serveur d’identité des participants authentifiés, séparés par + des virgules. + + Si non renseigné, prend la valeur de ``OIDC_SCOPES``. + + Passé en paramètre ``auth_request_params`` de flask-pyoidc. + Plus d’infos sur https://flask-pyoidc.readthedocs.io/en/latest/api.html#module-flask_pyoidc.provider_configuration + """ + + @field_validator("OIDC_ATTENDEE_ISSUER") + def get_attendee_issuer(cls, attendee_issuer: str, info: ValidationInfo) -> str: + return attendee_issuer or info.data.get("OIDC_ISSUER") + + @field_validator("OIDC_ATTENDEE_CLIENT_ID") + def get_attendee_client_id( + cls, attendee_client_id: str, info: ValidationInfo + ) -> str: + return attendee_client_id or info.data.get("OIDC_CLIENT_ID") + + @field_validator("OIDC_ATTENDEE_CLIENT_SECRET") + def get_attendee_client_secret( + cls, attendee_client_secret: str, info: ValidationInfo + ) -> str: + return attendee_client_secret or info.data.get("OIDC_CLIENT_SECRET") + + @field_validator("OIDC_ATTENDEE_CLIENT_AUTH_METHOD") + def get_attendee_client_auth_method( + cls, attendee_client_auth_method: str, info: ValidationInfo + ) -> str: + return attendee_client_auth_method or info.data.get("OIDC_CLIENT_AUTH_METHOD") + + @field_validator("OIDC_ATTENDEE_INTROSPECTION_AUTH_METHOD") + def get_attendee_introspection_endpoint_auth_method( + cls, attendee_introspection_endpoint_auth_method: str, info: ValidationInfo + ) -> str: + return attendee_introspection_endpoint_auth_method or info.data.get( + "OIDC_INTROSPECTION_AUTH_METHOD" + ) + + @field_validator("OIDC_ATTENDEE_USERINFO_HTTP_METHOD") + def get_attendee_userinfo_http_method( + cls, attendee_userinfo_http_method: str, info: ValidationInfo + ) -> str: + return attendee_userinfo_http_method or info.data.get( + "OIDC_USERINFO_HTTP_METHOD" + ) + + @field_validator("OIDC_ATTENDEE_SERVICE_NAME") + def get_attendee_attendee_service_name( + cls, attendee_attendee_service_name: str, info: ValidationInfo + ) -> str: + return attendee_attendee_service_name or info.data.get("OIDC_SERVICE_NAME") + + @field_validator("OIDC_ATTENDEE_SCOPES") + def get_attendee_attendee_scopes( + cls, attendee_scopes: str, info: ValidationInfo + ) -> str: + scopes = attendee_scopes or info.data.get("OIDC_SCOPES") + return scopes.split(",") if isinstance(scopes, str) else scopes + + DOCUMENTATION_LINK_URL: Optional[str] = None + """Surcharge l’adresse de la page de documentation si renseigné.""" + + DOCUMENTATION_LINK_LABEL: Optional[str] = None + """Semble inutilisé.""" + + @computed_field + def DOCUMENTATION_LINK(self) -> Dict[str, Any]: + return { + "url": self.DOCUMENTATION_LINK_URL, + "label": self.DOCUMENTATION_LINK_LABEL, + "is_external": self.DOCUMENTATION_LINK_URL + and self.DOCUMENTATION_LINK_URL.lower().startswith( + ("/", "http://", "https://") + ), + } + + SERVICE_TITLE: str = "Webinaire" + """Nom du service B3Desk.""" + + SERVICE_TAGLINE: str = "Le service de webinaire pour les agents de l’État" + """Slogan du service B3Desk.""" + + MEETING_LOGOUT_URL: Optional[str] = None + """URL vers laquelle sont redirigés les utilisateurs après un séminaire.""" + + SATISFACTION_POLL_URL: Optional[str] = None + """URL de l’iframe du formulaire de satisfaction.""" + + SQLALCHEMY_DATABASE_URI: str + """URI de configuration de la base de données. + + Par exemple ``postgresql://user:password@localhost:5432/bbb_visio`` + """ + + # TODO: delete as this is the default in flask-sqlalchemy 3? + SQLALCHEMY_TRACK_MODIFICATIONS: bool = False + """Traçage des évènements de modification des modèles dans SQLAlchemy. + + Plus d’informations sur + https://flask-sqlalchemy.palletsprojects.com/en/3.1.x/track-modifications/ + """ + + MEETING_KEY_WORDING: str = "reunion" + """Nommage des réunions. + + Peut-être *reunion*, *cours* ou *séminaire*. + """ + + WORDING_A_MEETING: Any = None + """Formulation de « une réunion », par exemple *un cours* ou *un + séminaire*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_A_MEETING") + def get_wording_a_meeting(cls, wording_a_meeting: Any, info: ValidationInfo) -> Any: + return ( + wording_a_meeting + or AVAILABLE_WORDINGS["A_MEETING"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_MY_MEETING: Any = None + """Formulation de « ma réunion », par exemple *mon cours* ou *mon + séminaire*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_MY_MEETING") + def get_wording_my_meeting( + cls, wording_my_meeting: Any, info: ValidationInfo + ) -> Any: + return ( + wording_my_meeting + or AVAILABLE_WORDINGS["MY_MEETING"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_THE_MEETING: Any = None + """Formulation de « la réunion », par exemple *le cours* ou *le séminaire*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_THE_MEETING") + def get_wording_the_meeting( + cls, wording_the_meeting: Any, info: ValidationInfo + ) -> Any: + return ( + wording_the_meeting + or AVAILABLE_WORDINGS["THE_MEETING"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_OF_THE_MEETING: Any = None + """Formulation de « de la réunion », par exemple *du cours* ou *du + séminaire*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_OF_THE_MEETING") + def get_wording_of_the_meeting( + cls, wording_of_the_meeting: Any, info: ValidationInfo + ) -> Any: + return ( + wording_of_the_meeting + or AVAILABLE_WORDINGS["OF_THE_MEETING"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_MEETING: Any = None + """Formulation de « réunion », par exemple *cours* ou *séminaire*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_MEETING") + def get_wording_meeting(cls, wording_meeting: Any, info: ValidationInfo) -> Any: + return ( + wording_meeting + or AVAILABLE_WORDINGS["MEETING"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_MEETINGS: Any = None + """Formulation de « réunions », par exemple *cours* ou *séminaires*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_MEETINGS") + def get_wording_meetings(cls, wording_meetings: Any, info: ValidationInfo) -> Any: + return ( + wording_meetings + or AVAILABLE_WORDINGS["MEETINGS"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_THIS_MEETING: Any = None + """Formulation de « cette réunion », par exemple *ce cours* ou *ce + séminaires*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_THIS_MEETING") + def get_wording_this_meeting( + cls, wording_this_meeting: Any, info: ValidationInfo + ) -> Any: + return ( + wording_this_meeting + or AVAILABLE_WORDINGS["THIS_MEETING"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_TO_THE_MEETING: Any = None + """Formulation de « à la réunion », par exemple *au cours* ou *au + séminaires*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_TO_THE_MEETING") + def get_wording_to_the_meeting( + cls, wording_to_the_meeting: Any, info: ValidationInfo + ) -> Any: + return ( + wording_to_the_meeting + or AVAILABLE_WORDINGS["TO_THE_MEETING"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_IMPROVISED_MEETING: Any = None + """Formulation de « réunion improvisée », par exemple *cours improvisé* ou + *séminaire improvisé*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_IMPROVISED_MEETING") + def get_wording_improvised_meeting( + cls, wording_improvised_meeting: Any, info: ValidationInfo + ) -> Any: + return ( + wording_improvised_meeting + or AVAILABLE_WORDINGS["IMPROVISED_MEETING"][ + info.data["MEETING_KEY_WORDING"] + ] + ) + + WORDING_AN_IMPROVISED_MEETING: Any = None + """Formulation de « une réunion improvisée », par exemple *un cours + improvisé* ou *un séminaire improvisé*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_AN_IMPROVISED_MEETING") + def get_wording_an_improvised_meeting( + cls, wording_an_improvised_meeting: Any, info: ValidationInfo + ) -> Any: + return ( + wording_an_improvised_meeting + or AVAILABLE_WORDINGS["AN_IMPROVISED_MEETING"][ + info.data["MEETING_KEY_WORDING"] + ] + ) + + WORDING_A_QUICK_MEETING: Any = None + """Formulation de « une réunion immédiate », par exemple *un cours + immédiat* ou *un séminaire immédiat*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_A_QUICK_MEETING") + def get_wording_a_quick_meeting( + cls, wording_a_quick_meeting: Any, info: ValidationInfo + ) -> Any: + return ( + wording_a_quick_meeting + or AVAILABLE_WORDINGS["A_QUICK_MEETING"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_PRIVATE_MEETINGS: Any = None + """Formulation de « réunions privées », par exemple *cours privés* ou + *séminaires privés*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_PRIVATE_MEETINGS") + def get_wording_private_meetings( + cls, wording_private_meetings: Any, info: ValidationInfo + ) -> Any: + return ( + wording_private_meetings + or AVAILABLE_WORDINGS["PRIVATE_MEETINGS"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_GOOD_MEETING: Any = None + """Formulation de « bonne réunion », par exemple *bon cours* ou *bon + séminaire*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_GOOD_MEETING") + def get_wording_good_meeting( + cls, wording_good_meeting: Any, info: ValidationInfo + ) -> Any: + return ( + wording_good_meeting + or AVAILABLE_WORDINGS["GOOD_MEETING"][info.data["MEETING_KEY_WORDING"]] + ) + + WORDING_MEETING_UNDEFINED_ARTICLE: Any = None + """Formulation de l’article indéterminé de « réunion » comme « une », par + exemple *un*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_MEETING_UNDEFINED_ARTICLE") + def get_wording_meeting_undefined_article( + cls, wording_meeting_undefined_article: Any, info: ValidationInfo + ) -> Any: + return ( + wording_meeting_undefined_article + or AVAILABLE_WORDINGS["MEETING_UNDEFINED_ARTICLE"][ + info.data["MEETING_KEY_WORDING"] + ] + ) + + WORDING_A_MEETING_TO_WHICH: Any = None + """Formulation de « une réunion à laquelle », par exemple *un cours auquel* + ou *un séminaire auquel*. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WORDING_A_MEETING_TO_WHICH") + def get_wording_a_meeting_to_which( + cls, wording_a_meeting_to_which: Any, info: ValidationInfo + ) -> Any: + return ( + wording_a_meeting_to_which + or AVAILABLE_WORDINGS["A_MEETING_TO_WHICH"][ + info.data["MEETING_KEY_WORDING"] + ] + ) + + WELCOME_PAGE_SUBTITLE: Any = None + """Formulation du sous-titre de la page de création de réunion. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("WELCOME_PAGE_SUBTITLE") + def get_welcome_page_subtitle( + cls, welcome_page_subtitle: Any, info: ValidationInfo + ) -> Any: + return ( + welcome_page_subtitle + or AVAILABLE_WORDINGS["WELCOME_PAGE_SUBTITLE"][ + info.data["MEETING_KEY_WORDING"] + ] + ) + + MEETING_MAIL_SUBJECT: Any = None + """Formulation du titre du mail d’invitation à une réunion. + + Par défaut s’adapte à ``MEETING_KEY_WORDING``. + """ + + @field_validator("MEETING_MAIL_SUBJECT") + def get_meeting_mail_subject( + cls, meeting_mail_subject: Any, info: ValidationInfo + ) -> Any: + return ( + meeting_mail_subject + or AVAILABLE_WORDINGS["MEETING_MAIL_SUBJECT"][ + info.data["MEETING_KEY_WORDING"] + ] + ) + + WORDING_MEETING_PRESENTATION: str = "présentation" + """Formulation de « présentation » qui désigne les fichiers accompagnant + les réunions.""" + + WORDING_UPLOAD_FILE: str = "envoyer" + """Semble inutilisé.""" + + FILE_SHARING: bool = False + """Active la fonctionnalité de téléversement de fichiers.""" + + DOCUMENTATION_PAGE_SUBTITLE: Optional[str] = None + """Sous-titre de la page de documentation.""" + + @computed_field + def WORDINGS(self) -> Dict[str, Any]: + return { + "a_meeting": self.WORDING_A_MEETING, + "the_meeting": self.WORDING_THE_MEETING, + "some_meetings": self.WORDING_MEETINGS, + "of_the_meeting": self.WORDING_OF_THE_MEETING, + "my_meeting": self.WORDING_MY_MEETING, + "this_meeting": self.WORDING_THIS_MEETING, + "meeting_label": self.WORDING_MEETING, + "meeting_presentation": self.WORDING_MEETING_PRESENTATION, + "upload_file_label": self.WORDING_UPLOAD_FILE, + "service_title": self.SERVICE_TITLE, + "service_tagline": self.SERVICE_TAGLINE, + "an_improvised_meeting": self.WORDING_AN_IMPROVISED_MEETING, + "private_meetings": self.WORDING_PRIVATE_MEETINGS, + "a_quick_meeting": self.WORDING_A_QUICK_MEETING, + "good_meeting": self.WORDING_GOOD_MEETING, + "to_the_meeting": self.WORDING_TO_THE_MEETING, + "meeting_undefined_article": self.WORDING_MEETING_UNDEFINED_ARTICLE, + "a_meeting_to_which": self.WORDING_A_MEETING_TO_WHICH, + "welcome_page_subtitle": self.WELCOME_PAGE_SUBTITLE, + "documentation_page_subtitle": self.DOCUMENTATION_PAGE_SUBTITLE, + "meeting_mail_subject": self.MEETING_MAIL_SUBJECT, + } + + QUICK_MEETING: bool = True + """Affiche le lien de création de réunions improvisées.""" + + QUICK_MEETING_DEFAULT_NAME: Optional[str] = None + """Nom par défaut des réunions improvisées. + + Par défaut prend la valeur de ``WORDING_IMPROVISED_MEETING``. + """ + + @field_validator("QUICK_MEETING_DEFAULT_NAME") + def get_quick_meeting_default_value( + cls, quick_meeting_default_value: Optional[str], info: ValidationInfo + ) -> Any: + return ( + quick_meeting_default_value + or info.data["WORDING_IMPROVISED_MEETING"].capitalize() + ) + + QUICK_MEETING_MODERATOR_LINK_INTRODUCTION: Any = _(" Lien Modérateur ") + """Formulation de « Lien Modérateur » dans les liens BBB.""" + + QUICK_MEETING_ATTENDEE_LINK_INTRODUCTION: Any = _(" Lien Participant ") + """Formulation de « Lien Participant » dans les liens BBB.""" + + QUICK_MEETING_MODERATOR_WELCOME_MESSAGE: Any = None + """Formulation du message d’accueil aux modérateurs dans BBB. + + Par défaut s’adapte à ``WORDING_THIS_MEETING``. + """ + + @field_validator("QUICK_MEETING_MODERATOR_WELCOME_MESSAGE") + def get_quick_meeting_moderator_welcome_message( + cls, + quick_meeting_moderator_welcome_message: Optional[str], + info: ValidationInfo, + ) -> Any: + return quick_meeting_moderator_welcome_message or _( + "Bienvenue aux modérateurs. Pour inviter quelqu'un à %(this_meeting)s, envoyez-lui l'un de ces liens :", + this_meeting=info.data["WORDING_THIS_MEETING"], + ) + + QUICK_MEETING_LOGOUT_URL: Optional[str] = None + """Lien vers lequel sont redirigés les participants à la fin d’une réunion + improvisée. + + Par défaut, c’est la page d’accueil du service B3Desk. + """ + + MAIL_MODERATOR_WELCOME_MESSAGE: Any = None + """Formulation du message d’accueil aux modérateurs dans BBB, dont le lien + à été envoyé par mail. + + Par défaut s’adapte à ``WORDING_THIS_MEETING``. + """ + + @field_validator("MAIL_MODERATOR_WELCOME_MESSAGE") + def get_moderator_welcome_message( + cls, moderator_welcome_message: Optional[str], info: ValidationInfo + ) -> Any: + return moderator_welcome_message or _( + "Bienvenue. Pour inviter quelqu'un à %(this_meeting)s, envoyez-lui l'un de ces liens :", + this_meeting=info.data["WORDING_THIS_MEETING"], + ) + + MAILTO_LINKS: bool = False + """Affiche des liens vers les adresses email des modérateurs et + participants dans la liste des réunions.""" + + SHORTY: bool = False + """Affichage court des listes de réunions.""" + + CLIPBOARD: bool = False + """Semble inutilisé.""" + + RECORDING: bool = False + """Active la fonctionnalité d’enregistrement des réunions.""" + + RECORDING_DURATION: Optional[datetime.timedelta] = datetime.timedelta(days=365) + """Durée par défaut de conservation des enregistrements. + + Utilisé à des fins d’affichage seulement. + """ + + BETA: bool = False + """Active l’encart « Bêta » dans l’entête du service B3Desk.""" + + MAIL_MEETING: bool = False + """Active l’organisation de réunion par envoi de liens par email.""" + + SMTP_FROM: Optional[str] = None + """Adresse email d’expéditeur pour les mails d’invitation.""" + + SMTP_HOST: Optional[str] = None + """Addresse du serveur SMTP.""" + + SMTP_PORT: Optional[int] = None + """Port du serveur SMTP.""" + + SMTP_USERNAME: Optional[str] = None + """Identifiant auprès du serveur SMTP.""" + + SMTP_PASSWORD: Optional[str] = None + """Mot de passe du serveur SMTP.""" + + SMTP_SSL: Optional[bool] = False + """Connexion SSL au serveur SMTP.""" + + SMTP_STARTTLS: Optional[bool] = False + """Connexion StartTLS au serveur SMTP.""" + + EMAIL_WHITELIST: Any = None + + @field_validator("EMAIL_WHITELIST") + def get_email_whitelist( + cls, email_whitelist: List[str], info: ValidationInfo + ) -> str: + if not email_whitelist: + return DEFAULT_EMAIL_WHITELIST + return ( + [email_whitelist] if isinstance(email_whitelist, str) else email_whitelist + ) + + DEFAULT_MEETING_DURATION: int = 280 + """Durée maximum en minutes des réunion passée à l'API BBB. + + Plus d’informations sur + https://docs.bigbluebutton.org/development/api/#create + """ + + RIE_NETWORK_IPS: Optional[List[str]] = None + """Plages d’adresses IP du réseau interministériel de l'État. + + Affiche un encart particulier pour les utilisateurs se connectant + depuis ce réseau. + """ + + @field_validator("RIE_NETWORK_IPS", mode="before") + def get_rie_network_ips( + cls, rie_network_ips: List[str], info: ValidationInfo + ) -> str: + return ( + rie_network_ips.split(",") + if isinstance(rie_network_ips, str) + else rie_network_ips + ) + + MAX_PARTICIPANTS: int = 200 + """Nombre moyen de participants indicatif sur la plateforme. + + Seulement utilisé à des fins d’affichage. + """ + + STATS_CACHE_DURATION: int = 1800 + """Durée de rétention du cache des statistiques des réunions.""" + + STATS_URL: Optional[str] = None + """URL du fichier de statistiques des réunions. + + Par exemple ``http://localhost:5000/static/local/stats.csv`` + """ + + STATS_INDEX: int = 2 + """Numéro de ligne des statistiques de réunion dans le fichier CSV.""" + + BIGBLUEBUTTON_ENDPOINT: Optional[str] = None + """URL du service BBB. + + Par exemple ``https://bbb26.test/bigbluebutton/api`` + """ + + BIGBLUEBUTTON_SECRET: Optional[str] = None + """Mot de passe du service BBB.""" + + BIGBLUEBUTTON_ANALYTICS_CALLBACK_URL: Optional[str] = None + """Passé à l'API BBB via le paramètre ``meta_analytics-callback-url``. + + Plus d’informations sur + https://docs.bigbluebutton.org/development/api/#create + """ + + MATOMO_URL: Optional[str] = None + """URL de l’instance de Matomo vers laquelle envoyer des statistiques.""" + + MATOMO_SITE_ID: Optional[str] = None + """ID de l’instance B3Desk dans Matomo.""" + + BIGBLUEBUTTON_API_CACHE_DURATION: int = 5 + """Le temps de mise en cache (en secondes) des réponses aux requêtes GET à + l'API BBB.""" diff --git a/web/flaskr/static/css/global.css b/web/b3desk/static/css/global.css similarity index 88% rename from web/flaskr/static/css/global.css rename to web/b3desk/static/css/global.css index 359e6b2a..56b13694 100644 --- a/web/flaskr/static/css/global.css +++ b/web/b3desk/static/css/global.css @@ -43,6 +43,12 @@ header.rf-header { background-size: auto 100%; background-position: center; } +.image-no-meetings { + background: url('../images/home.svg') no-repeat; + background-size: auto 60%; + background-position: top; + filter: grayscale(0.8) opacity(0.5); +} .alerte { width: 80%; margin: 2em auto; @@ -68,6 +74,7 @@ footer{ form.delete { display: inline-block; text-align: center; + width: 100%; } @@ -188,6 +195,7 @@ form.delete { #js-modal-overlay .invisible{ opacity: 0; } + /* modal */ .scampi-modal { left: 0; @@ -286,6 +294,13 @@ color: #000091; } overflow: scroll; } +.fr-btn--delete { + background-color: var(--background-action-high-red-marianne) !important; +} +.fr-btn--delete:hover { + background-color: var(--background-action-high-red-marianne-hover) !important; +} + #doc > a.anchor { display: inline; float: left; @@ -378,3 +393,22 @@ This is a fix until we deal with the update. padding: .5rem 1rem; } } + +.fr-btn--visio.fr-icon-live-line[target="_blank"]::after { + mask-image: url("../dsfr-1.7/icons/media/live-line.svg"); + mask-image: url("../dsfr-1.7/icons/media/live-line.svg"); +} + +.list-meeting-rooms-title { + display: flex; + justify-content: space-between; +} + +.list-meeting-rooms-title div { + margin: var(--title-spacing); + display: flex; +} + +.list-meeting-rooms-title div a { + align-self: flex-end; +} diff --git a/web/flaskr/static/css/jumbotron.css b/web/b3desk/static/css/jumbotron.css similarity index 100% rename from web/flaskr/static/css/jumbotron.css rename to web/b3desk/static/css/jumbotron.css diff --git a/web/flaskr/static/css/remixicon/remixicon.css b/web/b3desk/static/css/remixicon/remixicon.css similarity index 100% rename from web/flaskr/static/css/remixicon/remixicon.css rename to web/b3desk/static/css/remixicon/remixicon.css diff --git a/web/flaskr/static/css/remixicon/remixicon.eot b/web/b3desk/static/css/remixicon/remixicon.eot similarity index 100% rename from web/flaskr/static/css/remixicon/remixicon.eot rename to web/b3desk/static/css/remixicon/remixicon.eot diff --git a/web/flaskr/static/css/remixicon/remixicon.glyph.json b/web/b3desk/static/css/remixicon/remixicon.glyph.json similarity index 100% rename from web/flaskr/static/css/remixicon/remixicon.glyph.json rename to web/b3desk/static/css/remixicon/remixicon.glyph.json diff --git a/web/flaskr/static/css/remixicon/remixicon.less b/web/b3desk/static/css/remixicon/remixicon.less similarity index 100% rename from web/flaskr/static/css/remixicon/remixicon.less rename to web/b3desk/static/css/remixicon/remixicon.less diff --git a/web/flaskr/static/css/remixicon/remixicon.svg b/web/b3desk/static/css/remixicon/remixicon.svg similarity index 100% rename from web/flaskr/static/css/remixicon/remixicon.svg rename to web/b3desk/static/css/remixicon/remixicon.svg diff --git a/web/flaskr/static/css/remixicon/remixicon.symbol.svg b/web/b3desk/static/css/remixicon/remixicon.symbol.svg similarity index 100% rename from web/flaskr/static/css/remixicon/remixicon.symbol.svg rename to web/b3desk/static/css/remixicon/remixicon.symbol.svg diff --git a/web/flaskr/static/css/remixicon/remixicon.ttf b/web/b3desk/static/css/remixicon/remixicon.ttf similarity index 100% rename from web/flaskr/static/css/remixicon/remixicon.ttf rename to web/b3desk/static/css/remixicon/remixicon.ttf diff --git a/web/flaskr/static/css/remixicon/remixicon.woff b/web/b3desk/static/css/remixicon/remixicon.woff similarity index 100% rename from web/flaskr/static/css/remixicon/remixicon.woff rename to web/b3desk/static/css/remixicon/remixicon.woff diff --git a/web/flaskr/static/css/remixicon/remixicon.woff2 b/web/b3desk/static/css/remixicon/remixicon.woff2 similarity index 100% rename from web/flaskr/static/css/remixicon/remixicon.woff2 rename to web/b3desk/static/css/remixicon/remixicon.woff2 diff --git a/web/flaskr/static/css/spinner.css b/web/b3desk/static/css/spinner.css similarity index 100% rename from web/flaskr/static/css/spinner.css rename to web/b3desk/static/css/spinner.css diff --git a/web/flaskr/static/css/toc.css b/web/b3desk/static/css/toc.css similarity index 100% rename from web/flaskr/static/css/toc.css rename to web/b3desk/static/css/toc.css diff --git a/web/flaskr/static/dsfr-1.7/README.md b/web/b3desk/static/dsfr-1.7/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/README.md rename to web/b3desk/static/dsfr-1.7/README.md diff --git a/web/flaskr/static/dsfr-1.7/artwork/background/ovoid.svg b/web/b3desk/static/dsfr-1.7/artwork/background/ovoid.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/artwork/background/ovoid.svg rename to web/b3desk/static/dsfr-1.7/artwork/background/ovoid.svg diff --git a/web/flaskr/static/dsfr-1.7/artwork/dark.svg b/web/b3desk/static/dsfr-1.7/artwork/dark.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/artwork/dark.svg rename to web/b3desk/static/dsfr-1.7/artwork/dark.svg diff --git a/web/flaskr/static/dsfr-1.7/artwork/light.svg b/web/b3desk/static/dsfr-1.7/artwork/light.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/artwork/light.svg rename to web/b3desk/static/dsfr-1.7/artwork/light.svg diff --git a/web/flaskr/static/dsfr-1.7/artwork/system.svg b/web/b3desk/static/dsfr-1.7/artwork/system.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/artwork/system.svg rename to web/b3desk/static/dsfr-1.7/artwork/system.svg diff --git a/web/flaskr/static/dsfr-1.7/artwork/technical-error.svg b/web/b3desk/static/dsfr-1.7/artwork/technical-error.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/artwork/technical-error.svg rename to web/b3desk/static/dsfr-1.7/artwork/technical-error.svg diff --git a/web/flaskr/static/dsfr-1.7/artwork/test.svg b/web/b3desk/static/dsfr-1.7/artwork/test.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/artwork/test.svg rename to web/b3desk/static/dsfr-1.7/artwork/test.svg diff --git a/web/flaskr/static/dsfr-1.7/component/README.md b/web/b3desk/static/dsfr-1.7/component/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/README.md rename to web/b3desk/static/dsfr-1.7/component/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/README.md b/web/b3desk/static/dsfr-1.7/component/accordion/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/README.md rename to web/b3desk/static/dsfr-1.7/component/accordion/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.css b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.css rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.css diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.css.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.css.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.legacy.css b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.legacy.css rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.main.css b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.main.css rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.main.css.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.main.css.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.main.min.css b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.main.min.css rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.min.css b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.min.css rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.min.css.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.min.css.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.module.js b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.module.js rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.module.js.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.module.js.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.module.min.js b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.module.min.js rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.nomodule.js b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/accordion/accordion.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/accordion/accordion.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/accordion/accordion.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/accordion/accordion.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/alert/README.md b/web/b3desk/static/dsfr-1.7/component/alert/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/README.md rename to web/b3desk/static/dsfr-1.7/component/alert/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.css b/web/b3desk/static/dsfr-1.7/component/alert/alert.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.css rename to web/b3desk/static/dsfr-1.7/component/alert/alert.css diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.css.map b/web/b3desk/static/dsfr-1.7/component/alert/alert.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.css.map rename to web/b3desk/static/dsfr-1.7/component/alert/alert.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.legacy.css b/web/b3desk/static/dsfr-1.7/component/alert/alert.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.legacy.css rename to web/b3desk/static/dsfr-1.7/component/alert/alert.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/alert/alert.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/alert/alert.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/alert/alert.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/alert/alert.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/alert/alert.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/alert/alert.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.main.css b/web/b3desk/static/dsfr-1.7/component/alert/alert.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.main.css rename to web/b3desk/static/dsfr-1.7/component/alert/alert.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.main.css.map b/web/b3desk/static/dsfr-1.7/component/alert/alert.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.main.css.map rename to web/b3desk/static/dsfr-1.7/component/alert/alert.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.main.min.css b/web/b3desk/static/dsfr-1.7/component/alert/alert.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.main.min.css rename to web/b3desk/static/dsfr-1.7/component/alert/alert.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/alert/alert.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/alert/alert.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.min.css b/web/b3desk/static/dsfr-1.7/component/alert/alert.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.min.css rename to web/b3desk/static/dsfr-1.7/component/alert/alert.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/alert/alert.min.css.map b/web/b3desk/static/dsfr-1.7/component/alert/alert.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/alert/alert.min.css.map rename to web/b3desk/static/dsfr-1.7/component/alert/alert.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/badge/README.md b/web/b3desk/static/dsfr-1.7/component/badge/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/README.md rename to web/b3desk/static/dsfr-1.7/component/badge/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.css b/web/b3desk/static/dsfr-1.7/component/badge/badge.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.css rename to web/b3desk/static/dsfr-1.7/component/badge/badge.css diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.css.map b/web/b3desk/static/dsfr-1.7/component/badge/badge.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.css.map rename to web/b3desk/static/dsfr-1.7/component/badge/badge.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.legacy.css b/web/b3desk/static/dsfr-1.7/component/badge/badge.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.legacy.css rename to web/b3desk/static/dsfr-1.7/component/badge/badge.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/badge/badge.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/badge/badge.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/badge/badge.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/badge/badge.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/badge/badge.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/badge/badge.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.main.css b/web/b3desk/static/dsfr-1.7/component/badge/badge.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.main.css rename to web/b3desk/static/dsfr-1.7/component/badge/badge.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.main.css.map b/web/b3desk/static/dsfr-1.7/component/badge/badge.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.main.css.map rename to web/b3desk/static/dsfr-1.7/component/badge/badge.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.main.min.css b/web/b3desk/static/dsfr-1.7/component/badge/badge.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.main.min.css rename to web/b3desk/static/dsfr-1.7/component/badge/badge.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/badge/badge.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/badge/badge.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.min.css b/web/b3desk/static/dsfr-1.7/component/badge/badge.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.min.css rename to web/b3desk/static/dsfr-1.7/component/badge/badge.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/badge/badge.min.css.map b/web/b3desk/static/dsfr-1.7/component/badge/badge.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/badge/badge.min.css.map rename to web/b3desk/static/dsfr-1.7/component/badge/badge.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/README.md b/web/b3desk/static/dsfr-1.7/component/breadcrumb/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/README.md rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.css b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.css rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.css diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.css.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.css.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.css b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.css rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.css b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.css rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.css.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.css.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.min.css b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.min.css rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.min.css b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.min.css rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.min.css.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.min.css.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.js b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.js rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.js.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.js.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.min.js b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.min.js rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.js b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/breadcrumb/breadcrumb.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/README.md b/web/b3desk/static/dsfr-1.7/component/button/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/README.md rename to web/b3desk/static/dsfr-1.7/component/button/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.css b/web/b3desk/static/dsfr-1.7/component/button/button.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.css rename to web/b3desk/static/dsfr-1.7/component/button/button.css diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.css.map b/web/b3desk/static/dsfr-1.7/component/button/button.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.css.map rename to web/b3desk/static/dsfr-1.7/component/button/button.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.legacy.css b/web/b3desk/static/dsfr-1.7/component/button/button.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.legacy.css rename to web/b3desk/static/dsfr-1.7/component/button/button.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/button/button.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/button/button.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/button/button.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/button/button.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/button/button.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/button/button.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.main.css b/web/b3desk/static/dsfr-1.7/component/button/button.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.main.css rename to web/b3desk/static/dsfr-1.7/component/button/button.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.main.css.map b/web/b3desk/static/dsfr-1.7/component/button/button.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.main.css.map rename to web/b3desk/static/dsfr-1.7/component/button/button.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.main.min.css b/web/b3desk/static/dsfr-1.7/component/button/button.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.main.min.css rename to web/b3desk/static/dsfr-1.7/component/button/button.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/button/button.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/button/button.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.min.css b/web/b3desk/static/dsfr-1.7/component/button/button.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.min.css rename to web/b3desk/static/dsfr-1.7/component/button/button.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.min.css.map b/web/b3desk/static/dsfr-1.7/component/button/button.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.min.css.map rename to web/b3desk/static/dsfr-1.7/component/button/button.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.module.js b/web/b3desk/static/dsfr-1.7/component/button/button.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.module.js rename to web/b3desk/static/dsfr-1.7/component/button/button.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.module.js.map b/web/b3desk/static/dsfr-1.7/component/button/button.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.module.js.map rename to web/b3desk/static/dsfr-1.7/component/button/button.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.module.min.js b/web/b3desk/static/dsfr-1.7/component/button/button.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.module.min.js rename to web/b3desk/static/dsfr-1.7/component/button/button.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/button/button.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/button/button.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.nomodule.js b/web/b3desk/static/dsfr-1.7/component/button/button.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/button/button.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/button/button.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/button/button.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/button/button.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/button/button.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/button/button.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/button/button.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/button/button.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/button/button.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/callout/README.md b/web/b3desk/static/dsfr-1.7/component/callout/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/README.md rename to web/b3desk/static/dsfr-1.7/component/callout/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.css b/web/b3desk/static/dsfr-1.7/component/callout/callout.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.css rename to web/b3desk/static/dsfr-1.7/component/callout/callout.css diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.css.map b/web/b3desk/static/dsfr-1.7/component/callout/callout.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.css.map rename to web/b3desk/static/dsfr-1.7/component/callout/callout.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.legacy.css b/web/b3desk/static/dsfr-1.7/component/callout/callout.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.legacy.css rename to web/b3desk/static/dsfr-1.7/component/callout/callout.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/callout/callout.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/callout/callout.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/callout/callout.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/callout/callout.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/callout/callout.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/callout/callout.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.main.css b/web/b3desk/static/dsfr-1.7/component/callout/callout.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.main.css rename to web/b3desk/static/dsfr-1.7/component/callout/callout.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.main.css.map b/web/b3desk/static/dsfr-1.7/component/callout/callout.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.main.css.map rename to web/b3desk/static/dsfr-1.7/component/callout/callout.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.main.min.css b/web/b3desk/static/dsfr-1.7/component/callout/callout.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.main.min.css rename to web/b3desk/static/dsfr-1.7/component/callout/callout.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/callout/callout.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/callout/callout.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.min.css b/web/b3desk/static/dsfr-1.7/component/callout/callout.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.min.css rename to web/b3desk/static/dsfr-1.7/component/callout/callout.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/callout/callout.min.css.map b/web/b3desk/static/dsfr-1.7/component/callout/callout.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/callout/callout.min.css.map rename to web/b3desk/static/dsfr-1.7/component/callout/callout.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/card/README.md b/web/b3desk/static/dsfr-1.7/component/card/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/README.md rename to web/b3desk/static/dsfr-1.7/component/card/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.css b/web/b3desk/static/dsfr-1.7/component/card/card.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.css rename to web/b3desk/static/dsfr-1.7/component/card/card.css diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.css.map b/web/b3desk/static/dsfr-1.7/component/card/card.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.css.map rename to web/b3desk/static/dsfr-1.7/component/card/card.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.legacy.css b/web/b3desk/static/dsfr-1.7/component/card/card.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.legacy.css rename to web/b3desk/static/dsfr-1.7/component/card/card.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/card/card.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/card/card.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/card/card.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/card/card.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/card/card.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/card/card.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.main.css b/web/b3desk/static/dsfr-1.7/component/card/card.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.main.css rename to web/b3desk/static/dsfr-1.7/component/card/card.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.main.css.map b/web/b3desk/static/dsfr-1.7/component/card/card.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.main.css.map rename to web/b3desk/static/dsfr-1.7/component/card/card.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.main.min.css b/web/b3desk/static/dsfr-1.7/component/card/card.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.main.min.css rename to web/b3desk/static/dsfr-1.7/component/card/card.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/card/card.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/card/card.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.min.css b/web/b3desk/static/dsfr-1.7/component/card/card.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.min.css rename to web/b3desk/static/dsfr-1.7/component/card/card.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/card/card.min.css.map b/web/b3desk/static/dsfr-1.7/component/card/card.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/card/card.min.css.map rename to web/b3desk/static/dsfr-1.7/component/card/card.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/README.md b/web/b3desk/static/dsfr-1.7/component/checkbox/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/README.md rename to web/b3desk/static/dsfr-1.7/component/checkbox/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.css b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.css rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.css diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.css.map b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.css.map rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.legacy.css b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.legacy.css rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.main.css b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.main.css rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.main.css.map b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.main.css.map rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.main.min.css b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.main.min.css rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.min.css b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.min.css rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.min.css.map b/web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/checkbox/checkbox.min.css.map rename to web/b3desk/static/dsfr-1.7/component/checkbox/checkbox.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.css b/web/b3desk/static/dsfr-1.7/component/component.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.css rename to web/b3desk/static/dsfr-1.7/component/component.css diff --git a/web/flaskr/static/dsfr-1.7/component/component.css.map b/web/b3desk/static/dsfr-1.7/component/component.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.css.map rename to web/b3desk/static/dsfr-1.7/component/component.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.legacy.css b/web/b3desk/static/dsfr-1.7/component/component.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.legacy.css rename to web/b3desk/static/dsfr-1.7/component/component.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/component.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/component.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/component.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/component.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/component.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/component.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/component.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/component.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.main.css b/web/b3desk/static/dsfr-1.7/component/component.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.main.css rename to web/b3desk/static/dsfr-1.7/component/component.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/component.main.css.map b/web/b3desk/static/dsfr-1.7/component/component.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.main.css.map rename to web/b3desk/static/dsfr-1.7/component/component.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.main.min.css b/web/b3desk/static/dsfr-1.7/component/component.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.main.min.css rename to web/b3desk/static/dsfr-1.7/component/component.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/component.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/component.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/component.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.min.css b/web/b3desk/static/dsfr-1.7/component/component.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.min.css rename to web/b3desk/static/dsfr-1.7/component/component.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/component.min.css.map b/web/b3desk/static/dsfr-1.7/component/component.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.min.css.map rename to web/b3desk/static/dsfr-1.7/component/component.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.module.js b/web/b3desk/static/dsfr-1.7/component/component.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.module.js rename to web/b3desk/static/dsfr-1.7/component/component.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/component.module.js.map b/web/b3desk/static/dsfr-1.7/component/component.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.module.js.map rename to web/b3desk/static/dsfr-1.7/component/component.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.module.min.js b/web/b3desk/static/dsfr-1.7/component/component.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.module.min.js rename to web/b3desk/static/dsfr-1.7/component/component.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/component.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/component.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/component.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.nomodule.js b/web/b3desk/static/dsfr-1.7/component/component.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/component.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/component.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/component.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/component.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/component.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/component.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/component.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/component.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/component.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/component.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/component.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/connect/README.md b/web/b3desk/static/dsfr-1.7/component/connect/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/README.md rename to web/b3desk/static/dsfr-1.7/component/connect/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.css b/web/b3desk/static/dsfr-1.7/component/connect/connect.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.css rename to web/b3desk/static/dsfr-1.7/component/connect/connect.css diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.css.map b/web/b3desk/static/dsfr-1.7/component/connect/connect.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.css.map rename to web/b3desk/static/dsfr-1.7/component/connect/connect.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.legacy.css b/web/b3desk/static/dsfr-1.7/component/connect/connect.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.legacy.css rename to web/b3desk/static/dsfr-1.7/component/connect/connect.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/connect/connect.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/connect/connect.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/connect/connect.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/connect/connect.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/connect/connect.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/connect/connect.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.main.css b/web/b3desk/static/dsfr-1.7/component/connect/connect.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.main.css rename to web/b3desk/static/dsfr-1.7/component/connect/connect.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.main.css.map b/web/b3desk/static/dsfr-1.7/component/connect/connect.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.main.css.map rename to web/b3desk/static/dsfr-1.7/component/connect/connect.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.main.min.css b/web/b3desk/static/dsfr-1.7/component/connect/connect.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.main.min.css rename to web/b3desk/static/dsfr-1.7/component/connect/connect.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/connect/connect.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/connect/connect.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.min.css b/web/b3desk/static/dsfr-1.7/component/connect/connect.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.min.css rename to web/b3desk/static/dsfr-1.7/component/connect/connect.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/connect/connect.min.css.map b/web/b3desk/static/dsfr-1.7/component/connect/connect.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/connect/connect.min.css.map rename to web/b3desk/static/dsfr-1.7/component/connect/connect.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/consent/README.md b/web/b3desk/static/dsfr-1.7/component/consent/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/README.md rename to web/b3desk/static/dsfr-1.7/component/consent/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.css b/web/b3desk/static/dsfr-1.7/component/consent/consent.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.css rename to web/b3desk/static/dsfr-1.7/component/consent/consent.css diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.css.map b/web/b3desk/static/dsfr-1.7/component/consent/consent.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.css.map rename to web/b3desk/static/dsfr-1.7/component/consent/consent.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.legacy.css b/web/b3desk/static/dsfr-1.7/component/consent/consent.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.legacy.css rename to web/b3desk/static/dsfr-1.7/component/consent/consent.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/consent/consent.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/consent/consent.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/consent/consent.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/consent/consent.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/consent/consent.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/consent/consent.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.main.css b/web/b3desk/static/dsfr-1.7/component/consent/consent.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.main.css rename to web/b3desk/static/dsfr-1.7/component/consent/consent.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.main.css.map b/web/b3desk/static/dsfr-1.7/component/consent/consent.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.main.css.map rename to web/b3desk/static/dsfr-1.7/component/consent/consent.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.main.min.css b/web/b3desk/static/dsfr-1.7/component/consent/consent.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.main.min.css rename to web/b3desk/static/dsfr-1.7/component/consent/consent.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/consent/consent.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/consent/consent.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.min.css b/web/b3desk/static/dsfr-1.7/component/consent/consent.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.min.css rename to web/b3desk/static/dsfr-1.7/component/consent/consent.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/consent/consent.min.css.map b/web/b3desk/static/dsfr-1.7/component/consent/consent.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/consent/consent.min.css.map rename to web/b3desk/static/dsfr-1.7/component/consent/consent.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/content/README.md b/web/b3desk/static/dsfr-1.7/component/content/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/README.md rename to web/b3desk/static/dsfr-1.7/component/content/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.css b/web/b3desk/static/dsfr-1.7/component/content/content.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.css rename to web/b3desk/static/dsfr-1.7/component/content/content.css diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.css.map b/web/b3desk/static/dsfr-1.7/component/content/content.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.css.map rename to web/b3desk/static/dsfr-1.7/component/content/content.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.legacy.css b/web/b3desk/static/dsfr-1.7/component/content/content.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.legacy.css rename to web/b3desk/static/dsfr-1.7/component/content/content.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/content/content.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/content/content.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/content/content.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/content/content.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/content/content.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/content/content.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.main.css b/web/b3desk/static/dsfr-1.7/component/content/content.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.main.css rename to web/b3desk/static/dsfr-1.7/component/content/content.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.main.css.map b/web/b3desk/static/dsfr-1.7/component/content/content.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.main.css.map rename to web/b3desk/static/dsfr-1.7/component/content/content.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.main.min.css b/web/b3desk/static/dsfr-1.7/component/content/content.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.main.min.css rename to web/b3desk/static/dsfr-1.7/component/content/content.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/content/content.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/content/content.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.min.css b/web/b3desk/static/dsfr-1.7/component/content/content.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.min.css rename to web/b3desk/static/dsfr-1.7/component/content/content.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/content/content.min.css.map b/web/b3desk/static/dsfr-1.7/component/content/content.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/content/content.min.css.map rename to web/b3desk/static/dsfr-1.7/component/content/content.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/display/README.md b/web/b3desk/static/dsfr-1.7/component/display/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/display/README.md rename to web/b3desk/static/dsfr-1.7/component/display/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/display/display.module.js b/web/b3desk/static/dsfr-1.7/component/display/display.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/display/display.module.js rename to web/b3desk/static/dsfr-1.7/component/display/display.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/display/display.module.js.map b/web/b3desk/static/dsfr-1.7/component/display/display.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/display/display.module.js.map rename to web/b3desk/static/dsfr-1.7/component/display/display.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/display/display.module.min.js b/web/b3desk/static/dsfr-1.7/component/display/display.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/display/display.module.min.js rename to web/b3desk/static/dsfr-1.7/component/display/display.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/display/display.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/display/display.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/display/display.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/display/display.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/display/display.nomodule.js b/web/b3desk/static/dsfr-1.7/component/display/display.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/display/display.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/display/display.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/display/display.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/display/display.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/display/display.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/display/display.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/display/display.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/display/display.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/display/display.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/display/display.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/display/display.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/display/display.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/display/display.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/display/display.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/download/README.md b/web/b3desk/static/dsfr-1.7/component/download/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/README.md rename to web/b3desk/static/dsfr-1.7/component/download/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.css b/web/b3desk/static/dsfr-1.7/component/download/download.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.css rename to web/b3desk/static/dsfr-1.7/component/download/download.css diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.css.map b/web/b3desk/static/dsfr-1.7/component/download/download.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.css.map rename to web/b3desk/static/dsfr-1.7/component/download/download.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.min.css b/web/b3desk/static/dsfr-1.7/component/download/download.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.min.css rename to web/b3desk/static/dsfr-1.7/component/download/download.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.min.css.map b/web/b3desk/static/dsfr-1.7/component/download/download.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.min.css.map rename to web/b3desk/static/dsfr-1.7/component/download/download.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.module.js b/web/b3desk/static/dsfr-1.7/component/download/download.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.module.js rename to web/b3desk/static/dsfr-1.7/component/download/download.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.module.js.map b/web/b3desk/static/dsfr-1.7/component/download/download.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.module.js.map rename to web/b3desk/static/dsfr-1.7/component/download/download.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.module.min.js b/web/b3desk/static/dsfr-1.7/component/download/download.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.module.min.js rename to web/b3desk/static/dsfr-1.7/component/download/download.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/download/download.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/download/download.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.nomodule.js b/web/b3desk/static/dsfr-1.7/component/download/download.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/download/download.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/download/download.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/download/download.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/download/download.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/download/download.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/download/download.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/download/download.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/download/download.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/download/download.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/follow/README.md b/web/b3desk/static/dsfr-1.7/component/follow/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/README.md rename to web/b3desk/static/dsfr-1.7/component/follow/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.css b/web/b3desk/static/dsfr-1.7/component/follow/follow.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.css rename to web/b3desk/static/dsfr-1.7/component/follow/follow.css diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.css.map b/web/b3desk/static/dsfr-1.7/component/follow/follow.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.css.map rename to web/b3desk/static/dsfr-1.7/component/follow/follow.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.legacy.css b/web/b3desk/static/dsfr-1.7/component/follow/follow.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.legacy.css rename to web/b3desk/static/dsfr-1.7/component/follow/follow.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/follow/follow.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/follow/follow.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/follow/follow.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/follow/follow.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/follow/follow.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/follow/follow.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.main.css b/web/b3desk/static/dsfr-1.7/component/follow/follow.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.main.css rename to web/b3desk/static/dsfr-1.7/component/follow/follow.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.main.css.map b/web/b3desk/static/dsfr-1.7/component/follow/follow.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.main.css.map rename to web/b3desk/static/dsfr-1.7/component/follow/follow.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.main.min.css b/web/b3desk/static/dsfr-1.7/component/follow/follow.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.main.min.css rename to web/b3desk/static/dsfr-1.7/component/follow/follow.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/follow/follow.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/follow/follow.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.min.css b/web/b3desk/static/dsfr-1.7/component/follow/follow.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.min.css rename to web/b3desk/static/dsfr-1.7/component/follow/follow.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/follow/follow.min.css.map b/web/b3desk/static/dsfr-1.7/component/follow/follow.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/follow/follow.min.css.map rename to web/b3desk/static/dsfr-1.7/component/follow/follow.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/footer/README.md b/web/b3desk/static/dsfr-1.7/component/footer/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/README.md rename to web/b3desk/static/dsfr-1.7/component/footer/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.css b/web/b3desk/static/dsfr-1.7/component/footer/footer.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.css rename to web/b3desk/static/dsfr-1.7/component/footer/footer.css diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.css.map b/web/b3desk/static/dsfr-1.7/component/footer/footer.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.css.map rename to web/b3desk/static/dsfr-1.7/component/footer/footer.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.legacy.css b/web/b3desk/static/dsfr-1.7/component/footer/footer.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.legacy.css rename to web/b3desk/static/dsfr-1.7/component/footer/footer.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/footer/footer.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/footer/footer.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/footer/footer.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/footer/footer.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/footer/footer.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/footer/footer.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.main.css b/web/b3desk/static/dsfr-1.7/component/footer/footer.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.main.css rename to web/b3desk/static/dsfr-1.7/component/footer/footer.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.main.css.map b/web/b3desk/static/dsfr-1.7/component/footer/footer.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.main.css.map rename to web/b3desk/static/dsfr-1.7/component/footer/footer.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.main.min.css b/web/b3desk/static/dsfr-1.7/component/footer/footer.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.main.min.css rename to web/b3desk/static/dsfr-1.7/component/footer/footer.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/footer/footer.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/footer/footer.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.min.css b/web/b3desk/static/dsfr-1.7/component/footer/footer.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.min.css rename to web/b3desk/static/dsfr-1.7/component/footer/footer.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/footer/footer.min.css.map b/web/b3desk/static/dsfr-1.7/component/footer/footer.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/footer/footer.min.css.map rename to web/b3desk/static/dsfr-1.7/component/footer/footer.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/form/README.md b/web/b3desk/static/dsfr-1.7/component/form/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/README.md rename to web/b3desk/static/dsfr-1.7/component/form/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.css b/web/b3desk/static/dsfr-1.7/component/form/form.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.css rename to web/b3desk/static/dsfr-1.7/component/form/form.css diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.css.map b/web/b3desk/static/dsfr-1.7/component/form/form.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.css.map rename to web/b3desk/static/dsfr-1.7/component/form/form.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.legacy.css b/web/b3desk/static/dsfr-1.7/component/form/form.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.legacy.css rename to web/b3desk/static/dsfr-1.7/component/form/form.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/form/form.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/form/form.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/form/form.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/form/form.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/form/form.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/form/form.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.main.css b/web/b3desk/static/dsfr-1.7/component/form/form.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.main.css rename to web/b3desk/static/dsfr-1.7/component/form/form.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.main.css.map b/web/b3desk/static/dsfr-1.7/component/form/form.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.main.css.map rename to web/b3desk/static/dsfr-1.7/component/form/form.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.main.min.css b/web/b3desk/static/dsfr-1.7/component/form/form.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.main.min.css rename to web/b3desk/static/dsfr-1.7/component/form/form.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/form/form.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/form/form.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.min.css b/web/b3desk/static/dsfr-1.7/component/form/form.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.min.css rename to web/b3desk/static/dsfr-1.7/component/form/form.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/form/form.min.css.map b/web/b3desk/static/dsfr-1.7/component/form/form.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/form/form.min.css.map rename to web/b3desk/static/dsfr-1.7/component/form/form.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/README.md b/web/b3desk/static/dsfr-1.7/component/header/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/README.md rename to web/b3desk/static/dsfr-1.7/component/header/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.css b/web/b3desk/static/dsfr-1.7/component/header/header.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.css rename to web/b3desk/static/dsfr-1.7/component/header/header.css diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.css.map b/web/b3desk/static/dsfr-1.7/component/header/header.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.css.map rename to web/b3desk/static/dsfr-1.7/component/header/header.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.legacy.css b/web/b3desk/static/dsfr-1.7/component/header/header.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.legacy.css rename to web/b3desk/static/dsfr-1.7/component/header/header.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/header/header.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/header/header.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/header/header.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/header/header.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/header/header.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/header/header.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.main.css b/web/b3desk/static/dsfr-1.7/component/header/header.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.main.css rename to web/b3desk/static/dsfr-1.7/component/header/header.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.main.css.map b/web/b3desk/static/dsfr-1.7/component/header/header.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.main.css.map rename to web/b3desk/static/dsfr-1.7/component/header/header.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.main.min.css b/web/b3desk/static/dsfr-1.7/component/header/header.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.main.min.css rename to web/b3desk/static/dsfr-1.7/component/header/header.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/header/header.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/header/header.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.min.css b/web/b3desk/static/dsfr-1.7/component/header/header.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.min.css rename to web/b3desk/static/dsfr-1.7/component/header/header.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.min.css.map b/web/b3desk/static/dsfr-1.7/component/header/header.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.min.css.map rename to web/b3desk/static/dsfr-1.7/component/header/header.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.module.js b/web/b3desk/static/dsfr-1.7/component/header/header.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.module.js rename to web/b3desk/static/dsfr-1.7/component/header/header.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.module.js.map b/web/b3desk/static/dsfr-1.7/component/header/header.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.module.js.map rename to web/b3desk/static/dsfr-1.7/component/header/header.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.module.min.js b/web/b3desk/static/dsfr-1.7/component/header/header.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.module.min.js rename to web/b3desk/static/dsfr-1.7/component/header/header.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/header/header.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/header/header.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.nomodule.js b/web/b3desk/static/dsfr-1.7/component/header/header.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/header/header.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/header/header.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/header/header.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/header/header.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/header/header.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/header/header.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/header/header.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/header/header.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/header/header.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/README.md b/web/b3desk/static/dsfr-1.7/component/highlight/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/README.md rename to web/b3desk/static/dsfr-1.7/component/highlight/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.css b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.css rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.css diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.css.map b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.css.map rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.legacy.css b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.legacy.css rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.main.css b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.main.css rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.main.css.map b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.main.css.map rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.main.min.css b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.main.min.css rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.min.css b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.min.css rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/highlight/highlight.min.css.map b/web/b3desk/static/dsfr-1.7/component/highlight/highlight.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/highlight/highlight.min.css.map rename to web/b3desk/static/dsfr-1.7/component/highlight/highlight.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/input/README.md b/web/b3desk/static/dsfr-1.7/component/input/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/README.md rename to web/b3desk/static/dsfr-1.7/component/input/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.css b/web/b3desk/static/dsfr-1.7/component/input/input.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.css rename to web/b3desk/static/dsfr-1.7/component/input/input.css diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.css.map b/web/b3desk/static/dsfr-1.7/component/input/input.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.css.map rename to web/b3desk/static/dsfr-1.7/component/input/input.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.legacy.css b/web/b3desk/static/dsfr-1.7/component/input/input.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.legacy.css rename to web/b3desk/static/dsfr-1.7/component/input/input.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/input/input.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/input/input.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/input/input.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/input/input.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/input/input.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/input/input.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.main.css b/web/b3desk/static/dsfr-1.7/component/input/input.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.main.css rename to web/b3desk/static/dsfr-1.7/component/input/input.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.main.css.map b/web/b3desk/static/dsfr-1.7/component/input/input.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.main.css.map rename to web/b3desk/static/dsfr-1.7/component/input/input.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.main.min.css b/web/b3desk/static/dsfr-1.7/component/input/input.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.main.min.css rename to web/b3desk/static/dsfr-1.7/component/input/input.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/input/input.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/input/input.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.min.css b/web/b3desk/static/dsfr-1.7/component/input/input.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.min.css rename to web/b3desk/static/dsfr-1.7/component/input/input.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/input/input.min.css.map b/web/b3desk/static/dsfr-1.7/component/input/input.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/input/input.min.css.map rename to web/b3desk/static/dsfr-1.7/component/input/input.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/link/README.md b/web/b3desk/static/dsfr-1.7/component/link/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/README.md rename to web/b3desk/static/dsfr-1.7/component/link/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.css b/web/b3desk/static/dsfr-1.7/component/link/link.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.css rename to web/b3desk/static/dsfr-1.7/component/link/link.css diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.css.map b/web/b3desk/static/dsfr-1.7/component/link/link.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.css.map rename to web/b3desk/static/dsfr-1.7/component/link/link.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.legacy.css b/web/b3desk/static/dsfr-1.7/component/link/link.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.legacy.css rename to web/b3desk/static/dsfr-1.7/component/link/link.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/link/link.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/link/link.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/link/link.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/link/link.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/link/link.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/link/link.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.main.css b/web/b3desk/static/dsfr-1.7/component/link/link.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.main.css rename to web/b3desk/static/dsfr-1.7/component/link/link.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.main.css.map b/web/b3desk/static/dsfr-1.7/component/link/link.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.main.css.map rename to web/b3desk/static/dsfr-1.7/component/link/link.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.main.min.css b/web/b3desk/static/dsfr-1.7/component/link/link.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.main.min.css rename to web/b3desk/static/dsfr-1.7/component/link/link.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/link/link.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/link/link.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.min.css b/web/b3desk/static/dsfr-1.7/component/link/link.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.min.css rename to web/b3desk/static/dsfr-1.7/component/link/link.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/link/link.min.css.map b/web/b3desk/static/dsfr-1.7/component/link/link.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/link/link.min.css.map rename to web/b3desk/static/dsfr-1.7/component/link/link.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/logo/README.md b/web/b3desk/static/dsfr-1.7/component/logo/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/README.md rename to web/b3desk/static/dsfr-1.7/component/logo/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.css b/web/b3desk/static/dsfr-1.7/component/logo/logo.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.css rename to web/b3desk/static/dsfr-1.7/component/logo/logo.css diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.css.map b/web/b3desk/static/dsfr-1.7/component/logo/logo.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.css.map rename to web/b3desk/static/dsfr-1.7/component/logo/logo.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.legacy.css b/web/b3desk/static/dsfr-1.7/component/logo/logo.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.legacy.css rename to web/b3desk/static/dsfr-1.7/component/logo/logo.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/logo/logo.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/logo/logo.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/logo/logo.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/logo/logo.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/logo/logo.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/logo/logo.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.main.css b/web/b3desk/static/dsfr-1.7/component/logo/logo.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.main.css rename to web/b3desk/static/dsfr-1.7/component/logo/logo.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.main.css.map b/web/b3desk/static/dsfr-1.7/component/logo/logo.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.main.css.map rename to web/b3desk/static/dsfr-1.7/component/logo/logo.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.main.min.css b/web/b3desk/static/dsfr-1.7/component/logo/logo.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.main.min.css rename to web/b3desk/static/dsfr-1.7/component/logo/logo.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/logo/logo.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/logo/logo.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.min.css b/web/b3desk/static/dsfr-1.7/component/logo/logo.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.min.css rename to web/b3desk/static/dsfr-1.7/component/logo/logo.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/logo/logo.min.css.map b/web/b3desk/static/dsfr-1.7/component/logo/logo.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/logo/logo.min.css.map rename to web/b3desk/static/dsfr-1.7/component/logo/logo.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/README.md b/web/b3desk/static/dsfr-1.7/component/modal/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/README.md rename to web/b3desk/static/dsfr-1.7/component/modal/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.css b/web/b3desk/static/dsfr-1.7/component/modal/modal.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.css rename to web/b3desk/static/dsfr-1.7/component/modal/modal.css diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.css.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.css.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.legacy.css b/web/b3desk/static/dsfr-1.7/component/modal/modal.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.legacy.css rename to web/b3desk/static/dsfr-1.7/component/modal/modal.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/modal/modal.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/modal/modal.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.main.css b/web/b3desk/static/dsfr-1.7/component/modal/modal.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.main.css rename to web/b3desk/static/dsfr-1.7/component/modal/modal.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.main.css.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.main.css.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.main.min.css b/web/b3desk/static/dsfr-1.7/component/modal/modal.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.main.min.css rename to web/b3desk/static/dsfr-1.7/component/modal/modal.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.min.css b/web/b3desk/static/dsfr-1.7/component/modal/modal.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.min.css rename to web/b3desk/static/dsfr-1.7/component/modal/modal.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.min.css.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.min.css.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.module.js b/web/b3desk/static/dsfr-1.7/component/modal/modal.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.module.js rename to web/b3desk/static/dsfr-1.7/component/modal/modal.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.module.js.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.module.js.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.module.min.js b/web/b3desk/static/dsfr-1.7/component/modal/modal.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.module.min.js rename to web/b3desk/static/dsfr-1.7/component/modal/modal.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.nomodule.js b/web/b3desk/static/dsfr-1.7/component/modal/modal.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/modal/modal.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/modal/modal.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/modal/modal.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/modal/modal.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/modal/modal.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/modal/modal.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/modal/modal.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/README.md b/web/b3desk/static/dsfr-1.7/component/navigation/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/README.md rename to web/b3desk/static/dsfr-1.7/component/navigation/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.css b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.css rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.css diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.css.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.css.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.legacy.css b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.legacy.css rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.main.css b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.main.css rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.main.css.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.main.css.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.main.min.css b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.main.min.css rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.min.css b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.min.css rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.min.css.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.min.css.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.module.js b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.module.js rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.module.js.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.module.js.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.module.min.js b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.module.min.js rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.nomodule.js b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/navigation/navigation.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/navigation/navigation.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/navigation/navigation.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/navigation/navigation.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/notice/README.md b/web/b3desk/static/dsfr-1.7/component/notice/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/README.md rename to web/b3desk/static/dsfr-1.7/component/notice/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.css b/web/b3desk/static/dsfr-1.7/component/notice/notice.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.css rename to web/b3desk/static/dsfr-1.7/component/notice/notice.css diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.css.map b/web/b3desk/static/dsfr-1.7/component/notice/notice.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.css.map rename to web/b3desk/static/dsfr-1.7/component/notice/notice.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.legacy.css b/web/b3desk/static/dsfr-1.7/component/notice/notice.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.legacy.css rename to web/b3desk/static/dsfr-1.7/component/notice/notice.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/notice/notice.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/notice/notice.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/notice/notice.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/notice/notice.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/notice/notice.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/notice/notice.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.main.css b/web/b3desk/static/dsfr-1.7/component/notice/notice.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.main.css rename to web/b3desk/static/dsfr-1.7/component/notice/notice.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.main.css.map b/web/b3desk/static/dsfr-1.7/component/notice/notice.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.main.css.map rename to web/b3desk/static/dsfr-1.7/component/notice/notice.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.main.min.css b/web/b3desk/static/dsfr-1.7/component/notice/notice.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.main.min.css rename to web/b3desk/static/dsfr-1.7/component/notice/notice.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/notice/notice.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/notice/notice.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.min.css b/web/b3desk/static/dsfr-1.7/component/notice/notice.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.min.css rename to web/b3desk/static/dsfr-1.7/component/notice/notice.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/notice/notice.min.css.map b/web/b3desk/static/dsfr-1.7/component/notice/notice.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/notice/notice.min.css.map rename to web/b3desk/static/dsfr-1.7/component/notice/notice.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/README.md b/web/b3desk/static/dsfr-1.7/component/pagination/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/README.md rename to web/b3desk/static/dsfr-1.7/component/pagination/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.css b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.css rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.css diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.css.map b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.css.map rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.legacy.css b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.legacy.css rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.main.css b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.main.css rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.main.css.map b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.main.css.map rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.main.min.css b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.main.min.css rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.min.css b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.min.css rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/pagination/pagination.min.css.map b/web/b3desk/static/dsfr-1.7/component/pagination/pagination.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/pagination/pagination.min.css.map rename to web/b3desk/static/dsfr-1.7/component/pagination/pagination.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/quote/README.md b/web/b3desk/static/dsfr-1.7/component/quote/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/README.md rename to web/b3desk/static/dsfr-1.7/component/quote/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.css b/web/b3desk/static/dsfr-1.7/component/quote/quote.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.css rename to web/b3desk/static/dsfr-1.7/component/quote/quote.css diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.css.map b/web/b3desk/static/dsfr-1.7/component/quote/quote.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.css.map rename to web/b3desk/static/dsfr-1.7/component/quote/quote.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.legacy.css b/web/b3desk/static/dsfr-1.7/component/quote/quote.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.legacy.css rename to web/b3desk/static/dsfr-1.7/component/quote/quote.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/quote/quote.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/quote/quote.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/quote/quote.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/quote/quote.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/quote/quote.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/quote/quote.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.main.css b/web/b3desk/static/dsfr-1.7/component/quote/quote.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.main.css rename to web/b3desk/static/dsfr-1.7/component/quote/quote.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.main.css.map b/web/b3desk/static/dsfr-1.7/component/quote/quote.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.main.css.map rename to web/b3desk/static/dsfr-1.7/component/quote/quote.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.main.min.css b/web/b3desk/static/dsfr-1.7/component/quote/quote.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.main.min.css rename to web/b3desk/static/dsfr-1.7/component/quote/quote.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/quote/quote.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/quote/quote.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.min.css b/web/b3desk/static/dsfr-1.7/component/quote/quote.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.min.css rename to web/b3desk/static/dsfr-1.7/component/quote/quote.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/quote/quote.min.css.map b/web/b3desk/static/dsfr-1.7/component/quote/quote.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/quote/quote.min.css.map rename to web/b3desk/static/dsfr-1.7/component/quote/quote.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/radio/README.md b/web/b3desk/static/dsfr-1.7/component/radio/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/README.md rename to web/b3desk/static/dsfr-1.7/component/radio/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.css b/web/b3desk/static/dsfr-1.7/component/radio/radio.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.css rename to web/b3desk/static/dsfr-1.7/component/radio/radio.css diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.css.map b/web/b3desk/static/dsfr-1.7/component/radio/radio.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.css.map rename to web/b3desk/static/dsfr-1.7/component/radio/radio.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.legacy.css b/web/b3desk/static/dsfr-1.7/component/radio/radio.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.legacy.css rename to web/b3desk/static/dsfr-1.7/component/radio/radio.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/radio/radio.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/radio/radio.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/radio/radio.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/radio/radio.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/radio/radio.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/radio/radio.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.main.css b/web/b3desk/static/dsfr-1.7/component/radio/radio.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.main.css rename to web/b3desk/static/dsfr-1.7/component/radio/radio.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.main.css.map b/web/b3desk/static/dsfr-1.7/component/radio/radio.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.main.css.map rename to web/b3desk/static/dsfr-1.7/component/radio/radio.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.main.min.css b/web/b3desk/static/dsfr-1.7/component/radio/radio.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.main.min.css rename to web/b3desk/static/dsfr-1.7/component/radio/radio.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/radio/radio.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/radio/radio.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.min.css b/web/b3desk/static/dsfr-1.7/component/radio/radio.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.min.css rename to web/b3desk/static/dsfr-1.7/component/radio/radio.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/radio/radio.min.css.map b/web/b3desk/static/dsfr-1.7/component/radio/radio.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/radio/radio.min.css.map rename to web/b3desk/static/dsfr-1.7/component/radio/radio.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/search/README.md b/web/b3desk/static/dsfr-1.7/component/search/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/README.md rename to web/b3desk/static/dsfr-1.7/component/search/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.css b/web/b3desk/static/dsfr-1.7/component/search/search.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.css rename to web/b3desk/static/dsfr-1.7/component/search/search.css diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.css.map b/web/b3desk/static/dsfr-1.7/component/search/search.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.css.map rename to web/b3desk/static/dsfr-1.7/component/search/search.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.legacy.css b/web/b3desk/static/dsfr-1.7/component/search/search.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.legacy.css rename to web/b3desk/static/dsfr-1.7/component/search/search.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/search/search.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/search/search.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/search/search.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/search/search.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/search/search.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/search/search.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.main.css b/web/b3desk/static/dsfr-1.7/component/search/search.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.main.css rename to web/b3desk/static/dsfr-1.7/component/search/search.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.main.css.map b/web/b3desk/static/dsfr-1.7/component/search/search.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.main.css.map rename to web/b3desk/static/dsfr-1.7/component/search/search.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.main.min.css b/web/b3desk/static/dsfr-1.7/component/search/search.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.main.min.css rename to web/b3desk/static/dsfr-1.7/component/search/search.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/search/search.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/search/search.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.min.css b/web/b3desk/static/dsfr-1.7/component/search/search.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.min.css rename to web/b3desk/static/dsfr-1.7/component/search/search.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/search/search.min.css.map b/web/b3desk/static/dsfr-1.7/component/search/search.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/search/search.min.css.map rename to web/b3desk/static/dsfr-1.7/component/search/search.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/select/README.md b/web/b3desk/static/dsfr-1.7/component/select/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/README.md rename to web/b3desk/static/dsfr-1.7/component/select/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.css b/web/b3desk/static/dsfr-1.7/component/select/select.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.css rename to web/b3desk/static/dsfr-1.7/component/select/select.css diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.css.map b/web/b3desk/static/dsfr-1.7/component/select/select.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.css.map rename to web/b3desk/static/dsfr-1.7/component/select/select.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.legacy.css b/web/b3desk/static/dsfr-1.7/component/select/select.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.legacy.css rename to web/b3desk/static/dsfr-1.7/component/select/select.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/select/select.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/select/select.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/select/select.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/select/select.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/select/select.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/select/select.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.main.css b/web/b3desk/static/dsfr-1.7/component/select/select.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.main.css rename to web/b3desk/static/dsfr-1.7/component/select/select.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.main.css.map b/web/b3desk/static/dsfr-1.7/component/select/select.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.main.css.map rename to web/b3desk/static/dsfr-1.7/component/select/select.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.main.min.css b/web/b3desk/static/dsfr-1.7/component/select/select.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.main.min.css rename to web/b3desk/static/dsfr-1.7/component/select/select.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/select/select.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/select/select.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.min.css b/web/b3desk/static/dsfr-1.7/component/select/select.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.min.css rename to web/b3desk/static/dsfr-1.7/component/select/select.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/select/select.min.css.map b/web/b3desk/static/dsfr-1.7/component/select/select.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/select/select.min.css.map rename to web/b3desk/static/dsfr-1.7/component/select/select.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/share/README.md b/web/b3desk/static/dsfr-1.7/component/share/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/README.md rename to web/b3desk/static/dsfr-1.7/component/share/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.css b/web/b3desk/static/dsfr-1.7/component/share/share.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.css rename to web/b3desk/static/dsfr-1.7/component/share/share.css diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.css.map b/web/b3desk/static/dsfr-1.7/component/share/share.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.css.map rename to web/b3desk/static/dsfr-1.7/component/share/share.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.legacy.css b/web/b3desk/static/dsfr-1.7/component/share/share.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.legacy.css rename to web/b3desk/static/dsfr-1.7/component/share/share.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/share/share.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/share/share.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/share/share.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/share/share.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/share/share.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/share/share.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.main.css b/web/b3desk/static/dsfr-1.7/component/share/share.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.main.css rename to web/b3desk/static/dsfr-1.7/component/share/share.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.main.css.map b/web/b3desk/static/dsfr-1.7/component/share/share.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.main.css.map rename to web/b3desk/static/dsfr-1.7/component/share/share.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.main.min.css b/web/b3desk/static/dsfr-1.7/component/share/share.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.main.min.css rename to web/b3desk/static/dsfr-1.7/component/share/share.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/share/share.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/share/share.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.min.css b/web/b3desk/static/dsfr-1.7/component/share/share.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.min.css rename to web/b3desk/static/dsfr-1.7/component/share/share.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/share/share.min.css.map b/web/b3desk/static/dsfr-1.7/component/share/share.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/share/share.min.css.map rename to web/b3desk/static/dsfr-1.7/component/share/share.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/README.md b/web/b3desk/static/dsfr-1.7/component/sidemenu/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/README.md rename to web/b3desk/static/dsfr-1.7/component/sidemenu/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.css b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.css rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.css diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.css.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.css.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.css b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.css rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.main.css b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.main.css rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.main.css.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.main.css.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.main.min.css b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.main.min.css rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.min.css b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.min.css rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.min.css.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.min.css.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.module.js b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.module.js rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.module.js.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.module.js.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.module.min.js b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.module.min.js rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.js b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/sidemenu/sidemenu.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/README.md b/web/b3desk/static/dsfr-1.7/component/skiplink/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/README.md rename to web/b3desk/static/dsfr-1.7/component/skiplink/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.css b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.css rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.css diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.css.map b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.css.map rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.legacy.css b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.legacy.css rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.main.css b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.main.css rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.main.css.map b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.main.css.map rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.main.min.css b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.main.min.css rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.min.css b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.min.css rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.min.css.map b/web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/skiplink/skiplink.min.css.map rename to web/b3desk/static/dsfr-1.7/component/skiplink/skiplink.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/README.md b/web/b3desk/static/dsfr-1.7/component/stepper/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/README.md rename to web/b3desk/static/dsfr-1.7/component/stepper/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.css b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.css rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.css diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.css.map b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.css.map rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.legacy.css b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.legacy.css rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.main.css b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.main.css rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.main.css.map b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.main.css.map rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.main.min.css b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.main.min.css rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.min.css b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.min.css rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/stepper/stepper.min.css.map b/web/b3desk/static/dsfr-1.7/component/stepper/stepper.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/stepper/stepper.min.css.map rename to web/b3desk/static/dsfr-1.7/component/stepper/stepper.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/summary/README.md b/web/b3desk/static/dsfr-1.7/component/summary/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/README.md rename to web/b3desk/static/dsfr-1.7/component/summary/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.css b/web/b3desk/static/dsfr-1.7/component/summary/summary.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.css rename to web/b3desk/static/dsfr-1.7/component/summary/summary.css diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.css.map b/web/b3desk/static/dsfr-1.7/component/summary/summary.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.css.map rename to web/b3desk/static/dsfr-1.7/component/summary/summary.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.legacy.css b/web/b3desk/static/dsfr-1.7/component/summary/summary.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.legacy.css rename to web/b3desk/static/dsfr-1.7/component/summary/summary.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/summary/summary.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/summary/summary.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/summary/summary.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/summary/summary.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/summary/summary.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/summary/summary.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.main.css b/web/b3desk/static/dsfr-1.7/component/summary/summary.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.main.css rename to web/b3desk/static/dsfr-1.7/component/summary/summary.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.main.css.map b/web/b3desk/static/dsfr-1.7/component/summary/summary.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.main.css.map rename to web/b3desk/static/dsfr-1.7/component/summary/summary.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.main.min.css b/web/b3desk/static/dsfr-1.7/component/summary/summary.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.main.min.css rename to web/b3desk/static/dsfr-1.7/component/summary/summary.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/summary/summary.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/summary/summary.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.min.css b/web/b3desk/static/dsfr-1.7/component/summary/summary.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.min.css rename to web/b3desk/static/dsfr-1.7/component/summary/summary.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/summary/summary.min.css.map b/web/b3desk/static/dsfr-1.7/component/summary/summary.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/summary/summary.min.css.map rename to web/b3desk/static/dsfr-1.7/component/summary/summary.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/README.md b/web/b3desk/static/dsfr-1.7/component/tab/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/README.md rename to web/b3desk/static/dsfr-1.7/component/tab/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.css b/web/b3desk/static/dsfr-1.7/component/tab/tab.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.css rename to web/b3desk/static/dsfr-1.7/component/tab/tab.css diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.css.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.css.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.legacy.css b/web/b3desk/static/dsfr-1.7/component/tab/tab.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.legacy.css rename to web/b3desk/static/dsfr-1.7/component/tab/tab.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/tab/tab.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/tab/tab.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.main.css b/web/b3desk/static/dsfr-1.7/component/tab/tab.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.main.css rename to web/b3desk/static/dsfr-1.7/component/tab/tab.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.main.css.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.main.css.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.main.min.css b/web/b3desk/static/dsfr-1.7/component/tab/tab.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.main.min.css rename to web/b3desk/static/dsfr-1.7/component/tab/tab.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.min.css b/web/b3desk/static/dsfr-1.7/component/tab/tab.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.min.css rename to web/b3desk/static/dsfr-1.7/component/tab/tab.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.min.css.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.min.css.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.module.js b/web/b3desk/static/dsfr-1.7/component/tab/tab.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.module.js rename to web/b3desk/static/dsfr-1.7/component/tab/tab.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.module.js.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.module.js.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.module.min.js b/web/b3desk/static/dsfr-1.7/component/tab/tab.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.module.min.js rename to web/b3desk/static/dsfr-1.7/component/tab/tab.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.nomodule.js b/web/b3desk/static/dsfr-1.7/component/tab/tab.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/tab/tab.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/tab/tab.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/tab/tab.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/tab/tab.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/tab/tab.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tab/tab.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/tab/tab.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/README.md b/web/b3desk/static/dsfr-1.7/component/table/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/README.md rename to web/b3desk/static/dsfr-1.7/component/table/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.css b/web/b3desk/static/dsfr-1.7/component/table/table.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.css rename to web/b3desk/static/dsfr-1.7/component/table/table.css diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.css.map b/web/b3desk/static/dsfr-1.7/component/table/table.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.css.map rename to web/b3desk/static/dsfr-1.7/component/table/table.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.legacy.css b/web/b3desk/static/dsfr-1.7/component/table/table.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.legacy.css rename to web/b3desk/static/dsfr-1.7/component/table/table.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/table/table.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/table/table.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/table/table.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/table/table.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/table/table.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/table/table.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.main.css b/web/b3desk/static/dsfr-1.7/component/table/table.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.main.css rename to web/b3desk/static/dsfr-1.7/component/table/table.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.main.css.map b/web/b3desk/static/dsfr-1.7/component/table/table.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.main.css.map rename to web/b3desk/static/dsfr-1.7/component/table/table.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.main.min.css b/web/b3desk/static/dsfr-1.7/component/table/table.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.main.min.css rename to web/b3desk/static/dsfr-1.7/component/table/table.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/table/table.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/table/table.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.min.css b/web/b3desk/static/dsfr-1.7/component/table/table.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.min.css rename to web/b3desk/static/dsfr-1.7/component/table/table.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.min.css.map b/web/b3desk/static/dsfr-1.7/component/table/table.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.min.css.map rename to web/b3desk/static/dsfr-1.7/component/table/table.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.module.js b/web/b3desk/static/dsfr-1.7/component/table/table.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.module.js rename to web/b3desk/static/dsfr-1.7/component/table/table.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.module.js.map b/web/b3desk/static/dsfr-1.7/component/table/table.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.module.js.map rename to web/b3desk/static/dsfr-1.7/component/table/table.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.module.min.js b/web/b3desk/static/dsfr-1.7/component/table/table.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.module.min.js rename to web/b3desk/static/dsfr-1.7/component/table/table.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/table/table.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/table/table.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.nomodule.js b/web/b3desk/static/dsfr-1.7/component/table/table.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/table/table.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/table/table.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/table/table.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/table/table.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/table/table.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/table/table.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/table/table.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/table/table.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/table/table.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/README.md b/web/b3desk/static/dsfr-1.7/component/tag/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/README.md rename to web/b3desk/static/dsfr-1.7/component/tag/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.css b/web/b3desk/static/dsfr-1.7/component/tag/tag.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.css rename to web/b3desk/static/dsfr-1.7/component/tag/tag.css diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.css.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.css.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.legacy.css b/web/b3desk/static/dsfr-1.7/component/tag/tag.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.legacy.css rename to web/b3desk/static/dsfr-1.7/component/tag/tag.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/tag/tag.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/tag/tag.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.main.css b/web/b3desk/static/dsfr-1.7/component/tag/tag.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.main.css rename to web/b3desk/static/dsfr-1.7/component/tag/tag.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.main.css.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.main.css.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.main.min.css b/web/b3desk/static/dsfr-1.7/component/tag/tag.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.main.min.css rename to web/b3desk/static/dsfr-1.7/component/tag/tag.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.min.css b/web/b3desk/static/dsfr-1.7/component/tag/tag.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.min.css rename to web/b3desk/static/dsfr-1.7/component/tag/tag.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.min.css.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.min.css.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.module.js b/web/b3desk/static/dsfr-1.7/component/tag/tag.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.module.js rename to web/b3desk/static/dsfr-1.7/component/tag/tag.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.module.js.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.module.js.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.module.min.js b/web/b3desk/static/dsfr-1.7/component/tag/tag.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.module.min.js rename to web/b3desk/static/dsfr-1.7/component/tag/tag.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.nomodule.js b/web/b3desk/static/dsfr-1.7/component/tag/tag.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/tag/tag.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/tag/tag.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/tag/tag.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/tag/tag.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/tag/tag.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tag/tag.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/tag/tag.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/tile/README.md b/web/b3desk/static/dsfr-1.7/component/tile/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/README.md rename to web/b3desk/static/dsfr-1.7/component/tile/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.css b/web/b3desk/static/dsfr-1.7/component/tile/tile.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.css rename to web/b3desk/static/dsfr-1.7/component/tile/tile.css diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.css.map b/web/b3desk/static/dsfr-1.7/component/tile/tile.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.css.map rename to web/b3desk/static/dsfr-1.7/component/tile/tile.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.legacy.css b/web/b3desk/static/dsfr-1.7/component/tile/tile.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.legacy.css rename to web/b3desk/static/dsfr-1.7/component/tile/tile.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/tile/tile.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/tile/tile.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/tile/tile.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/tile/tile.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/tile/tile.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/tile/tile.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.main.css b/web/b3desk/static/dsfr-1.7/component/tile/tile.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.main.css rename to web/b3desk/static/dsfr-1.7/component/tile/tile.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.main.css.map b/web/b3desk/static/dsfr-1.7/component/tile/tile.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.main.css.map rename to web/b3desk/static/dsfr-1.7/component/tile/tile.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.main.min.css b/web/b3desk/static/dsfr-1.7/component/tile/tile.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.main.min.css rename to web/b3desk/static/dsfr-1.7/component/tile/tile.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/tile/tile.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/tile/tile.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.min.css b/web/b3desk/static/dsfr-1.7/component/tile/tile.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.min.css rename to web/b3desk/static/dsfr-1.7/component/tile/tile.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/tile/tile.min.css.map b/web/b3desk/static/dsfr-1.7/component/tile/tile.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/tile/tile.min.css.map rename to web/b3desk/static/dsfr-1.7/component/tile/tile.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/README.md b/web/b3desk/static/dsfr-1.7/component/toggle/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/README.md rename to web/b3desk/static/dsfr-1.7/component/toggle/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.css b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.css rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.css diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.css.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.css.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.legacy.css b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.legacy.css rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.main.css b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.main.css rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.main.css.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.main.css.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.main.min.css b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.main.min.css rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.min.css b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.min.css rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.min.css.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.min.css.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.module.js b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.module.js rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.module.js diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.module.js.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.module.js.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.module.min.js b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.module.min.js rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.module.min.js.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.module.min.js.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.nomodule.js b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.nomodule.js rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.nomodule.js.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.nomodule.min.js b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/component/toggle/toggle.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/component/toggle/toggle.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/toggle/toggle.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/component/toggle/toggle.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/component/translate/README.md b/web/b3desk/static/dsfr-1.7/component/translate/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/README.md rename to web/b3desk/static/dsfr-1.7/component/translate/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.css b/web/b3desk/static/dsfr-1.7/component/translate/translate.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.css rename to web/b3desk/static/dsfr-1.7/component/translate/translate.css diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.css.map b/web/b3desk/static/dsfr-1.7/component/translate/translate.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.css.map rename to web/b3desk/static/dsfr-1.7/component/translate/translate.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.legacy.css b/web/b3desk/static/dsfr-1.7/component/translate/translate.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.legacy.css rename to web/b3desk/static/dsfr-1.7/component/translate/translate.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.legacy.css.map b/web/b3desk/static/dsfr-1.7/component/translate/translate.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.legacy.css.map rename to web/b3desk/static/dsfr-1.7/component/translate/translate.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.legacy.min.css b/web/b3desk/static/dsfr-1.7/component/translate/translate.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.legacy.min.css rename to web/b3desk/static/dsfr-1.7/component/translate/translate.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/component/translate/translate.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/component/translate/translate.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.main.css b/web/b3desk/static/dsfr-1.7/component/translate/translate.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.main.css rename to web/b3desk/static/dsfr-1.7/component/translate/translate.main.css diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.main.css.map b/web/b3desk/static/dsfr-1.7/component/translate/translate.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.main.css.map rename to web/b3desk/static/dsfr-1.7/component/translate/translate.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.main.min.css b/web/b3desk/static/dsfr-1.7/component/translate/translate.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.main.min.css rename to web/b3desk/static/dsfr-1.7/component/translate/translate.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.main.min.css.map b/web/b3desk/static/dsfr-1.7/component/translate/translate.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.main.min.css.map rename to web/b3desk/static/dsfr-1.7/component/translate/translate.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.min.css b/web/b3desk/static/dsfr-1.7/component/translate/translate.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.min.css rename to web/b3desk/static/dsfr-1.7/component/translate/translate.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/translate/translate.min.css.map b/web/b3desk/static/dsfr-1.7/component/translate/translate.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/translate/translate.min.css.map rename to web/b3desk/static/dsfr-1.7/component/translate/translate.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/upload/README.md b/web/b3desk/static/dsfr-1.7/component/upload/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/upload/README.md rename to web/b3desk/static/dsfr-1.7/component/upload/README.md diff --git a/web/flaskr/static/dsfr-1.7/component/upload/upload.css b/web/b3desk/static/dsfr-1.7/component/upload/upload.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/upload/upload.css rename to web/b3desk/static/dsfr-1.7/component/upload/upload.css diff --git a/web/flaskr/static/dsfr-1.7/component/upload/upload.css.map b/web/b3desk/static/dsfr-1.7/component/upload/upload.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/upload/upload.css.map rename to web/b3desk/static/dsfr-1.7/component/upload/upload.css.map diff --git a/web/flaskr/static/dsfr-1.7/component/upload/upload.min.css b/web/b3desk/static/dsfr-1.7/component/upload/upload.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/upload/upload.min.css rename to web/b3desk/static/dsfr-1.7/component/upload/upload.min.css diff --git a/web/flaskr/static/dsfr-1.7/component/upload/upload.min.css.map b/web/b3desk/static/dsfr-1.7/component/upload/upload.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/component/upload/upload.min.css.map rename to web/b3desk/static/dsfr-1.7/component/upload/upload.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/core/README.md b/web/b3desk/static/dsfr-1.7/core/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/README.md rename to web/b3desk/static/dsfr-1.7/core/README.md diff --git a/web/flaskr/static/dsfr-1.7/core/core.css b/web/b3desk/static/dsfr-1.7/core/core.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.css rename to web/b3desk/static/dsfr-1.7/core/core.css diff --git a/web/flaskr/static/dsfr-1.7/core/core.css.map b/web/b3desk/static/dsfr-1.7/core/core.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.css.map rename to web/b3desk/static/dsfr-1.7/core/core.css.map diff --git a/web/flaskr/static/dsfr-1.7/core/core.legacy.css b/web/b3desk/static/dsfr-1.7/core/core.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.legacy.css rename to web/b3desk/static/dsfr-1.7/core/core.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/core/core.legacy.css.map b/web/b3desk/static/dsfr-1.7/core/core.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.legacy.css.map rename to web/b3desk/static/dsfr-1.7/core/core.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/core/core.legacy.min.css b/web/b3desk/static/dsfr-1.7/core/core.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.legacy.min.css rename to web/b3desk/static/dsfr-1.7/core/core.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/core/core.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/core/core.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/core/core.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/core/core.main.css b/web/b3desk/static/dsfr-1.7/core/core.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.main.css rename to web/b3desk/static/dsfr-1.7/core/core.main.css diff --git a/web/flaskr/static/dsfr-1.7/core/core.main.css.map b/web/b3desk/static/dsfr-1.7/core/core.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.main.css.map rename to web/b3desk/static/dsfr-1.7/core/core.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/core/core.main.min.css b/web/b3desk/static/dsfr-1.7/core/core.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.main.min.css rename to web/b3desk/static/dsfr-1.7/core/core.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/core/core.main.min.css.map b/web/b3desk/static/dsfr-1.7/core/core.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.main.min.css.map rename to web/b3desk/static/dsfr-1.7/core/core.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/core/core.min.css b/web/b3desk/static/dsfr-1.7/core/core.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.min.css rename to web/b3desk/static/dsfr-1.7/core/core.min.css diff --git a/web/flaskr/static/dsfr-1.7/core/core.min.css.map b/web/b3desk/static/dsfr-1.7/core/core.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.min.css.map rename to web/b3desk/static/dsfr-1.7/core/core.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/core/core.module.js b/web/b3desk/static/dsfr-1.7/core/core.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.module.js rename to web/b3desk/static/dsfr-1.7/core/core.module.js diff --git a/web/flaskr/static/dsfr-1.7/core/core.module.js.map b/web/b3desk/static/dsfr-1.7/core/core.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.module.js.map rename to web/b3desk/static/dsfr-1.7/core/core.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/core/core.module.min.js b/web/b3desk/static/dsfr-1.7/core/core.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.module.min.js rename to web/b3desk/static/dsfr-1.7/core/core.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/core/core.module.min.js.map b/web/b3desk/static/dsfr-1.7/core/core.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.module.min.js.map rename to web/b3desk/static/dsfr-1.7/core/core.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/core/core.nomodule.js b/web/b3desk/static/dsfr-1.7/core/core.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.nomodule.js rename to web/b3desk/static/dsfr-1.7/core/core.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/core/core.nomodule.js.map b/web/b3desk/static/dsfr-1.7/core/core.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/core/core.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/core/core.nomodule.min.js b/web/b3desk/static/dsfr-1.7/core/core.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/core/core.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/core/core.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/core/core.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/core/core.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/core/core.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.css b/web/b3desk/static/dsfr-1.7/dsfr.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.css rename to web/b3desk/static/dsfr-1.7/dsfr.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr.css.map b/web/b3desk/static/dsfr-1.7/dsfr.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.css.map rename to web/b3desk/static/dsfr-1.7/dsfr.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.legacy.css b/web/b3desk/static/dsfr-1.7/dsfr.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.legacy.css rename to web/b3desk/static/dsfr-1.7/dsfr.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr.legacy.css.map b/web/b3desk/static/dsfr-1.7/dsfr.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.legacy.css.map rename to web/b3desk/static/dsfr-1.7/dsfr.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.legacy.min.css b/web/b3desk/static/dsfr-1.7/dsfr.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.legacy.min.css rename to web/b3desk/static/dsfr-1.7/dsfr.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/dsfr.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/dsfr.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.main.css b/web/b3desk/static/dsfr-1.7/dsfr.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.main.css rename to web/b3desk/static/dsfr-1.7/dsfr.main.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr.main.css.map b/web/b3desk/static/dsfr-1.7/dsfr.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.main.css.map rename to web/b3desk/static/dsfr-1.7/dsfr.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.main.min.css b/web/b3desk/static/dsfr-1.7/dsfr.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.main.min.css rename to web/b3desk/static/dsfr-1.7/dsfr.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr.main.min.css.map b/web/b3desk/static/dsfr-1.7/dsfr.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.main.min.css.map rename to web/b3desk/static/dsfr-1.7/dsfr.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.min.css b/web/b3desk/static/dsfr-1.7/dsfr.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.min.css rename to web/b3desk/static/dsfr-1.7/dsfr.min.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr.min.css.map b/web/b3desk/static/dsfr-1.7/dsfr.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.min.css.map rename to web/b3desk/static/dsfr-1.7/dsfr.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.module.js b/web/b3desk/static/dsfr-1.7/dsfr.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.module.js rename to web/b3desk/static/dsfr-1.7/dsfr.module.js diff --git a/web/flaskr/static/dsfr-1.7/dsfr.module.js.map b/web/b3desk/static/dsfr-1.7/dsfr.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.module.js.map rename to web/b3desk/static/dsfr-1.7/dsfr.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.module.min.js b/web/b3desk/static/dsfr-1.7/dsfr.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.module.min.js rename to web/b3desk/static/dsfr-1.7/dsfr.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/dsfr.module.min.js.map b/web/b3desk/static/dsfr-1.7/dsfr.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.module.min.js.map rename to web/b3desk/static/dsfr-1.7/dsfr.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.nomodule.js b/web/b3desk/static/dsfr-1.7/dsfr.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.nomodule.js rename to web/b3desk/static/dsfr-1.7/dsfr.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/dsfr.nomodule.js.map b/web/b3desk/static/dsfr-1.7/dsfr.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/dsfr.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr.nomodule.min.js b/web/b3desk/static/dsfr-1.7/dsfr.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/dsfr.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/dsfr.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/dsfr.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/dsfr.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/README.md b/web/b3desk/static/dsfr-1.7/dsfr/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/README.md rename to web/b3desk/static/dsfr-1.7/dsfr/README.md diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.css b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.css rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.css.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.css.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.legacy.css b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.legacy.css rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.legacy.css.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.legacy.css.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.legacy.min.css b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.legacy.min.css rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.main.css b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.main.css rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.main.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.main.css.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.main.css.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.main.min.css b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.main.min.css rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.main.min.css.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.main.min.css.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.min.css b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.min.css rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.min.css diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.min.css.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.min.css.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.module.js b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.module.js rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.module.js diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.module.js.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.module.js.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.module.min.js b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.module.min.js rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.module.min.js.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.module.min.js.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.nomodule.js b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.nomodule.js rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.nomodule.js.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.nomodule.min.js b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/dsfr/dsfr.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/dsfr/dsfr.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/dsfr/dsfr.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/dsfr/dsfr.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/favicon/android-chrome-192x192.png b/web/b3desk/static/dsfr-1.7/favicon/android-chrome-192x192.png similarity index 100% rename from web/flaskr/static/dsfr-1.7/favicon/android-chrome-192x192.png rename to web/b3desk/static/dsfr-1.7/favicon/android-chrome-192x192.png diff --git a/web/flaskr/static/dsfr-1.7/favicon/android-chrome-512x512.png b/web/b3desk/static/dsfr-1.7/favicon/android-chrome-512x512.png similarity index 100% rename from web/flaskr/static/dsfr-1.7/favicon/android-chrome-512x512.png rename to web/b3desk/static/dsfr-1.7/favicon/android-chrome-512x512.png diff --git a/web/flaskr/static/dsfr-1.7/favicon/apple-touch-icon.png b/web/b3desk/static/dsfr-1.7/favicon/apple-touch-icon.png similarity index 100% rename from web/flaskr/static/dsfr-1.7/favicon/apple-touch-icon.png rename to web/b3desk/static/dsfr-1.7/favicon/apple-touch-icon.png diff --git a/web/flaskr/static/dsfr-1.7/favicon/favicon.ico b/web/b3desk/static/dsfr-1.7/favicon/favicon.ico similarity index 100% rename from web/flaskr/static/dsfr-1.7/favicon/favicon.ico rename to web/b3desk/static/dsfr-1.7/favicon/favicon.ico diff --git a/web/flaskr/static/dsfr-1.7/favicon/favicon.svg b/web/b3desk/static/dsfr-1.7/favicon/favicon.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/favicon/favicon.svg rename to web/b3desk/static/dsfr-1.7/favicon/favicon.svg diff --git a/web/flaskr/static/dsfr-1.7/favicon/manifest.webmanifest b/web/b3desk/static/dsfr-1.7/favicon/manifest.webmanifest similarity index 100% rename from web/flaskr/static/dsfr-1.7/favicon/manifest.webmanifest rename to web/b3desk/static/dsfr-1.7/favicon/manifest.webmanifest diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Bold.woff b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Bold.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Bold.woff rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Bold.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Bold.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Bold.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Bold.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Bold.woff2 diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Bold_Italic.woff b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Bold_Italic.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Bold_Italic.woff rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Bold_Italic.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Bold_Italic.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Bold_Italic.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Bold_Italic.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Bold_Italic.woff2 diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Light.woff b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Light.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Light.woff rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Light.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Light.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Light.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Light.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Light.woff2 diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Light_Italic.woff b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Light_Italic.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Light_Italic.woff rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Light_Italic.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Light_Italic.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Light_Italic.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Light_Italic.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Light_Italic.woff2 diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Medium.woff b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Medium.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Medium.woff rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Medium.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Medium.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Medium.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Medium.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Medium.woff2 diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Medium_Italic.woff b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Medium_Italic.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Medium_Italic.woff rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Medium_Italic.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Medium_Italic.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Medium_Italic.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Medium_Italic.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Medium_Italic.woff2 diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Regular.woff b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Regular.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Regular.woff rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Regular.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Regular.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Regular.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Regular.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Regular.woff2 diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Regular_Italic.woff b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Regular_Italic.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Regular_Italic.woff rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Regular_Italic.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Marianne-Regular_Italic.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Marianne-Regular_Italic.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Marianne-Regular_Italic.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Marianne-Regular_Italic.woff2 diff --git a/web/flaskr/static/dsfr-1.7/fonts/Spectral-ExtraBold.woff b/web/b3desk/static/dsfr-1.7/fonts/Spectral-ExtraBold.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Spectral-ExtraBold.woff rename to web/b3desk/static/dsfr-1.7/fonts/Spectral-ExtraBold.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Spectral-ExtraBold.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Spectral-ExtraBold.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Spectral-ExtraBold.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Spectral-ExtraBold.woff2 diff --git a/web/flaskr/static/dsfr-1.7/fonts/Spectral-Regular.woff b/web/b3desk/static/dsfr-1.7/fonts/Spectral-Regular.woff similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Spectral-Regular.woff rename to web/b3desk/static/dsfr-1.7/fonts/Spectral-Regular.woff diff --git a/web/flaskr/static/dsfr-1.7/fonts/Spectral-Regular.woff2 b/web/b3desk/static/dsfr-1.7/fonts/Spectral-Regular.woff2 similarity index 100% rename from web/flaskr/static/dsfr-1.7/fonts/Spectral-Regular.woff2 rename to web/b3desk/static/dsfr-1.7/fonts/Spectral-Regular.woff2 diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/ancient-gate-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/ancient-gate-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/ancient-gate-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/ancient-gate-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/ancient-gate-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/ancient-gate-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/ancient-gate-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/ancient-gate-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/ancient-pavilion-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/ancient-pavilion-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/ancient-pavilion-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/ancient-pavilion-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/ancient-pavilion-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/ancient-pavilion-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/ancient-pavilion-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/ancient-pavilion-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/bank-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/bank-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/bank-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/bank-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/bank-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/bank-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/bank-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/bank-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/building-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/building-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/building-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/building-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/building-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/building-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/building-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/building-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/community-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/community-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/community-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/community-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/community-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/community-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/community-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/community-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/government-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/government-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/government-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/government-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/government-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/government-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/government-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/government-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/home-4-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/home-4-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/home-4-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/home-4-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/home-4-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/home-4-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/home-4-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/home-4-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/hospital-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/hospital-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/hospital-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/hospital-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/hospital-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/hospital-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/hospital-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/hospital-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/hotel-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/hotel-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/hotel-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/hotel-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/hotel-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/hotel-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/hotel-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/hotel-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/store-fill.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/store-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/store-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/store-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/buildings/store-line.svg b/web/b3desk/static/dsfr-1.7/icons/buildings/store-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/buildings/store-line.svg rename to web/b3desk/static/dsfr-1.7/icons/buildings/store-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/archive-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/archive-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/archive-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/archive-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/archive-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/archive-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/archive-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/archive-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/attachment-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/attachment-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/attachment-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/attachment-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/attachment-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/attachment-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/attachment-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/attachment-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/award-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/award-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/award-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/award-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/award-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/award-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/award-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/award-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/bar-chart-box-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/bar-chart-box-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/bar-chart-box-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/bar-chart-box-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/bar-chart-box-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/bar-chart-box-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/bar-chart-box-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/bar-chart-box-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/bookmark-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/bookmark-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/bookmark-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/bookmark-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/bookmark-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/bookmark-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/bookmark-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/bookmark-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/briefcase-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/briefcase-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/briefcase-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/briefcase-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/briefcase-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/briefcase-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/briefcase-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/briefcase-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/calendar-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/calendar-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/calendar-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/calendar-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/calendar-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/calendar-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/calendar-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/calendar-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/calendar-event-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/calendar-event-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/calendar-event-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/calendar-event-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/calendar-event-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/calendar-event-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/calendar-event-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/calendar-event-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/calendar-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/calendar-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/calendar-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/calendar-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/calendar-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/calendar-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/calendar-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/calendar-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/cloud-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/cloud-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/cloud-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/cloud-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/cloud-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/cloud-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/cloud-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/cloud-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/copyright-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/copyright-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/copyright-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/copyright-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/copyright-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/copyright-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/copyright-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/copyright-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/customer-service-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/customer-service-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/customer-service-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/customer-service-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/customer-service-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/customer-service-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/customer-service-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/customer-service-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/flag-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/flag-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/flag-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/flag-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/flag-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/flag-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/flag-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/flag-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/global-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/global-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/global-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/global-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/global-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/global-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/global-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/global-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/line-chart-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/line-chart-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/line-chart-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/line-chart-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/line-chart-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/line-chart-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/line-chart-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/line-chart-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/links-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/links-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/links-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/links-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/links-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/links-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/links-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/links-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/mail-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/mail-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/mail-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/mail-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/mail-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/mail-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/mail-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/mail-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/mail-open-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/mail-open-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/mail-open-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/mail-open-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/mail-open-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/mail-open-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/mail-open-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/mail-open-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/medal-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/medal-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/medal-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/medal-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/medal-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/medal-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/medal-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/medal-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/pie-chart-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/pie-chart-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/pie-chart-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/pie-chart-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/pie-chart-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/pie-chart-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/pie-chart-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/pie-chart-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/pie-chart-box-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/pie-chart-box-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/pie-chart-box-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/pie-chart-box-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/pie-chart-box-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/pie-chart-box-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/pie-chart-box-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/pie-chart-box-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/printer-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/printer-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/printer-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/printer-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/printer-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/printer-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/printer-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/printer-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/profil-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/profil-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/profil-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/profil-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/profil-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/profil-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/profil-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/profil-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/projector-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/projector-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/projector-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/projector-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/projector-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/projector-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/projector-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/projector-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/send-plane-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/send-plane-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/send-plane-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/send-plane-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/send-plane-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/send-plane-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/send-plane-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/send-plane-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/slideshow-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/slideshow-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/slideshow-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/slideshow-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/slideshow-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/slideshow-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/slideshow-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/slideshow-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/window-fill.svg b/web/b3desk/static/dsfr-1.7/icons/business/window-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/window-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/business/window-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/business/window-line.svg b/web/b3desk/static/dsfr-1.7/icons/business/window-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/business/window-line.svg rename to web/b3desk/static/dsfr-1.7/icons/business/window-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-3-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-3-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-3-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-3-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-3-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-3-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-3-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-3-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-check-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-check-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-check-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-check-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-check-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-check-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-check-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-check-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-delete-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-delete-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-delete-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-delete-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-delete-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-delete-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-delete-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-delete-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-poll-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-poll-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-poll-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-poll-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/chat-poll-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/chat-poll-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/chat-poll-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/chat-poll-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/discuss-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/discuss-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/discuss-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/discuss-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/discuss-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/discuss-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/discuss-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/discuss-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/feedback-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/feedback-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/feedback-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/feedback-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/feedback-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/feedback-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/feedback-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/feedback-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/message-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/message-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/message-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/message-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/message-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/message-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/message-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/message-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/question-answer-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/question-answer-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/question-answer-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/question-answer-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/question-answer-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/question-answer-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/question-answer-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/question-answer-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/questionnaire-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/questionnaire-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/questionnaire-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/questionnaire-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/questionnaire-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/questionnaire-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/questionnaire-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/questionnaire-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/video-chat-fill.svg b/web/b3desk/static/dsfr-1.7/icons/communication/video-chat-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/video-chat-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/video-chat-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/communication/video-chat-line.svg b/web/b3desk/static/dsfr-1.7/icons/communication/video-chat-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/communication/video-chat-line.svg rename to web/b3desk/static/dsfr-1.7/icons/communication/video-chat-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/ball-pen-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/ball-pen-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/ball-pen-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/ball-pen-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/ball-pen-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/ball-pen-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/ball-pen-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/ball-pen-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/brush-3-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/brush-3-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/brush-3-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/brush-3-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/brush-3-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/brush-3-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/brush-3-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/brush-3-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/brush-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/brush-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/brush-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/brush-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/brush-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/brush-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/brush-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/brush-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/contrast-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/contrast-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/contrast-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/contrast-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/contrast-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/contrast-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/contrast-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/contrast-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/crop-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/crop-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/crop-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/crop-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/crop-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/crop-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/crop-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/crop-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/drag-move-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/drag-move-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/drag-move-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/drag-move-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/drag-move-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/drag-move-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/drag-move-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/drag-move-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/drop-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/drop-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/drop-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/drop-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/drop-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/drop-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/drop-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/drop-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/edit-box-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/edit-box-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/edit-box-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/edit-box-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/edit-box-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/edit-box-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/edit-box-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/edit-box-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/edit-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/edit-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/edit-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/edit-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/edit-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/edit-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/edit-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/edit-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/ink-bottle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/ink-bottle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/ink-bottle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/ink-bottle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/ink-bottle-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/ink-bottle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/ink-bottle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/ink-bottle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/layout-grid-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/layout-grid-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/layout-grid-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/layout-grid-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/layout-grid-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/layout-grid-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/layout-grid-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/layout-grid-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/mark-pen-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/mark-pen-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/mark-pen-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/mark-pen-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/mark-pen-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/mark-pen-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/mark-pen-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/mark-pen-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/paint-brush-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/paint-brush-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/paint-brush-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/paint-brush-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/paint-brush-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/paint-brush-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/paint-brush-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/paint-brush-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/paint-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/paint-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/paint-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/paint-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/paint-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/paint-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/paint-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/paint-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/palette-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/palette-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/palette-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/palette-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/palette-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/palette-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/palette-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/palette-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/pantone-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/pantone-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/pantone-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/pantone-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/pantone-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/pantone-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/pantone-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/pantone-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/pen-nib-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/pen-nib-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/pen-nib-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/pen-nib-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/pen-nib-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/pen-nib-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/pen-nib-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/pen-nib-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/pencil-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/pencil-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/pencil-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/pencil-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/pencil-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/pencil-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/pencil-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/pencil-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/pencil-ruler-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/pencil-ruler-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/pencil-ruler-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/pencil-ruler-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/pencil-ruler-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/pencil-ruler-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/pencil-ruler-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/pencil-ruler-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/sip-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/sip-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/sip-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/sip-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/sip-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/sip-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/sip-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/sip-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/table-fill.svg b/web/b3desk/static/dsfr-1.7/icons/design/table-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/table-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/design/table-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/design/table-line.svg b/web/b3desk/static/dsfr-1.7/icons/design/table-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/design/table-line.svg rename to web/b3desk/static/dsfr-1.7/icons/design/table-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/bug-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/bug-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/bug-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/bug-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/bug-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/bug-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/bug-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/bug-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/code-box-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/code-box-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/code-box-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/code-box-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/code-box-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/code-box-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/code-box-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/code-box-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/code-s-slash-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/code-s-slash-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/code-s-slash-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/code-s-slash-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/cursor-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/cursor-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/cursor-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/cursor-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/cursor-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/cursor-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/cursor-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/cursor-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-branch-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-branch-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-branch-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-branch-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-branch-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-branch-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-branch-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-branch-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-commit-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-commit-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-commit-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-commit-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-commit-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-commit-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-commit-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-commit-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-merge-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-merge-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-merge-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-merge-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-merge-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-merge-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-merge-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-merge-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-pull-request-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-pull-request-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-pull-request-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-pull-request-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-pull-request-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-pull-request-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-pull-request-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-pull-request-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-repository-commits-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-repository-commits-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-repository-commits-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-repository-commits-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-repository-commits-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-repository-commits-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-repository-commits-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-repository-commits-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-repository-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-repository-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-repository-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-repository-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-repository-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-repository-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-repository-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-repository-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-repository-private-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-repository-private-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-repository-private-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-repository-private-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/git-repository-private-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/git-repository-private-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/git-repository-private-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/git-repository-private-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/terminal-box-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/terminal-box-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/terminal-box-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/terminal-box-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/terminal-box-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/terminal-box-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/terminal-box-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/terminal-box-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/terminal-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/terminal-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/terminal-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/terminal-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/terminal-window-fill.svg b/web/b3desk/static/dsfr-1.7/icons/development/terminal-window-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/terminal-window-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/development/terminal-window-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/development/terminal-window-line.svg b/web/b3desk/static/dsfr-1.7/icons/development/terminal-window-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/development/terminal-window-line.svg rename to web/b3desk/static/dsfr-1.7/icons/development/terminal-window-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/bluetooth-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/bluetooth-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/bluetooth-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/bluetooth-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/bluetooth-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/bluetooth-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/bluetooth-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/bluetooth-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/computer-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/computer-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/computer-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/computer-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/computer-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/computer-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/computer-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/computer-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/dashboard-3-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/dashboard-3-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/dashboard-3-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/dashboard-3-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/dashboard-3-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/dashboard-3-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/dashboard-3-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/dashboard-3-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/database-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/database-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/database-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/database-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/database-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/database-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/database-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/database-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/device-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/device-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/device-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/device-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/device-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/device-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/device-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/device-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/hard-drive-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/hard-drive-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/hard-drive-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/hard-drive-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/hard-drive-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/hard-drive-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/hard-drive-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/hard-drive-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/mac-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/mac-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/mac-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/mac-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/mac-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/mac-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/mac-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/mac-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/phone-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/phone-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/phone-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/phone-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/phone-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/phone-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/phone-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/phone-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/qr-code-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/qr-code-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/qr-code-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/qr-code-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/qr-code-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/qr-code-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/qr-code-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/qr-code-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/rss-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/rss-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/rss-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/rss-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/rss-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/rss-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/rss-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/rss-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/save-3-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/save-3-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/save-3-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/save-3-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/save-3-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/save-3-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/save-3-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/save-3-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/save-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/save-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/save-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/save-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/save-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/save-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/save-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/save-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/server-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/server-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/server-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/server-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/server-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/server-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/server-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/server-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/smartphone-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/smartphone-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/smartphone-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/smartphone-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/smartphone-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/smartphone-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/smartphone-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/smartphone-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/tablet-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/tablet-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/tablet-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/tablet-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/tablet-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/tablet-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/tablet-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/tablet-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/tv-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/tv-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/tv-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/tv-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/tv-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/tv-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/tv-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/tv-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/wifi-fill.svg b/web/b3desk/static/dsfr-1.7/icons/device/wifi-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/wifi-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/device/wifi-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/device/wifi-line.svg b/web/b3desk/static/dsfr-1.7/icons/device/wifi-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/device/wifi-line.svg rename to web/b3desk/static/dsfr-1.7/icons/device/wifi-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/article-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/article-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/article-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/article-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/article-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/article-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/article-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/article-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/book-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/book-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/book-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/book-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/book-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/book-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/book-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/book-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/booklet-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/booklet-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/booklet-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/booklet-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/booklet-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/booklet-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/booklet-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/booklet-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/clipboard-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/clipboard-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/clipboard-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/clipboard-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/clipboard-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/clipboard-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/clipboard-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/clipboard-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/draft-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/draft-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/draft-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/draft-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/draft-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/draft-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/draft-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/draft-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-add-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-add-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-add-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-add-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-add-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-add-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-add-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-add-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-download-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-download-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-download-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-download-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-download-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-download-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-download-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-download-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-pdf-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-pdf-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-pdf-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-pdf-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-pdf-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-pdf-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-pdf-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-pdf-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-text-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-text-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-text-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-text-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/file-text-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/file-text-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/file-text-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/file-text-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/folder-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/folder-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/folder-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/folder-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/folder-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/folder-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/folder-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/folder-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/newspaper-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/newspaper-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/newspaper-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/newspaper-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/newspaper-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/newspaper-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/newspaper-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/newspaper-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/survey-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/survey-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/survey-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/survey-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/survey-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/survey-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/survey-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/survey-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/todo-fill.svg b/web/b3desk/static/dsfr-1.7/icons/document/todo-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/todo-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/document/todo-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/document/todo-line.svg b/web/b3desk/static/dsfr-1.7/icons/document/todo-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/document/todo-line.svg rename to web/b3desk/static/dsfr-1.7/icons/document/todo-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/code-view.svg b/web/b3desk/static/dsfr-1.7/icons/editor/code-view.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/code-view.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/code-view.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/font-size.svg b/web/b3desk/static/dsfr-1.7/icons/editor/font-size.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/font-size.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/font-size.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/fr--bold.svg b/web/b3desk/static/dsfr-1.7/icons/editor/fr--bold.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/fr--bold.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/fr--bold.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/fr--highlight.svg b/web/b3desk/static/dsfr-1.7/icons/editor/fr--highlight.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/fr--highlight.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/fr--highlight.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/fr--quote-fill.svg b/web/b3desk/static/dsfr-1.7/icons/editor/fr--quote-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/fr--quote-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/fr--quote-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/fr--quote-line.svg b/web/b3desk/static/dsfr-1.7/icons/editor/fr--quote-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/fr--quote-line.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/fr--quote-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/h-1.svg b/web/b3desk/static/dsfr-1.7/icons/editor/h-1.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/h-1.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/h-1.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/h-2.svg b/web/b3desk/static/dsfr-1.7/icons/editor/h-2.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/h-2.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/h-2.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/h-3.svg b/web/b3desk/static/dsfr-1.7/icons/editor/h-3.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/h-3.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/h-3.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/h-4.svg b/web/b3desk/static/dsfr-1.7/icons/editor/h-4.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/h-4.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/h-4.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/h-5.svg b/web/b3desk/static/dsfr-1.7/icons/editor/h-5.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/h-5.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/h-5.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/h-6.svg b/web/b3desk/static/dsfr-1.7/icons/editor/h-6.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/h-6.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/h-6.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/hashtag.svg b/web/b3desk/static/dsfr-1.7/icons/editor/hashtag.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/hashtag.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/hashtag.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/italic.svg b/web/b3desk/static/dsfr-1.7/icons/editor/italic.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/italic.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/italic.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/link-unlink.svg b/web/b3desk/static/dsfr-1.7/icons/editor/link-unlink.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/link-unlink.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/link-unlink.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/link.svg b/web/b3desk/static/dsfr-1.7/icons/editor/link.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/link.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/link.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/list-ordered.svg b/web/b3desk/static/dsfr-1.7/icons/editor/list-ordered.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/list-ordered.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/list-ordered.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/list-unordered.svg b/web/b3desk/static/dsfr-1.7/icons/editor/list-unordered.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/list-unordered.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/list-unordered.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/question-mark.svg b/web/b3desk/static/dsfr-1.7/icons/editor/question-mark.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/question-mark.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/question-mark.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/separator.svg b/web/b3desk/static/dsfr-1.7/icons/editor/separator.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/separator.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/separator.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/space.svg b/web/b3desk/static/dsfr-1.7/icons/editor/space.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/space.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/space.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/subscript.svg b/web/b3desk/static/dsfr-1.7/icons/editor/subscript.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/subscript.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/subscript.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/superscript.svg b/web/b3desk/static/dsfr-1.7/icons/editor/superscript.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/superscript.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/superscript.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/table-2.svg b/web/b3desk/static/dsfr-1.7/icons/editor/table-2.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/table-2.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/table-2.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/editor/translate-2.svg b/web/b3desk/static/dsfr-1.7/icons/editor/translate-2.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/editor/translate-2.svg rename to web/b3desk/static/dsfr-1.7/icons/editor/translate-2.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/bank-card-fill.svg b/web/b3desk/static/dsfr-1.7/icons/finance/bank-card-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/bank-card-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/bank-card-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/bank-card-line.svg b/web/b3desk/static/dsfr-1.7/icons/finance/bank-card-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/bank-card-line.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/bank-card-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/coin-fill.svg b/web/b3desk/static/dsfr-1.7/icons/finance/coin-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/coin-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/coin-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/gift-fill.svg b/web/b3desk/static/dsfr-1.7/icons/finance/gift-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/gift-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/gift-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/gift-line.svg b/web/b3desk/static/dsfr-1.7/icons/finance/gift-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/gift-line.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/gift-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/money-euro-box-fill.svg b/web/b3desk/static/dsfr-1.7/icons/finance/money-euro-box-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/money-euro-box-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/money-euro-box-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/money-euro-box-line.svg b/web/b3desk/static/dsfr-1.7/icons/finance/money-euro-box-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/money-euro-box-line.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/money-euro-box-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/money-euro-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/finance/money-euro-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/money-euro-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/money-euro-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/money-euro-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/finance/money-euro-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/money-euro-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/money-euro-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/secure-payment-fill.svg b/web/b3desk/static/dsfr-1.7/icons/finance/secure-payment-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/secure-payment-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/secure-payment-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/secure-payment-line.svg b/web/b3desk/static/dsfr-1.7/icons/finance/secure-payment-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/secure-payment-line.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/secure-payment-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/shopping-bag-fill.svg b/web/b3desk/static/dsfr-1.7/icons/finance/shopping-bag-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/shopping-bag-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/shopping-bag-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/shopping-bag-line.svg b/web/b3desk/static/dsfr-1.7/icons/finance/shopping-bag-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/shopping-bag-line.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/shopping-bag-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/shopping-cart-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/finance/shopping-cart-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/shopping-cart-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/shopping-cart-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/shopping-cart-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/finance/shopping-cart-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/shopping-cart-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/shopping-cart-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/trophy-fill.svg b/web/b3desk/static/dsfr-1.7/icons/finance/trophy-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/trophy-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/trophy-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/finance/trophy-line.svg b/web/b3desk/static/dsfr-1.7/icons/finance/trophy-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/finance/trophy-line.svg rename to web/b3desk/static/dsfr-1.7/icons/finance/trophy-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/capsule-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/capsule-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/capsule-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/capsule-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/capsule-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/capsule-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/capsule-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/capsule-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/dislike-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/dislike-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/dislike-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/dislike-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/dislike-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/dislike-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/dislike-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/dislike-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/dossier-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/dossier-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/dossier-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/dossier-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/dossier-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/dossier-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/dossier-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/dossier-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/first-aid-kit-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/first-aid-kit-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/first-aid-kit-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/first-aid-kit-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/first-aid-kit-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/first-aid-kit-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/first-aid-kit-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/first-aid-kit-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/hand-sanitizer-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/hand-sanitizer-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/hand-sanitizer-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/hand-sanitizer-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/hand-sanitizer-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/hand-sanitizer-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/hand-sanitizer-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/hand-sanitizer-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/health-book-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/health-book-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/health-book-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/health-book-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/health-book-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/health-book-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/health-book-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/health-book-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/heart-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/heart-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/heart-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/heart-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/heart-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/heart-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/heart-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/heart-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/heart-pulse-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/heart-pulse-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/heart-pulse-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/heart-pulse-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/heart-pulse-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/heart-pulse-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/heart-pulse-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/heart-pulse-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/lungs-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/lungs-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/lungs-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/lungs-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/lungs-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/lungs-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/lungs-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/lungs-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/medicine-bottle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/medicine-bottle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/medicine-bottle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/medicine-bottle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/medicine-bottle-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/medicine-bottle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/medicine-bottle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/medicine-bottle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/mental-health-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/mental-health-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/mental-health-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/mental-health-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/mental-health-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/mental-health-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/mental-health-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/mental-health-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/microscope-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/microscope-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/microscope-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/microscope-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/microscope-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/microscope-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/microscope-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/microscope-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/psychotherapy-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/psychotherapy-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/psychotherapy-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/psychotherapy-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/psychotherapy-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/psychotherapy-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/psychotherapy-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/psychotherapy-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/pulse-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/pulse-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/pulse-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/pulse-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/stethoscope-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/stethoscope-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/stethoscope-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/stethoscope-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/stethoscope-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/stethoscope-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/stethoscope-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/stethoscope-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/surgical-mask-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/surgical-mask-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/surgical-mask-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/surgical-mask-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/surgical-mask-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/surgical-mask-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/surgical-mask-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/surgical-mask-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/syringe-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/syringe-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/syringe-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/syringe-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/syringe-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/syringe-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/syringe-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/syringe-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/test-tube-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/test-tube-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/test-tube-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/test-tube-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/test-tube-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/test-tube-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/test-tube-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/test-tube-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/thermometer-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/thermometer-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/thermometer-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/thermometer-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/thermometer-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/thermometer-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/thermometer-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/thermometer-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/virus-fill.svg b/web/b3desk/static/dsfr-1.7/icons/health/virus-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/virus-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/health/virus-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/health/virus-line.svg b/web/b3desk/static/dsfr-1.7/icons/health/virus-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/health/virus-line.svg rename to web/b3desk/static/dsfr-1.7/icons/health/virus-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/chrome-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/chrome-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/chrome-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/chrome-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/chrome-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/chrome-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/chrome-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/chrome-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/edge-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/edge-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/edge-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/edge-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/edge-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/edge-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/edge-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/edge-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/facebook-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/facebook-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/facebook-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/facebook-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/facebook-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/facebook-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/facebook-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/facebook-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/firefox-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/firefox-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/firefox-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/firefox-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/firefox-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/firefox-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/firefox-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/firefox-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/fr--dailymotion-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/fr--dailymotion-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/fr--dailymotion-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/fr--dailymotion-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/fr--dailymotion-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/fr--dailymotion-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/fr--dailymotion-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/fr--dailymotion-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/fr--tiktok-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/fr--tiktok-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/fr--tiktok-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/fr--tiktok-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/fr--tiktok-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/fr--tiktok-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/fr--tiktok-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/fr--tiktok-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/github-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/github-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/github-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/github-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/github-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/github-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/github-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/github-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/google-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/google-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/google-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/google-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/google-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/google-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/google-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/google-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/ie-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/ie-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/ie-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/ie-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/ie-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/ie-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/ie-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/ie-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/instagram-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/instagram-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/instagram-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/instagram-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/instagram-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/instagram-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/instagram-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/instagram-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/linkedin-box-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/linkedin-box-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/linkedin-box-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/linkedin-box-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/linkedin-box-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/linkedin-box-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/linkedin-box-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/linkedin-box-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/mastodon-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/mastodon-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/mastodon-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/mastodon-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/mastodon-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/mastodon-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/mastodon-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/mastodon-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/npmjs-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/npmjs-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/npmjs-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/npmjs-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/npmjs-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/npmjs-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/npmjs-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/npmjs-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/remixicon-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/remixicon-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/remixicon-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/remixicon-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/remixicon-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/remixicon-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/remixicon-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/remixicon-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/safari-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/safari-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/safari-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/safari-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/safari-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/safari-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/safari-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/safari-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/slack-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/slack-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/slack-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/slack-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/slack-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/slack-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/slack-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/slack-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/snapchat-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/snapchat-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/snapchat-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/snapchat-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/snapchat-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/snapchat-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/snapchat-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/snapchat-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/telegram-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/telegram-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/telegram-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/telegram-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/telegram-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/telegram-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/telegram-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/telegram-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/twitch-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/twitch-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/twitch-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/twitch-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/twitch-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/twitch-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/twitch-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/twitch-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/twitter-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/twitter-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/twitter-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/twitter-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/twitter-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/twitter-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/twitter-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/twitter-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/vimeo-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/vimeo-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/vimeo-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/vimeo-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/vimeo-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/vimeo-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/vimeo-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/vimeo-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/vuejs-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/vuejs-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/vuejs-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/vuejs-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/vuejs-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/vuejs-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/vuejs-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/vuejs-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/youtube-fill.svg b/web/b3desk/static/dsfr-1.7/icons/logo/youtube-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/youtube-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/youtube-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/logo/youtube-line.svg b/web/b3desk/static/dsfr-1.7/icons/logo/youtube-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/logo/youtube-line.svg rename to web/b3desk/static/dsfr-1.7/icons/logo/youtube-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/anchor-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/anchor-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/anchor-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/anchor-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/anchor-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/anchor-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/anchor-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/anchor-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/bike-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/bike-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/bike-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/bike-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/bike-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/bike-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/bike-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/bike-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/bus-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/bus-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/bus-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/bus-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/bus-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/bus-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/bus-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/bus-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/car-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/car-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/car-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/car-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/car-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/car-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/car-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/car-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/caravan-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/caravan-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/caravan-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/caravan-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/caravan-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/caravan-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/caravan-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/caravan-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/charging-pile-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/charging-pile-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/charging-pile-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/charging-pile-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/charging-pile-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/charging-pile-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/charging-pile-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/charging-pile-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/compass-3-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/compass-3-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/compass-3-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/compass-3-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/compass-3-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/compass-3-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/compass-3-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/compass-3-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/cup-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/cup-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/cup-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/cup-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/cup-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/cup-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/cup-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/cup-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/earth-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/earth-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/earth-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/earth-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/earth-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/earth-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/earth-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/earth-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/france-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/france-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/france-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/france-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/france-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/france-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/france-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/france-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/gas-station-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/gas-station-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/gas-station-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/gas-station-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/gas-station-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/gas-station-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/gas-station-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/gas-station-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/goblet-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/goblet-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/goblet-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/goblet-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/goblet-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/goblet-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/goblet-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/goblet-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/map-pin-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/map-pin-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/map-pin-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/map-pin-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/map-pin-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/map-pin-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/map-pin-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/map-pin-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/map-pin-user-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/map-pin-user-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/map-pin-user-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/map-pin-user-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/map-pin-user-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/map-pin-user-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/map-pin-user-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/map-pin-user-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/motorbike-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/motorbike-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/motorbike-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/motorbike-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/motorbike-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/motorbike-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/motorbike-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/motorbike-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/passport-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/passport-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/passport-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/passport-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/passport-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/passport-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/passport-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/passport-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/restaurant-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/restaurant-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/restaurant-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/restaurant-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/restaurant-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/restaurant-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/restaurant-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/restaurant-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/road-map-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/road-map-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/road-map-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/road-map-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/road-map-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/road-map-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/road-map-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/road-map-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/sailboat-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/sailboat-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/sailboat-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/sailboat-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/sailboat-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/sailboat-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/sailboat-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/sailboat-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/ship-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/ship-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/ship-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/ship-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/ship-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/ship-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/ship-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/ship-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/signal-tower-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/signal-tower-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/signal-tower-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/signal-tower-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/signal-tower-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/signal-tower-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/signal-tower-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/signal-tower-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/suitcase-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/suitcase-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/suitcase-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/suitcase-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/suitcase-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/suitcase-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/suitcase-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/suitcase-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/taxi-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/taxi-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/taxi-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/taxi-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/taxi-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/taxi-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/taxi-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/taxi-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/train-fill.svg b/web/b3desk/static/dsfr-1.7/icons/map/train-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/train-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/map/train-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/map/train-line.svg b/web/b3desk/static/dsfr-1.7/icons/map/train-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/map/train-line.svg rename to web/b3desk/static/dsfr-1.7/icons/map/train-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/camera-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/camera-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/camera-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/camera-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/camera-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/camera-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/camera-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/camera-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/clapperboard-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/clapperboard-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/clapperboard-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/clapperboard-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/clapperboard-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/clapperboard-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/clapperboard-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/clapperboard-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/equalizer-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/equalizer-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/equalizer-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/equalizer-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/equalizer-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/equalizer-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/equalizer-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/equalizer-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/film-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/film-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/film-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/film-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/film-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/film-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/film-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/film-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/gallery-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/gallery-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/gallery-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/gallery-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/gallery-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/gallery-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/gallery-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/gallery-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/headphone-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/headphone-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/headphone-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/headphone-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/headphone-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/headphone-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/headphone-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/headphone-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/image-add-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/image-add-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/image-add-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/image-add-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/image-add-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/image-add-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/image-add-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/image-add-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/image-edit-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/image-edit-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/image-edit-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/image-edit-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/image-edit-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/image-edit-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/image-edit-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/image-edit-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/image-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/image-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/image-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/image-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/image-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/image-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/image-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/image-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/live-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/live-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/live-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/live-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/live-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/live-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/live-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/live-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/mic-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/mic-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/mic-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/mic-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/mic-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/mic-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/mic-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/mic-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/music-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/music-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/music-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/music-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/music-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/music-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/music-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/music-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/notification-3-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/notification-3-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/notification-3-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/notification-3-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/notification-3-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/notification-3-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/notification-3-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/notification-3-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/pause-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/pause-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/pause-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/pause-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/pause-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/pause-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/pause-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/pause-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/play-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/play-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/play-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/play-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/play-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/play-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/play-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/play-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/stop-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/stop-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/stop-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/stop-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/stop-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/stop-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/stop-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/stop-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/transcription.svg b/web/b3desk/static/dsfr-1.7/icons/media/transcription.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/transcription.svg rename to web/b3desk/static/dsfr-1.7/icons/media/transcription.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/volume-down-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/volume-down-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/volume-down-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/volume-down-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/volume-down-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/volume-down-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/volume-down-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/volume-down-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/volume-mute-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/volume-mute-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/volume-mute-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/volume-mute-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/volume-mute-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/volume-mute-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/volume-mute-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/volume-mute-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/volume-up-fill.svg b/web/b3desk/static/dsfr-1.7/icons/media/volume-up-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/volume-up-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/media/volume-up-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/media/volume-up-line.svg b/web/b3desk/static/dsfr-1.7/icons/media/volume-up-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/media/volume-up-line.svg rename to web/b3desk/static/dsfr-1.7/icons/media/volume-up-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/leaf-fill.svg b/web/b3desk/static/dsfr-1.7/icons/others/leaf-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/leaf-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/others/leaf-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/leaf-line.svg b/web/b3desk/static/dsfr-1.7/icons/others/leaf-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/leaf-line.svg rename to web/b3desk/static/dsfr-1.7/icons/others/leaf-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/lightbulb-fill.svg b/web/b3desk/static/dsfr-1.7/icons/others/lightbulb-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/lightbulb-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/others/lightbulb-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/lightbulb-line.svg b/web/b3desk/static/dsfr-1.7/icons/others/lightbulb-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/lightbulb-line.svg rename to web/b3desk/static/dsfr-1.7/icons/others/lightbulb-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/plant-fill.svg b/web/b3desk/static/dsfr-1.7/icons/others/plant-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/plant-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/others/plant-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/plant-line.svg b/web/b3desk/static/dsfr-1.7/icons/others/plant-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/plant-line.svg rename to web/b3desk/static/dsfr-1.7/icons/others/plant-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/recycle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/others/recycle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/recycle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/others/recycle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/recycle-line.svg b/web/b3desk/static/dsfr-1.7/icons/others/recycle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/recycle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/others/recycle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/scales-3-fill.svg b/web/b3desk/static/dsfr-1.7/icons/others/scales-3-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/scales-3-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/others/scales-3-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/scales-3-line.svg b/web/b3desk/static/dsfr-1.7/icons/others/scales-3-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/scales-3-line.svg rename to web/b3desk/static/dsfr-1.7/icons/others/scales-3-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/seedling-fill.svg b/web/b3desk/static/dsfr-1.7/icons/others/seedling-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/seedling-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/others/seedling-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/seedling-line.svg b/web/b3desk/static/dsfr-1.7/icons/others/seedling-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/seedling-line.svg rename to web/b3desk/static/dsfr-1.7/icons/others/seedling-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/umbrella-fill.svg b/web/b3desk/static/dsfr-1.7/icons/others/umbrella-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/umbrella-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/others/umbrella-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/others/umbrella-line.svg b/web/b3desk/static/dsfr-1.7/icons/others/umbrella-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/others/umbrella-line.svg rename to web/b3desk/static/dsfr-1.7/icons/others/umbrella-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/add-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/add-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/add-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/add-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/add-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/add-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/add-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/add-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/add-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/add-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/add-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/add-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/alarm-warning-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/alarm-warning-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/alarm-warning-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/alarm-warning-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/alarm-warning-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/alarm-warning-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/alarm-warning-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/alarm-warning-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/alert-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/alert-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/alert-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/alert-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/alert-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/alert-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/alert-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/alert-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-down-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-down-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-down-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-down-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-down-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-down-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-down-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-down-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-down-s-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-down-s-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-down-s-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-down-s-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-down-s-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-down-s-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-down-s-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-down-s-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-go-back-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-go-back-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-go-back-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-go-back-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-go-back-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-go-back-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-go-back-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-go-back-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-go-forward-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-go-forward-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-go-forward-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-go-forward-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-go-forward-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-go-forward-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-go-forward-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-go-forward-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-left-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-left-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-left-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-left-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-left-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-left-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-left-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-left-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-left-s-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-left-s-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-left-s-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-left-s-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-left-s-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-left-s-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-left-s-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-left-s-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-right-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-right-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-right-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-right-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-right-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-right-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-right-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-right-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-right-s-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-right-s-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-right-s-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-right-s-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-right-s-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-right-s-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-right-s-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-right-s-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-right-up-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-right-up-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-right-up-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-right-up-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-up-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-up-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-up-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-up-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-up-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-up-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-up-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-up-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-up-s-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-up-s-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-up-s-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-up-s-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/arrow-up-s-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/arrow-up-s-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/arrow-up-s-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/arrow-up-s-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/check-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/check-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/check-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/check-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/checkbox-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/checkbox-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/checkbox-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/checkbox-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/checkbox-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/checkbox-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/checkbox-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/checkbox-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/checkbox-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/checkbox-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/checkbox-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/checkbox-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/checkbox-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/checkbox-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/checkbox-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/checkbox-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/close-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/close-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/close-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/close-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/close-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/close-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/close-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/close-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/close-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/close-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/close-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/close-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/delete-bin-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/delete-bin-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/delete-bin-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/delete-bin-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/delete-bin-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/delete-bin-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/delete-bin-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/delete-bin-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/download-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/download-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/download-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/download-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/download-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/download-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/download-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/download-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/error-warning-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/error-warning-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/error-warning-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/error-warning-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/error-warning-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/error-warning-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/error-warning-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/error-warning-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/external-link-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/external-link-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/external-link-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/external-link-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/external-link-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/external-link-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/external-link-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/external-link-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/eye-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/eye-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/eye-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/eye-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/eye-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/eye-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/eye-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/eye-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/eye-off-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/eye-off-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/eye-off-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/eye-off-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/eye-off-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/eye-off-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/eye-off-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/eye-off-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/filter-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/filter-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/filter-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/filter-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/filter-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/filter-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/filter-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/filter-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--arrow-left-s-first-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--arrow-left-s-first-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--arrow-left-s-first-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--arrow-left-s-first-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--arrow-left-s-line-double.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--arrow-left-s-line-double.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--arrow-left-s-line-double.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--arrow-left-s-line-double.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--arrow-right-s-last-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--arrow-right-s-last-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--arrow-right-s-last-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--arrow-right-s-last-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--arrow-right-s-line-double.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--arrow-right-s-line-double.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--arrow-right-s-line-double.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--arrow-right-s-line-double.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--error-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--error-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--error-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--error-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--error-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--error-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--error-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--error-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--info-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--info-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--info-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--info-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--info-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--info-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--info-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--info-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--success-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--success-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--success-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--success-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--success-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--success-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--success-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--success-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--theme-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--theme-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--theme-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--theme-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--warning-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--warning-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--warning-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--warning-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/fr--warning-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/fr--warning-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/fr--warning-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/fr--warning-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/information-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/information-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/information-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/information-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/information-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/information-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/information-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/information-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/lock-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/lock-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/lock-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/lock-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/lock-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/lock-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/lock-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/lock-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/lock-unlock-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/lock-unlock-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/lock-unlock-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/lock-unlock-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/lock-unlock-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/lock-unlock-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/lock-unlock-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/lock-unlock-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/logout-box-r-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/logout-box-r-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/logout-box-r-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/logout-box-r-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/logout-box-r-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/logout-box-r-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/logout-box-r-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/logout-box-r-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/menu-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/menu-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/menu-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/menu-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/menu-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/menu-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/menu-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/menu-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/more-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/more-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/more-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/more-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/more-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/more-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/more-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/more-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/notification-badge-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/notification-badge-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/notification-badge-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/notification-badge-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/notification-badge-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/notification-badge-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/notification-badge-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/notification-badge-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/question-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/question-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/question-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/question-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/question-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/question-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/question-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/question-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/refresh-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/refresh-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/refresh-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/refresh-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/refresh-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/refresh-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/refresh-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/refresh-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/search-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/search-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/search-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/search-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/search-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/search-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/search-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/search-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/settings-5-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/settings-5-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/settings-5-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/settings-5-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/settings-5-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/settings-5-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/settings-5-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/settings-5-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/shield-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/shield-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/shield-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/shield-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/shield-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/shield-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/shield-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/shield-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/star-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/star-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/star-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/star-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/star-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/star-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/star-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/star-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/star-s-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/star-s-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/star-s-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/star-s-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/star-s-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/star-s-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/star-s-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/star-s-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/subtract-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/subtract-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/subtract-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/subtract-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/thumb-down-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/thumb-down-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/thumb-down-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/thumb-down-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/thumb-down-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/thumb-down-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/thumb-down-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/thumb-down-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/thumb-up-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/thumb-up-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/thumb-up-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/thumb-up-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/thumb-up-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/thumb-up-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/thumb-up-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/thumb-up-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/time-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/time-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/time-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/time-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/time-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/time-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/time-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/time-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/timer-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/timer-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/timer-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/timer-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/timer-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/timer-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/timer-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/timer-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/upload-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/upload-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/upload-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/upload-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/upload-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/upload-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/upload-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/upload-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/upload-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/upload-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/upload-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/upload-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/upload-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/upload-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/upload-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/upload-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/zoom-in-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/zoom-in-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/zoom-in-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/zoom-in-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/zoom-in-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/zoom-in-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/zoom-in-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/zoom-in-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/zoom-out-fill.svg b/web/b3desk/static/dsfr-1.7/icons/system/zoom-out-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/zoom-out-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/system/zoom-out-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/system/zoom-out-line.svg b/web/b3desk/static/dsfr-1.7/icons/system/zoom-out-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/system/zoom-out-line.svg rename to web/b3desk/static/dsfr-1.7/icons/system/zoom-out-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/account-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/account-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/account-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/account-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/account-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/account-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/account-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/account-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/account-pin-circle-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/account-pin-circle-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/account-pin-circle-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/account-pin-circle-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/account-pin-circle-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/account-pin-circle-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/account-pin-circle-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/account-pin-circle-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/admin-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/admin-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/admin-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/admin-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/admin-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/admin-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/admin-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/admin-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/group-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/group-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/group-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/group-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/group-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/group-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/group-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/group-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/parent-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/parent-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/parent-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/parent-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/parent-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/parent-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/parent-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/parent-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/team-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/team-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/team-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/team-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/team-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/team-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/team-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/team-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-add-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-add-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-add-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-add-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-add-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-add-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-add-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-add-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-heart-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-heart-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-heart-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-heart-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-heart-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-heart-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-heart-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-heart-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-search-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-search-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-search-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-search-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-search-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-search-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-search-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-search-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-setting-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-setting-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-setting-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-setting-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-setting-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-setting-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-setting-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-setting-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-star-fill.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-star-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-star-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-star-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/user/user-star-line.svg b/web/b3desk/static/dsfr-1.7/icons/user/user-star-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/user/user-star-line.svg rename to web/b3desk/static/dsfr-1.7/icons/user/user-star-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/weather/cloudy-2-fill.svg b/web/b3desk/static/dsfr-1.7/icons/weather/cloudy-2-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/weather/cloudy-2-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/weather/cloudy-2-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/weather/cloudy-2-line.svg b/web/b3desk/static/dsfr-1.7/icons/weather/cloudy-2-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/weather/cloudy-2-line.svg rename to web/b3desk/static/dsfr-1.7/icons/weather/cloudy-2-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/weather/flashlight-fill.svg b/web/b3desk/static/dsfr-1.7/icons/weather/flashlight-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/weather/flashlight-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/weather/flashlight-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/weather/flashlight-line.svg b/web/b3desk/static/dsfr-1.7/icons/weather/flashlight-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/weather/flashlight-line.svg rename to web/b3desk/static/dsfr-1.7/icons/weather/flashlight-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/weather/moon-fill.svg b/web/b3desk/static/dsfr-1.7/icons/weather/moon-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/weather/moon-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/weather/moon-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/weather/moon-line.svg b/web/b3desk/static/dsfr-1.7/icons/weather/moon-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/weather/moon-line.svg rename to web/b3desk/static/dsfr-1.7/icons/weather/moon-line.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/weather/sun-fill.svg b/web/b3desk/static/dsfr-1.7/icons/weather/sun-fill.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/weather/sun-fill.svg rename to web/b3desk/static/dsfr-1.7/icons/weather/sun-fill.svg diff --git a/web/flaskr/static/dsfr-1.7/icons/weather/sun-line.svg b/web/b3desk/static/dsfr-1.7/icons/weather/sun-line.svg similarity index 100% rename from web/flaskr/static/dsfr-1.7/icons/weather/sun-line.svg rename to web/b3desk/static/dsfr-1.7/icons/weather/sun-line.svg diff --git a/web/flaskr/static/dsfr-1.7/legacy/README.md b/web/b3desk/static/dsfr-1.7/legacy/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/legacy/README.md rename to web/b3desk/static/dsfr-1.7/legacy/README.md diff --git a/web/flaskr/static/dsfr-1.7/legacy/legacy.nomodule.js b/web/b3desk/static/dsfr-1.7/legacy/legacy.nomodule.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/legacy/legacy.nomodule.js rename to web/b3desk/static/dsfr-1.7/legacy/legacy.nomodule.js diff --git a/web/flaskr/static/dsfr-1.7/legacy/legacy.nomodule.js.map b/web/b3desk/static/dsfr-1.7/legacy/legacy.nomodule.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/legacy/legacy.nomodule.js.map rename to web/b3desk/static/dsfr-1.7/legacy/legacy.nomodule.js.map diff --git a/web/flaskr/static/dsfr-1.7/legacy/legacy.nomodule.min.js b/web/b3desk/static/dsfr-1.7/legacy/legacy.nomodule.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/legacy/legacy.nomodule.min.js rename to web/b3desk/static/dsfr-1.7/legacy/legacy.nomodule.min.js diff --git a/web/flaskr/static/dsfr-1.7/legacy/legacy.nomodule.min.js.map b/web/b3desk/static/dsfr-1.7/legacy/legacy.nomodule.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/legacy/legacy.nomodule.min.js.map rename to web/b3desk/static/dsfr-1.7/legacy/legacy.nomodule.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/page/README.md b/web/b3desk/static/dsfr-1.7/page/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/page/README.md rename to web/b3desk/static/dsfr-1.7/page/README.md diff --git a/web/flaskr/static/dsfr-1.7/page/response/README.md b/web/b3desk/static/dsfr-1.7/page/response/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/page/response/README.md rename to web/b3desk/static/dsfr-1.7/page/response/README.md diff --git a/web/flaskr/static/dsfr-1.7/page/response/not-found/README.md b/web/b3desk/static/dsfr-1.7/page/response/not-found/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/page/response/not-found/README.md rename to web/b3desk/static/dsfr-1.7/page/response/not-found/README.md diff --git a/web/flaskr/static/dsfr-1.7/page/response/unavailable/README.md b/web/b3desk/static/dsfr-1.7/page/response/unavailable/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/page/response/unavailable/README.md rename to web/b3desk/static/dsfr-1.7/page/response/unavailable/README.md diff --git a/web/flaskr/static/dsfr-1.7/pattern/README.md b/web/b3desk/static/dsfr-1.7/pattern/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/pattern/README.md rename to web/b3desk/static/dsfr-1.7/pattern/README.md diff --git a/web/flaskr/static/dsfr-1.7/scheme/README.md b/web/b3desk/static/dsfr-1.7/scheme/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/scheme/README.md rename to web/b3desk/static/dsfr-1.7/scheme/README.md diff --git a/web/flaskr/static/dsfr-1.7/scheme/scheme.css b/web/b3desk/static/dsfr-1.7/scheme/scheme.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/scheme/scheme.css rename to web/b3desk/static/dsfr-1.7/scheme/scheme.css diff --git a/web/flaskr/static/dsfr-1.7/scheme/scheme.css.map b/web/b3desk/static/dsfr-1.7/scheme/scheme.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/scheme/scheme.css.map rename to web/b3desk/static/dsfr-1.7/scheme/scheme.css.map diff --git a/web/flaskr/static/dsfr-1.7/scheme/scheme.min.css b/web/b3desk/static/dsfr-1.7/scheme/scheme.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/scheme/scheme.min.css rename to web/b3desk/static/dsfr-1.7/scheme/scheme.min.css diff --git a/web/flaskr/static/dsfr-1.7/scheme/scheme.min.css.map b/web/b3desk/static/dsfr-1.7/scheme/scheme.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/scheme/scheme.min.css.map rename to web/b3desk/static/dsfr-1.7/scheme/scheme.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/scheme/scheme.module.js b/web/b3desk/static/dsfr-1.7/scheme/scheme.module.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/scheme/scheme.module.js rename to web/b3desk/static/dsfr-1.7/scheme/scheme.module.js diff --git a/web/flaskr/static/dsfr-1.7/scheme/scheme.module.js.map b/web/b3desk/static/dsfr-1.7/scheme/scheme.module.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/scheme/scheme.module.js.map rename to web/b3desk/static/dsfr-1.7/scheme/scheme.module.js.map diff --git a/web/flaskr/static/dsfr-1.7/scheme/scheme.module.min.js b/web/b3desk/static/dsfr-1.7/scheme/scheme.module.min.js similarity index 100% rename from web/flaskr/static/dsfr-1.7/scheme/scheme.module.min.js rename to web/b3desk/static/dsfr-1.7/scheme/scheme.module.min.js diff --git a/web/flaskr/static/dsfr-1.7/scheme/scheme.module.min.js.map b/web/b3desk/static/dsfr-1.7/scheme/scheme.module.min.js.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/scheme/scheme.module.min.js.map rename to web/b3desk/static/dsfr-1.7/scheme/scheme.module.min.js.map diff --git a/web/flaskr/static/dsfr-1.7/utility/README.md b/web/b3desk/static/dsfr-1.7/utility/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/README.md rename to web/b3desk/static/dsfr-1.7/utility/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/README.md b/web/b3desk/static/dsfr-1.7/utility/colors/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/README.md rename to web/b3desk/static/dsfr-1.7/utility/colors/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.css b/web/b3desk/static/dsfr-1.7/utility/colors/colors.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.css rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.css diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.css.map b/web/b3desk/static/dsfr-1.7/utility/colors/colors.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.css.map rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.legacy.css b/web/b3desk/static/dsfr-1.7/utility/colors/colors.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/colors/colors.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/colors/colors.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/colors/colors.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.main.css b/web/b3desk/static/dsfr-1.7/utility/colors/colors.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.main.css rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.main.css.map b/web/b3desk/static/dsfr-1.7/utility/colors/colors.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.main.min.css b/web/b3desk/static/dsfr-1.7/utility/colors/colors.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/colors/colors.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.min.css b/web/b3desk/static/dsfr-1.7/utility/colors/colors.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.min.css rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/colors/colors.min.css.map b/web/b3desk/static/dsfr-1.7/utility/colors/colors.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/colors/colors.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/colors/colors.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-buildings/icons-buildings.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-business/icons-business.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-business/icons-business.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-communication/icons-communication.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-design/icons-design.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-design/icons-design.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-development/icons-development.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-development/icons-development.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-device/icons-device.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-device/icons-device.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-document/icons-document.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-document/icons-document.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-editor/icons-editor.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-finance/icons-finance.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-health/icons-health.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-health/icons-health.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-logo/icons-logo.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-map/icons-map.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-map/icons-map.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-media/icons-media.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-media/icons-media.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-others/icons-others.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-others/icons-others.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-system/icons-system.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-system/icons-system.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-user/icons-user.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-user/icons-user.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/README.md b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/README.md similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/README.md rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/README.md diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons-weather/icons-weather.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.legacy.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.main.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.main.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.main.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.main.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.min.css b/web/b3desk/static/dsfr-1.7/utility/icons/icons.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.min.css rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/icons/icons.min.css.map b/web/b3desk/static/dsfr-1.7/utility/icons/icons.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/icons/icons.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/icons/icons.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.css b/web/b3desk/static/dsfr-1.7/utility/utility.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.css rename to web/b3desk/static/dsfr-1.7/utility/utility.css diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.css.map b/web/b3desk/static/dsfr-1.7/utility/utility.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.css.map rename to web/b3desk/static/dsfr-1.7/utility/utility.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.legacy.css b/web/b3desk/static/dsfr-1.7/utility/utility.legacy.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.legacy.css rename to web/b3desk/static/dsfr-1.7/utility/utility.legacy.css diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.legacy.css.map b/web/b3desk/static/dsfr-1.7/utility/utility.legacy.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.legacy.css.map rename to web/b3desk/static/dsfr-1.7/utility/utility.legacy.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.legacy.min.css b/web/b3desk/static/dsfr-1.7/utility/utility.legacy.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.legacy.min.css rename to web/b3desk/static/dsfr-1.7/utility/utility.legacy.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.legacy.min.css.map b/web/b3desk/static/dsfr-1.7/utility/utility.legacy.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.legacy.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/utility.legacy.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.main.css b/web/b3desk/static/dsfr-1.7/utility/utility.main.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.main.css rename to web/b3desk/static/dsfr-1.7/utility/utility.main.css diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.main.css.map b/web/b3desk/static/dsfr-1.7/utility/utility.main.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.main.css.map rename to web/b3desk/static/dsfr-1.7/utility/utility.main.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.main.min.css b/web/b3desk/static/dsfr-1.7/utility/utility.main.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.main.min.css rename to web/b3desk/static/dsfr-1.7/utility/utility.main.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.main.min.css.map b/web/b3desk/static/dsfr-1.7/utility/utility.main.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.main.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/utility.main.min.css.map diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.min.css b/web/b3desk/static/dsfr-1.7/utility/utility.min.css similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.min.css rename to web/b3desk/static/dsfr-1.7/utility/utility.min.css diff --git a/web/flaskr/static/dsfr-1.7/utility/utility.min.css.map b/web/b3desk/static/dsfr-1.7/utility/utility.min.css.map similarity index 100% rename from web/flaskr/static/dsfr-1.7/utility/utility.min.css.map rename to web/b3desk/static/dsfr-1.7/utility/utility.min.css.map diff --git a/web/flaskr/static/images/apps.png b/web/b3desk/static/images/apps.png similarity index 100% rename from web/flaskr/static/images/apps.png rename to web/b3desk/static/images/apps.png diff --git a/web/flaskr/static/images/favicon.png b/web/b3desk/static/images/favicon.png similarity index 100% rename from web/flaskr/static/images/favicon.png rename to web/b3desk/static/images/favicon.png diff --git a/web/flaskr/static/images/gouv.png b/web/b3desk/static/images/gouv.png similarity index 100% rename from web/flaskr/static/images/gouv.png rename to web/b3desk/static/images/gouv.png diff --git a/web/flaskr/static/images/home.svg b/web/b3desk/static/images/home.svg similarity index 100% rename from web/flaskr/static/images/home.svg rename to web/b3desk/static/images/home.svg diff --git a/web/flaskr/static/js/dropzone-min.js b/web/b3desk/static/js/dropzone-min.js similarity index 100% rename from web/flaskr/static/js/dropzone-min.js rename to web/b3desk/static/js/dropzone-min.js diff --git a/web/flaskr/static/js/dropzone.css b/web/b3desk/static/js/dropzone.css similarity index 100% rename from web/flaskr/static/js/dropzone.css rename to web/b3desk/static/js/dropzone.css diff --git a/web/flaskr/static/js/filePickerWrapper.js b/web/b3desk/static/js/filePickerWrapper.js similarity index 100% rename from web/flaskr/static/js/filePickerWrapper.js rename to web/b3desk/static/js/filePickerWrapper.js diff --git a/web/flaskr/static/js/filePickerWrapper.js.map b/web/b3desk/static/js/filePickerWrapper.js.map similarity index 100% rename from web/flaskr/static/js/filePickerWrapper.js.map rename to web/b3desk/static/js/filePickerWrapper.js.map diff --git a/web/b3desk/static/js/meeting.js b/web/b3desk/static/js/meeting.js new file mode 100644 index 00000000..45500f5f --- /dev/null +++ b/web/b3desk/static/js/meeting.js @@ -0,0 +1,416 @@ +// ALL FUNCTIONS FOR JS, NO EXECUTION HAPPNING RIGHT THERE, JUMP TO 'STARTJSEXEC' IF YOU WISH TO SEE JSS CODE EXECUTION + +function changeDefaultFile(newId){ + let tbody=document.getElementById('fileslist'); + let actualDefaultFile = tbody.querySelector('[disabled]'); + if (actualDefaultFile) { + actualDefaultFile.checked=false; + actualDefaultFile.disabled=false; + } + let newDefault = document.getElementById('isDefault-'+newId); + newDefault.checked=true; + newDefault.disabled=true; + +} + +function toggleIsDownloadable(e){ + let idFileSelected = e.target.id.split('-')[1]; + let newValue = e.target.checked; + let csrf_token = document.getElementsByName("csrf_token")[0].value; + + fetch(toggle_download_url, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'X-CSRFToken':csrf_token + }, + body: JSON.stringify({'id': idFileSelected, 'value': newValue}) + }) + .then(res => res.json()) + .then(res => { + //printout_message({ type: 'success', title: 'Modification prise en compte' }); + }) +} + +function submitDefaultFile(e){ + let csrf_token = document.getElementsByName("csrf_token")[0].value; + let idFileSelected = e.target.id.split('-').slice(-1); + + fetch(set_default_file_url, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'X-CSRFToken':csrf_token + }, + body: JSON.stringify({'id': idFileSelected}) + }) + .then(res => res.json()) + .then(res => { + changeDefaultFile(res.id); + }) +} + +function remove_file_from_fileslist(id){ + let liToDel = document.getElementById(id); + liToDel.parentNode.removeChild(liToDel); +} + +function deleteFile(e){ + e.preventDefault(); + + let csrf_token = document.getElementsByName("csrf_token")[0].value; + let idFileSelected = e.target[0].value; + fetch(delete_meeting_file_url, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'X-CSRFToken':csrf_token + }, + body: JSON.stringify({'id': idFileSelected}) + }) + .then(res => res.json()) + .then(res => { + close_dialog('delete-file-'+res.id); + remove_file_from_fileslist(res.id); + printout_message({ type: 'success', title: 'Document supprimé', data: res.msg}); + if (res.newDefaultId) { + changeDefaultFile(res.newDefaultId); + } + }) +} + +function add_URL_file(name, from) { + + //on teste que l'URL est pas trop exotique + if (! name.match(/(http(s)?:\/\/.)?([-a-zA-Z0-9@:%._\+~#=]{2,256}\.){1,10}[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g)) { + alert('URL mal formattée elle doit être de la forme ( [] = optionnel ): http[s]://[www.]monsite.fr/[mon-chemin]'); + return ; + } + // si pas de https:// renseigné, on le force en préfixe, si c'est du http, la personne devra corriger d'elle-même + if (!name.match(/^http/)) name = `https://${name}`; + //simple copy as we are fetch in asynchronous mode + var URL_to_fetch = name; + // gestion if name > 50 char, reduce its printing + if (name.length > 80 ) { + var splitted = name.split(['/']); + name = splitted[2] + '/' + splitted[3] + '.../' + splitted.slice(-1).slice(-20); + } + + link_file_to_meeting(name, 'URL'); + +} + +function append_file_to_fileslist(title, id, date, isDefault) { + var nofileavailable = document.getElementById('nofileavailable'); + if (nofileavailable) { + nofileavailable.parentNode.removeChild(nofileavailable); + } + var csrf_token = document.getElementsByName("csrf_token")[0].value; + var tbody = document.getElementById("fileslist"); + + // create TR-TD element + let tr = document.createElement('tr'); + let tdDefault = document.createElement('td'); + let inputDefault = document.createElement('input'); + let labelDefault = document.createElement('label'); + let divDefault = document.createElement('div'); + let tdTitle = document.createElement('td'); + let tdDate = document.createElement('td'); + let tdDel = document.createElement('td'); + let tdDownload = document.createElement('td'); + let tdIsDownloadable = document.createElement('td'); + let divLink = document.createElement('div'); + let divIsDl = document.createElement('div'); + let inputIsDl = document.createElement('input'); + let labelIsDl = document.createElement('label'); + let aLink = document.createElement('a'); + let buttonLink = document.createElement('button'); + let deleteButton = document.createElement('button'); + + tr.setAttribute('id', id); + deleteButton.setAttribute('data-fr-opened', 'false'); + deleteButton.setAttribute('title', 'Supprimer'); + deleteButton.classList.add('fr-btn','fr-fi-delete-line'); + + buttonLink.classList.add('fr-btn','fr-icon-download-fill'); + buttonLink.setAttribute('title', 'Télécharger'); + aLink.setAttribute('href', download_meeting_file_url + id); + aLink.appendChild(buttonLink); + tdDownload.appendChild(aLink); + inputIsDl.classList.add('fr-toggle__input'); + inputIsDl.setAttribute('id', 'toggle-'+id); + inputIsDl.setAttribute('type', 'checkbox'); + inputIsDl.addEventListener('click', toggleIsDownloadable); + labelIsDl.classList.add('fr-toggle__label'); + labelIsDl.setAttribute('for', 'toggle-'+id); + labelIsDl.setAttribute('data-fr-checked-label', 'Oui'); + labelIsDl.setAttribute('data-fr-unchecked-label', 'Non'); + + divIsDl.classList.add('fr-toggle'); + divIsDl.appendChild(inputIsDl); + divIsDl.appendChild(labelIsDl); + tdIsDownloadable.appendChild(divIsDl); + tdTitle.innerHTML=title; + tdDate.innerHTML=date; + + inputDefault.classList.add('fr-toggle__input'); + inputDefault.setAttribute('id', 'isDefault-'+id); + inputDefault.setAttribute('type', 'checkbox'); + inputDefault.addEventListener('click', submitDefaultFile); + if (isDefault) { + inputDefault.setAttribute('checked', true); + inputDefault.disabled=true; + } + labelDefault.classList.add('fr-toggle__label'); + labelDefault.setAttribute('data-fr-checked-label', 'Oui'); + labelDefault.setAttribute('data-fr-unchecked-label', 'Non'); + labelDefault.setAttribute('for', 'isDefault-'+id); + divDefault.classList.add('fr-toggle'); + divDefault.appendChild(inputDefault); + divDefault.appendChild(labelDefault); + tdDefault.appendChild(divDefault); + + + tr.appendChild(tdDefault); + tr.appendChild(tdIsDownloadable); + tr.appendChild(tdTitle); + tr.appendChild(tdDate); + tr.appendChild(tdDel); + tr.appendChild(tdDownload); + + // create delete element - modal + let dialog = document.createElement('dialog'); + let div1 = document.createElement('div'); + let div2 = document.createElement('div'); + let div3 = document.createElement('div'); + let div4 = document.createElement('div'); + let div5a = document.createElement('div'); + let div5b = document.createElement('div'); + let button = document.createElement('button'); + let button2 = document.createElement('button'); + let button3 = document.createElement('button'); + let form = document.createElement('form'); + let input = document.createElement('input'); + let p = document.createElement('p'); + + let modalId = 'delete-file-'+id + + deleteButton.setAttribute('aria-controls', modalId); + + dialog.setAttribute('id', modalId); + dialog.classList.add('fr-modal'); + div1.classList.add('fr-container','fr-container--fluid','fr-container-md'); + div2.classList.add('fr-grid-row','fr-grid-row--center'); + div3.classList.add('fr-col-12','fr-col-md','fr-col-lg-6'); + div4.classList.add('fr-modal__body'); + div5a.classList.add('fr-modal__header'); + div5b.classList.add('fr-modal__content'); + button.classList.add('fr-btn--close','fr-btn'); + button.setAttribute('title', 'Fermer'); + button.setAttribute('aria-controls', modalId); + + button2.setAttribute('type', 'submit'); + button2.classList.add('fr-btn','fr-btn--primary'); + button2.innerHTML = 'Supprimer'; + button3.setAttribute('type', 'reset'); + button3.setAttribute('aria-controls', modalId); + button3.classList.add('fr-btn','fr-btn--secondary'); + button3.innerHTML = 'Annuler'; + input.classList.add('fr-input'); + input.setAttribute('type', 'hidden'); + input.setAttribute('name', 'id'); + input.setAttribute('value', id); + form.setAttribute('action', delete_meeting_file_url); + form.setAttribute('method', 'POST'); + form.setAttribute('onsubmit', 'deleteFile(event)'); + + + form.appendChild(input); + form.appendChild(button2); + form.appendChild(button3); + + div5a.appendChild(button); + p.innerHTML = 'Voulez-vous vraiment supprimer le fichier '+title+' ?'; + div5b.appendChild(p); + div5b.appendChild(form); + div4.appendChild(div5a); + div4.appendChild(div5b); + div3.appendChild(div4); + div2.appendChild(div3); + div1.appendChild(div2); + dialog.appendChild(div1); + + tdDel.appendChild(deleteButton); + tbody.appendChild(dialog); + tbody.appendChild(tr); +} + +// + // msg should be formatted : +// { + // type : success/fail + // title : + // data : + // } +// +function printout_message(msg){ + let div=document.createElement('div'); + let h3=document.createElement('h3'); + let p=document.createElement('p'); + div.classList.add('fr-alert','fr-alert--'+msg.type); + h3.classList.add('fr-alert__title'); + h3.innerHTML=msg.title; + p.innerHTML=msg.data; + + div.appendChild(h3); + div.appendChild(p); + + nodeToPrepend = document.getElementById('layoutContainer'); + parentNodeToPrepend = nodeToPrepend.parentNode; + parentNodeToPrepend.insertBefore(div, nodeToPrepend); + window.scrollTo(0, 0); + setTimeout(() => { + parentNodeToPrepend.removeChild(div); + }, 3000) +} + +function close_dialog(id){ + let dialogToClose = document.getElementById(id); + dsfr(dialogToClose).modal.conceal(); +} + +// post data as : +// [ + // { 'from' : 'URL', 'value': 'https://lol.com/image.jpg' }, + // { 'from' : 'dropzone', 'value': 'tancarville.jpeg' }, + // ] + +function link_file_to_meeting(value, from) { + var csrf_token = document.getElementsByName("csrf_token")[0].value + var post_data = { + 'value': value, + 'from': from, + }; + JSON.stringify(post_data); + fetch(add_meeting_files_url, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'X-CSRFToken':csrf_token + }, + body: JSON.stringify(post_data) + }) + .then(res => { + if (res.status == 200) { + return (res.json()) + } else { + throw res + } + + }) + .then(data => { + if (data.status == 200) { + append_file_to_fileslist(data.title, data.id, data.created_at, data.isDefault); + printout_message({ type: 'success', title: 'Document ajouté', data: 'Le document '+data.title+' a bien été ajouté'}); + if (data.isfrom !== 'nextcloud') { + close_dialog(data.isfrom); + } + } else { + throw data + } + }) + .catch(data => { + console.log(data) + printout_message({ type: 'error', title: 'Erreur Document', data: data.msg}); + if (data.isfrom !== 'nextcloud') { + close_dialog(data.isfrom); + } + }) +} + +function openNCFilePicker(e) { + ncfilepicker.getFilesPath(); +} + + +function createNCFilePicker() { + let ncPickerParams = { + url: nc_locator, + login: nc_login, + accessToken: nc_token, + enableGetFilesPath: true, + }; + + ncfilepicker = window.createFilePicker('ncfilepicker', ncPickerParams); + document.addEventListener('get-files-path', (e) => { + // { selection: [ 'lol.jpg', 'megalol.jpg' ] } + e.detail.selection.map( (name, index) => { + setTimeout(() => {link_file_to_meeting(name.slice(1), 'nextcloud')}, index * 500); + }) + + }) +} + +// END OF JS FUNCTION DECLARATION +// HERE IS STARTJSEXEC + +let ncfilepicker = null; + +document.addEventListener('DOMContentLoaded', () => { + + if (!nc_locator || !nc_login || !nc_token) { + printout_message({ type: 'error', title: 'Nextcloud connexion', data: "La connexion avec votre Nextcloud n'est pas fonctionnelle, les options associées sont désactivées"}); + } + + Dropzone.autoDiscover = false; + var dropzone_conf = { + paramName: 'dropzoneFiles', + //autoProcessQueue: false, + //uploadMultiple: true, + //chunking: false, + //forceChunking: false, + chunking: true, + forceChunking: true, + maxFilesize: 20, // megabytes + acceptedFiles: accepted_files, + dictRemoveFile: 'Supprimer', + dictDefaultMessage: 'Cliquer ou glisser-déposer les fichiers à ajouter', + addRemoveLinks: true, + parallelUploads: 10, + chunkSize: 1000000, // bytes + init: function() { + this.on("removedfile", file => { + console.log('removed file from dropzone'); + }); + this.on('success', file => { + setTimeout(() => {link_file_to_meeting(file.name, 'dropzone')}, this.getUploadingFiles().length * 1000); + setTimeout(() => {this.removeFile(file)}, 1000); + }); + this.on('error', (file, message) => { + close_dialog('dropzone'); + printout_message({ type: 'error', title: 'Le téléversement du fichier « '+file.name+' » a échoué.', data: message}); + this.removeFile(file); + }); + } + } + var dropper = new Dropzone("form#dropper", dropzone_conf); + + var form_files = document.getElementById('meeting-form'); + + form_files.addEventListener('submit', (e) => { + e.preventDefault(); + + var formData = new FormData(form_files); + + var name = `${formData.get('url')}`; + var from = `depuis URL`; + + add_URL_file(name, from); + }); + + createNCFilePicker() +}) diff --git a/web/flaskr/static/js/scampi-modal.js b/web/b3desk/static/js/scampi-modal.js similarity index 100% rename from web/flaskr/static/js/scampi-modal.js rename to web/b3desk/static/js/scampi-modal.js diff --git a/web/flaskr/static/local/stats.csv b/web/b3desk/static/local/stats.csv similarity index 100% rename from web/flaskr/static/local/stats.csv rename to web/b3desk/static/local/stats.csv diff --git a/web/flaskr/static/misc/ip-fqdn-adm-sort.txt b/web/b3desk/static/misc/ip-fqdn-adm-sort.txt similarity index 100% rename from web/flaskr/static/misc/ip-fqdn-adm-sort.txt rename to web/b3desk/static/misc/ip-fqdn-adm-sort.txt diff --git a/web/flaskr/static/misc/ip-fqdn-complet.txt b/web/b3desk/static/misc/ip-fqdn-complet.txt similarity index 100% rename from web/flaskr/static/misc/ip-fqdn-complet.txt rename to web/b3desk/static/misc/ip-fqdn-complet.txt diff --git a/web/flaskr/static/misc/ip-fqdn-dinum.txt b/web/b3desk/static/misc/ip-fqdn-dinum.txt similarity index 100% rename from web/flaskr/static/misc/ip-fqdn-dinum.txt rename to web/b3desk/static/misc/ip-fqdn-dinum.txt diff --git a/web/flaskr/static/presentation/css/all.css b/web/b3desk/static/presentation/css/all.css similarity index 100% rename from web/flaskr/static/presentation/css/all.css rename to web/b3desk/static/presentation/css/all.css diff --git a/web/b3desk/static/presentation/js/all.js b/web/b3desk/static/presentation/js/all.js new file mode 100644 index 00000000..e69de29b diff --git a/web/flaskr/tasks.py b/web/b3desk/tasks.py similarity index 88% rename from web/flaskr/tasks.py rename to web/b3desk/tasks.py index 5cbd63c7..d454d78f 100644 --- a/web/flaskr/tasks.py +++ b/web/b3desk/tasks.py @@ -14,12 +14,11 @@ @celery.task(name="background_upload") -def background_upload(endpoint, xml, params): +def background_upload(endpoint, xml): requests.post( endpoint, headers={"Content-Type": "application/xml"}, data=xml, - params=params, ) logger.info(f"adding background files endpoint:{endpoint} xml:{xml}") return True diff --git a/web/b3desk/templates/brand.html b/web/b3desk/templates/brand.html new file mode 100644 index 00000000..e2ee21bc --- /dev/null +++ b/web/b3desk/templates/brand.html @@ -0,0 +1,28 @@ + diff --git a/web/flaskr/templates/content.py b/web/b3desk/templates/content.py similarity index 84% rename from web/flaskr/templates/content.py rename to web/b3desk/templates/content.py index 5fca16d5..1cfd1648 100644 --- a/web/flaskr/templates/content.py +++ b/web/b3desk/templates/content.py @@ -1,12 +1,11 @@ -from flask_babel import lazy_gettext - +from flask_babel import lazy_gettext as _ FAQ_CONTENT = [ { - "title": lazy_gettext( + "title": _( """Quelles sont les conditions d’accès pour accéder aux services ?""" ), - "description": lazy_gettext( + "description": _( """Cette plateforme offre une solution complète et puissante, adaptée à de nombreux types d’événements en ligne, jusqu’à 350 participants (Séminaire, formation, table ronde, ateliers collaboratifs…) Pour qui ? @@ -30,8 +29,8 @@ ), }, { - "title": lazy_gettext("""Quel est le matériel nécessaire ?"""), - "description": lazy_gettext( + "title": _("""Quel est le matériel nécessaire ?"""), + "description": _( """Pour utiliser l’outil Webinaire de l’État, il vous suffit de disposer du matériel suivant : • un ordinateur connecté à Internet @@ -43,17 +42,17 @@ ), }, { - "title": lazy_gettext( + "title": _( """Puis-je utiliser mon smartphone ou ma tablette pour me connecter ?""" ), - "description": lazy_gettext( + "description": _( """Le Webinaire de l’Etat fonctionne également sur les appareils mobiles par un simple lien (sans application) sur le portail ou dans le séminaire. Sur les iphone et ipad (IOS 12.2+) le navigateur Safari est recommandé. Sur Android, utiliser le navigateur chrome par défaut (Android 6.0+). """ ), }, { - "title": lazy_gettext("""Comment créer un séminaire ?"""), - "description": lazy_gettext( + "title": _("""Comment créer un séminaire ?"""), + "description": _( """Si vous êtes un agent de l’état, vous pouvez : - Créer des séminaires immédiatement en renseignant votre courriel professionnel sur .gouv.fr et suivant les noms de domaines autorisés. - Créer un compte pour créer et configurer des séminaires que vous pourrez retrouver facilement dans votre espace ainsi que les liens de connexions, les replays des enregistrements… @@ -64,24 +63,24 @@ ), }, { - "title": lazy_gettext("""Comment créer un compte ?"""), - "description": lazy_gettext( + "title": _("""Comment créer un compte ?"""), + "description": _( """En tant qu’agent de l’État, si vous organisez régulièrement des séminaires vous pouvez créer un compte pour organiser et conserver facilement vos séminaires sur mesure. Vous avez la possibilité créer une ou plusieurs salles de séminaire et les configurer suivant le type de dispositifs adaptés (ex : Séminaire, Formation, classe virtuelle, Conférence interactive, Plénière, Table ronde, Assemblée générale, Ateliers collaboratifs ou d’idéation, Comités en grand nombre, …etc.).""" ), }, { - "title": lazy_gettext("""Comment inviter les participants/ modérateurs"""), - "description": lazy_gettext( + "title": _("""Comment inviter les participants/ modérateurs"""), + "description": _( """L’organisateur qui a créé le séminaire peut partager le lien : « Participants » qu’ils soient de l’administration ou de l’extérieur (partenaires, prestataires, entreprises, citoyens…) « Organisateurs/modérateurs » qui géreront avec vous le séminaire.""" ), }, { - "title": lazy_gettext("""Rejoindre un Webinaire en appel téléphonique ?"""), - "description": lazy_gettext( + "title": _("""Rejoindre un Webinaire en appel téléphonique ?"""), + "description": _( """Une fois dans le séminaire, il est possible d’utiliser aussi son téléphone fixe ou mobile pour suivre le séminaire. Les informations sont visibles dans le séminaire sur discussion publique. Vous pouvez transmettre ses informations composées du numéro d’appel et du code du séminaire : @@ -92,8 +91,8 @@ ), }, { - "title": lazy_gettext("""J'ai des perturbations audio ou vidéo ?"""), - "description": lazy_gettext( + "title": _("""J'ai des perturbations audio ou vidéo ?"""), + "description": _( """ Pour l’audio, rapprochez-vous de votre borne wifi, ou/et coupez votre caméra Nous vous invitons à utiliser un casque pour une meilleure écoute et pour que les bruits de fond autour de vous ne perturbent pas les autres participants. @@ -107,16 +106,14 @@ ), }, { - "title": lazy_gettext( - """Besoin de contacter l'équipe du Webinaire de l’Etat ?""" - ), - "description": lazy_gettext("""contact@webinaire.numerique.gouv.fr"""), + "title": _("""Besoin de contacter l'équipe du Webinaire de l’Etat ?"""), + "description": _("""contact@webinaire.numerique.gouv.fr"""), }, { - "title": lazy_gettext( + "title": _( """Besoin de contacter l'équipe du ministére de l'Éducation nationale ?""" ), - "description": lazy_gettext( + "description": _( """Rendez-vous sur votre portail d'assistance académique https://www.education.gouv.fr/la-messagerie-professionnelle-3446 ou sur Apps.education.fr""" ), }, diff --git a/web/b3desk/templates/empty.html b/web/b3desk/templates/empty.html new file mode 100644 index 00000000..0f64af5e --- /dev/null +++ b/web/b3desk/templates/empty.html @@ -0,0 +1,3 @@ +

+{% trans %}Vous devez vous identifier pour consulter la liste des visioconférences.{% endtrans %} +

diff --git a/web/b3desk/templates/errors/400.html b/web/b3desk/templates/errors/400.html new file mode 100644 index 00000000..c2c79456 --- /dev/null +++ b/web/b3desk/templates/errors/400.html @@ -0,0 +1,18 @@ +{% extends 'layout.html' %} + +{% block main %} +
+
+
+

{% trans %}Erreur 400{% endtrans %}

+

+ {% if error %} + {{ error }} + {% else %} + {% trans index_url=url_for("public.index") %}La requête que vous avez effectué est invalide. Vous pouvez retourner à l’accueil.{% endtrans %} + {% endif %} +

+
+
+
+{% endblock %} diff --git a/web/b3desk/templates/errors/403.html b/web/b3desk/templates/errors/403.html new file mode 100644 index 00000000..dc6ba8b3 --- /dev/null +++ b/web/b3desk/templates/errors/403.html @@ -0,0 +1,12 @@ +{% extends 'layout.html' %} + +{% block main %} +
+
+
+

{% trans %}Erreur 403{% endtrans %}

+

{% trans index_url=url_for("public.index") %}Vous n’êtes pas autorisé à accéder cette page. Vous pouvez retourner à l’accueil.{% endtrans %}

+
+
+
+{% endblock %} diff --git a/web/b3desk/templates/errors/404.html b/web/b3desk/templates/errors/404.html new file mode 100644 index 00000000..15f2745b --- /dev/null +++ b/web/b3desk/templates/errors/404.html @@ -0,0 +1,12 @@ +{% extends 'layout.html' %} + +{% block main %} +
+
+
+

{% trans %}Erreur 404{% endtrans %}

+

{% trans index_url=url_for("public.index") %}Cette page n'existe pas. Vous pouvez retourner à l’accueil.{% endtrans %}

+
+
+
+{% endblock %} diff --git a/web/b3desk/templates/errors/500.html b/web/b3desk/templates/errors/500.html new file mode 100644 index 00000000..94048d13 --- /dev/null +++ b/web/b3desk/templates/errors/500.html @@ -0,0 +1,12 @@ +{% extends 'layout.html' %} + +{% block main %} +
+
+
+

{% trans %}Erreur 500{% endtrans %}

+

{% trans %}Le serveur a rencontré une erreur interne, veuillez réessayer ultérieurement.{% endtrans %}

+
+
+
+{% endblock %} diff --git a/web/b3desk/templates/faq.html b/web/b3desk/templates/faq.html new file mode 100644 index 00000000..5f700208 --- /dev/null +++ b/web/b3desk/templates/faq.html @@ -0,0 +1,23 @@ +{% extends 'static-layout.html' %} + +{% block main %} +

{% trans %}FAQ - Modalités d'accès{% endtrans %}

+
    + {% for content in contents %} +
    +

    + +

    +
    +
    +
    + {{content["description"]}} +
    +
    +
    +
    + {% endfor %} +
+{% endblock %} diff --git a/web/b3desk/templates/footer.html b/web/b3desk/templates/footer.html new file mode 100644 index 00000000..f4792873 --- /dev/null +++ b/web/b3desk/templates/footer.html @@ -0,0 +1,70 @@ + diff --git a/web/b3desk/templates/footer/accessibilite.html b/web/b3desk/templates/footer/accessibilite.html new file mode 100644 index 00000000..6dfaed22 --- /dev/null +++ b/web/b3desk/templates/footer/accessibilite.html @@ -0,0 +1,18 @@ +{% extends 'static-layout.html' %} + +{% block main %} +
+

{% trans %}Accessibilité{% endtrans %}

+

{% trans %}Le site webinaire.numerique.gouv.fr est développé selon les recommendations du référentiel général d’amélioration d’accessibilité pour être accessible à tous les usagers quel que soit le matériel ou le logiciel utilisé pour naviguer sur internet.{% endtrans %}

+

{% trans %}Cependant, aucun audit formel n’a été effectué.{% endtrans %}

+ +

{% trans %}Droit à compensation{% endtrans %}

+

{% trans %}Dans l’attente d’une mise en conformité totale, vous pouvez obtenir une version accessible des documents ou des informations qui y seraient contenues en envoyant un courriel à contact@webinaire.numerique.gouv.fr en indiquant le nom du document concerné et/ou les informations que vous souhaiteriez obtenir. Les informations demandées vous seront transmises dans les plus bref délais.{% endtrans %}

+ +

{% trans %}Amélioration et contact{% endtrans %}

+

{% trans %}Vous pouvez nous aider à améliorer l’accessibilité du site en nous signalant les problèmes éventuels que vous rencontrez. Pour ce faire, envoyez-nous un courriel à contact@webinaire.numerique.gouv.fr .{% endtrans %}

+ +

{% trans %}Défenseur des droits{% endtrans %}

+

{% trans %}Si vous constatez un défaut d'accessibilité vous empêchant d'accéder à un contenu ou une fonctionnalité du site, que vous nous le signalez et que vous ne parvenez pas à obtenir une réponse rapide de notre part, vous êtes en droit de faire parvenir vos doléances ou une demande de saisine au Défenseur des droits. Plusieurs moyens sont à votre disposition :{% endtrans %}

+ + {% endblock %} diff --git a/web/flaskr/templates/footer/cgu.html b/web/b3desk/templates/footer/cgu.html similarity index 99% rename from web/flaskr/templates/footer/cgu.html rename to web/b3desk/templates/footer/cgu.html index 1e962759..fa96566d 100644 --- a/web/flaskr/templates/footer/cgu.html +++ b/web/b3desk/templates/footer/cgu.html @@ -1,7 +1,7 @@ {% extends 'static-layout.html' %} {% block main %} -
+

{% trans %}Conditions générales d’utilisation{% endtrans %}

{% trans %}Le webinaire, Visio-ecoles/colleges/lycees/agents de l’État permet d’accéder à la page d’accueil du sous-domaine internet utilisé par l’Etat pour publier sur internet sa solution de webconférence interministérielle. Cette mesure facilite l’accès à cette solution pour tous les agents de l’Etat tout en permettant également de coopérer avec les partenaires du service public.{% endtrans %}

{% trans %}Le sous-domaine « https://webinaire.numerique.gouv.fr » est piloté par la Direction interministérielle du numérique (DINUM){% endtrans %}

@@ -27,5 +27,5 @@

{% trans %}Évolution des conditions d’utilisation{% endtrans %}

{% trans %}Loi n° 2004-575 du 21 juin 2004 pour la confiance dans l’économie numérique{% endtrans %}

{% trans %}Ordonnance 2005-1516 du 8 décembre 2005 relative aux échanges électroniques entre les usagers et les autorités administratives et entre les autorités administratives et notamment ses articles 9 à 12.{% endtrans %}

{% trans %}Loi n° 2016-1321 du 7 octobre 2016 pour une République numérique{% endtrans %}

-
+
{% endblock %} diff --git a/web/b3desk/templates/footer/documentation.html b/web/b3desk/templates/footer/documentation.html new file mode 100644 index 00000000..2b673221 --- /dev/null +++ b/web/b3desk/templates/footer/documentation.html @@ -0,0 +1,107 @@ +{% extends 'static-layout.html' %} + +{% block main %} +

{% trans %}Documentation{% endtrans %}

+

{% trans %}Guides utilisateurs{% endtrans %}

+{% if documentation_page_subtitle %} +

{{ documentation_page_subtitle }}

+{% endif %} +
  • {% trans %}Présentation des nouveautés de la v2.4{% endtrans %}
  • +
    + +
    +
  • {% trans %}Créer {{ an_improvised_meeting }}{% endtrans %}
  • +
  • {% trans %}Participer à {{ a_meeting }}{% endtrans %}
  • +
  • {% trans %}Créer et paramétrer une salle de {{ meeting_label }}{% endtrans %}
  • +
  • {% trans %}Activer le matériel dans le navigateur{% endtrans %}
  • +
  • {% trans %}Gérer les utilisateurs{% endtrans %}
  • +
  • {% trans %}Gérer les documents{% endtrans %}
  • +
  • {% trans %}Gestion des {{ private_meetings }}{% endtrans %}
  • +
  • {% trans %}Déléguer la création de {{ meeting_label }}{% endtrans %}
  • +
  • {% trans %}Enregistrer {{ a_meeting }}{% endtrans %}
  • +
  • {% trans %}Créer un sondage{% endtrans %}
  • +
  • {% trans %}Joindre {{ a_meeting }} par téléphone{% endtrans %}
  • +
  • {% trans %}Afficher le tableau de bord{% endtrans %}
  • +
  • {% trans %}Gérer la mise en page{% endtrans %}
  • +
  • {% trans %}Contrôle du volume{% endtrans %}
  • +
    + + + + + + + + + + + + + + + + + +
    1 caméra5 caméras10 caméras20 caméras30 caméras
    350 personnes250 personnes150 personnes100 personnesmaximum 50 personnes
    +

    Documentation technique

    + +

    L'ensemble de ces services requiére d'ouverture de ports UDP notamment dans les pare-feux

    + + +

    Le service BigBlueButton est composé de 3 types de services : +

      +
    • le service BigBlueButton
    • +
    • le service TURN/STUN qui permet, en méthode de contournement, lorsque les ports UDP sont bloqués d'encapsuler le flux UDP dans un flux 443/TCP/DTLS embarqué par les serveurs de web-visio BigBlueButton
    • +
    • le service Scalelite sur des serveurs dédiés qui servent à répartir les salles sur l'ensemble des serveurs BBB
    • +
    +

    + +

    +Ces ports sont : +

      +
    • Serveurs BBB/scalelite +
        +
      • TCP/IP ports 80/443 (HTTP/HTTPS)
      • +
      • UDP la plage de ports 16384 - 32768
      • +
      • TCP/IP ports 443 service TURN (TCP/DTLS) dont il faut positionner en exclusion du proxy les FQDN/IP
      • +
      +
    • +
    +

    +
    + +

    Serveurs TURN

    +
  • TCP/IP ports 443 service TURN (TCP/DTLS) dont il faut positionner en exclusion du proxy les FQDN/IP
  • +
  • Instance Éducation, depuis la version 2.6 de BigBlueButton le service TURN est embarqué directement dans chaque serveur BigBlueButton et non plus une grappe de serveurs TURN dédiés.
  • +
  • Instance Webinaire de l'État, il y une grappe de serveurs TURN dédiés.
  • + + + + + + + + + + + + + +
    IPFQDNDomaine
    212.47.226.44bbb-dinum-turn1.visio.education.frWebinaire de l'état
    212.47.243.166bbb-dinum-turn2.visio.education.frWebinaire de l'état
    212.47.231.140bbb-dinum-turn3.visio.education.frWebinaire de l'état
    212.47.243.234bbb-dinum-turn4.visio.education.frWebinaire de l'état
    212.47.231.160bbb-dinum-turn5.visio.education.frWebinaire de l'état
    + + +

    Fichiers avec les IP et FQDN des serveurs BBB

    + + +{% endblock %} diff --git a/web/b3desk/templates/footer/donnees_personnelles.html b/web/b3desk/templates/footer/donnees_personnelles.html new file mode 100644 index 00000000..df135e1f --- /dev/null +++ b/web/b3desk/templates/footer/donnees_personnelles.html @@ -0,0 +1,100 @@ +{% extends 'static-layout.html' %} + +{% block main %} +
    +

    {% trans %}Données personnelles{% endtrans %}

    + +

    {% trans %}Gestion des cookies{% endtrans %}

    +

    {% trans %}À propos des cookies / traceurs{% endtrans %}

    +

    {% trans %}Afin de permettre aux applications Web de fournir des services, des « cookies » (« traceurs » en français) peuvent être utilisés.{% endtrans %}

    + +

    {% trans %}Qu’est-ce qu’un « cookie » ?{% endtrans %}

    +

    {% trans %}Un « cookie » est un fichier de taille limitée, généralement constitué de lettres et de chiffres, envoyé par le serveur internet au fichier cookie du navigateur situé sur le disque dur de votre ordinateur.{% endtrans %}

    + +

    {% trans %}Quels types de « cookies » sont utilisés par la le Webinaire de de l’Etat ?{% endtrans %}

    +

    {% trans %}Les cookies servent à l’authentification sur le site Webinaire/Visio-ecoles/colleges/lycees/agents{% endtrans %}

    +

    {% trans %}Il n’y a pas de cookie de mesure d’audience{% endtrans %}

    +

    {% trans %}Informations complémentaires sur les « cookies »{% endtrans %}

    +

    http://www.cnil.fr/vos-droits/vos-traces/les-cookies/

    + +

    {% trans %}Quelle sécurité pour vos données personnelles ?{% endtrans %}

    +

    {% trans %}Nous veillons à prendre les mesures physiques, techniques et organisationnelles appropriées pour garantir la sécurité et la confidentialité de vos données personnelles.{% endtrans %}

    + +

    {% trans %}Politique de confidentialité{% endtrans %}

    +

    {% trans %}Dans le cadre de l’utilisation du Webinaire, des données à caractère personnel vous concernant font l’objet d’un traitement par la DINUM (Direction Interministérielle du Numérique, ci-après « Nous »).{% endtrans %}

    +

    {% trans %}La présente politique décrit nos engagements en ce qui concerne le traitement de vos données, conformément au Règlement européen sur la protection des données (Règlement UE n° 2026/679 du 27 avril 2016, ci-après « RGPD ») et à la loi n° 78-17 du 6 janvier 1978 modifiée relative à l’informatique, aux fichiers et aux libertés (ci-après loi « Informatique et Libertés »).{% endtrans %}

    + +

    {% trans %}Quel est notre rôle ?{% endtrans %}

    +

    {% trans %}Le Webinaire est un service en ligne proposé aux agents de l’Etat destiné à faciliter le travail à distance par l’organisation et la tenue de réunions, de conférences et de formations en ligne.{% endtrans %}

    +

    {% trans %}La DINUM est responsable de traitement des informations traitées dans le cadre du Service et, à ce titre, s’engage à respecter les obligations inhérentes à ce traitement, notamment celles relevant de la loi n° 78-17 du 6 janvier 1978 relative à l’informatique aux fichiers et aux libertés.{% endtrans %}

    +

    {% trans %}Les organisateurs qui procèdent aux invitations et à l’enregistrement des webinaires sont responsables des traitements ultérieurs qu’ils réalisent à partir de ces enregistrements. Il leur appartient de vous délivrer une information sur ces traitements.{% endtrans %}

    + +

    {% trans %}Quels sont les traitements de données mis en œuvre ?{% endtrans %}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {% trans %}Finalité du traitement{% endtrans %}{% trans %}Base légale du traitement{% endtrans %}{% trans %}Catégorie de données personnelles traitées{% endtrans %}{% trans %}Durée de conservation{% endtrans %}
    {% trans %}Gestion des comptes des organisateurs de webinaires{% endtrans %}{% trans %}Article 6-1(e) RGPD : exécution d’une mission de service public{% endtrans %}{% trans %}Données d’identification :{% endtrans %} + • {% trans %}Nom{% endtrans %} + • {% trans %}Prénom{% endtrans %} + • {% trans %}Adresse électronique{% endtrans %}{% trans %}Les données sont supprimées après une période de 12 mois d’inactivité du compte ou au moment de la désactivation du compte (1ère moe planifiée au plus tard en 12/22).{% endtrans %}
    {% trans %}Enregistrement des webinaires à des fins de partage et de rediffusion{% endtrans %}{% trans %}Article 6-1(e) RGPD : exécution d’une mission de service public{% endtrans %}{% trans %}Enregistrement vidéo des webinaires{% endtrans %}{% trans %}Les données d’enregistrement peuvent être supprimées à tout moment par l’organisateur. Elles sont automatiquement supprimées 12 mois après la date du webinaire (1ère moe planifiée au plus tard en 12/22).{% endtrans %}
    {% trans %}Outils de chat et de vote en ligne{% endtrans %}{% trans %}Article 6-1(e) RGPD : exécution d’une mission de service public{% endtrans %}{% trans %}Échanges écrits entre participants et résultats des votes en lignes{% endtrans %}{% trans %}Les données sont supprimées à l’issue de la session du webinaire.{% endtrans %}
    {% trans %}Gestion de la sécurité du Webinaire{% endtrans %}{% trans %}(Loi n° 2004-575 du 25 juin 2005 pour la confiance dans l’économie numérique, Décret n° 2021-1362 du 20 octobre 2021 relatif à la conservation des données permettant d’identifier toute personne ayant contribué à la création d’un contenu en ligne){% endtrans %}{% trans %}Données de connexion des utilisateurs du service (logs, adresse IP){% endtrans %}{% trans %}12 mois{% endtrans %}
    + +

    {% trans %}Quels sont les destinataires de vos données ?{% endtrans %}

    +

    {% trans %}Les destinataires de vos données personnelles sont les agents et salariées dûment habilitées de la DINUM et de nos sous-traitants qui interviennent pour l’hébergement, et l’infogérance du service.{% endtrans %}

    +

    {% trans %}Nous nous sommes assurés de la mise en œuvre par nos sous-traitants de garanties adéquates et du respect de conditions strictes de confidentialité, d’usage et de protection des données.{% endtrans %}

    +

    {% trans %}Les données collectées sur le Webinaire ne sont pas transférées en dehors de l’Union européenne.{% endtrans %}

    +

    {% trans %}Quels sont vos droits ?{% endtrans %}

    +

    {% trans %}Vous disposez d’un droit d’accès et de rectification des données à caractère personnel qui vous concernent. Vous disposez également d’un droit d’opposition et de limitation du traitement de vos données.{% endtrans %}

    +

    {% trans %}Pour exercer vos droits ou pour toute question sur le traitement de vos données, vous pouvez nous écrire à l’adresse : contact@webinaire.numerique.gouv.fr.{% endtrans %}

    +

    {% trans %}Vous pouvez également contacter le délégué à la protection des données (DPD) des services du Premier Ministre :{% endtrans %}

    + • {% trans %}par mail à dpd@pm.gouv.fr{% endtrans %}
    + • {% trans %}ou par courrier à l’adresse suivante :{% endtrans %}
    +

    {% trans %}Services du Premier Ministre{% endtrans %}

    + {% trans %}À l’attention du délégué à la protection des données (DPD)
    + 56 rue de Varenne
    + 75007 Paris{% endtrans %}
    +

    {% trans %}Si vous estimez, après nous avoir contactés, que vos droits Informatiques et Libertés ne sont pas respectés vous pouvez adresser une réclamation à la CNIL :{% endtrans %}

    + {% trans %}Commission nationale informatique et libertés
    + 3 place de Fontenoy – TSA 80715 –
    + 75334 PARIS CEDEX 07{% endtrans %}
    + +

    {% trans %}Les modalités de réclamation sont précisées sur le site de la CNIL : www.cnil.fr.{% endtrans %}

    + +

    {% trans %}Contactez le Délégué à la protection des données pour les services Écoles/Colléges/Lycées/Agents{% endtrans %}

    +

    {% trans %}Pour ce faire, envoyez un courriel à dpd[chez]education.gouv.fr{% endtrans %}

    +
    +{% endblock %} diff --git a/web/flaskr/templates/footer/mentions_legales.html b/web/b3desk/templates/footer/mentions_legales.html similarity index 99% rename from web/flaskr/templates/footer/mentions_legales.html rename to web/b3desk/templates/footer/mentions_legales.html index bf019ac6..1a92098d 100644 --- a/web/flaskr/templates/footer/mentions_legales.html +++ b/web/b3desk/templates/footer/mentions_legales.html @@ -1,7 +1,7 @@ {% extends 'static-layout.html' %} {% block main %} -
    +

    {% trans %}Mentions légales{% endtrans %}

    {% trans %}Éditeur{% endtrans %}

    {% trans %}Ministère de l’Éducation nationale et de la jeunesse Direction du numérique pour l’éducation 110 rue Grenelle, 75007 Paris{% endtrans %}
    {% trans %}Directeur de publication{% endtrans %}

    diff --git a/web/flaskr/templates/header.html b/web/b3desk/templates/header.html similarity index 100% rename from web/flaskr/templates/header.html rename to web/b3desk/templates/header.html diff --git a/web/flaskr/templates/index.html b/web/b3desk/templates/index.html similarity index 65% rename from web/flaskr/templates/index.html rename to web/b3desk/templates/index.html index 3930f6bd..d065cc2e 100644 --- a/web/flaskr/templates/index.html +++ b/web/b3desk/templates/index.html @@ -1,5 +1,5 @@ {% extends 'layout.html' %} {% block jumbotron %} - {% include 'jumbotron.html' %} +{% include 'jumbotron.html' %} {% endblock %} diff --git a/web/b3desk/templates/jumbotron.html b/web/b3desk/templates/jumbotron.html new file mode 100644 index 00000000..cab9eb59 --- /dev/null +++ b/web/b3desk/templates/jumbotron.html @@ -0,0 +1,107 @@ +{% include 'rie.html' %} +{% if user %} +
    +
    + {% if stats is defined and stats %} +
    +
    +

    + + {% trans trimmed count=stats["runningCount"]%} + Actuellement, il y a {{ count }} webinaire + {% pluralize %} + Actuellement, il y a {{ count }} webinaires + {% endtrans %} + {% trans trimmed count=stats["participantCount"]%} + et {{ count }} participant + {% pluralize %} + et {{ count }} participants + {% endtrans %} + {% trans %} sur une capacité moyenne pour la plateforme de {{ max_participants }} participants.{% endtrans %} + +

    +
    +
    + {% endif %} +
    +
    +{% else %} +
    +
    +
    +
    +

    {% trans %}Vous organisez régulièrement des {{ some_meetings }}{% endtrans %}

    +

    {% trans %}Vous êtes agent de l’État, créez un compte pour organiser et conserver vos {{ some_meetings }}.{% endtrans %}

    +

    {% trans %}Se connecter ou créer un compte{% endtrans %}

    +

    + {% if stats is defined and stats %} +

    + + {% trans trimmed count=stats["runningCount"]%} + Actuellement, il y a {{ count }} webinaire + {% pluralize %} + Actuellement, il y a {{ count }} webinaires + {% endtrans %} + {% trans trimmed count=stats["participantCount"]%} + et {{ count }} participant + {% pluralize %} + et {{ count }} participants + {% endtrans %} + {% trans %} sur une capacité moyenne pour la plateforme de {{ max_participants }} participants.{% endtrans %} + +

    + {% endif %} +
    +
    +
    +
    +
    +
    +{% if mail_meeting %} +
    +
    +
    +

    {% trans %}Démarrer {{ a_meeting }} en ligne immédiatement{% endtrans %}

    + {% with messages = get_flashed_messages(with_categories=true, category_filter=["error_login","success_login", "warning"]) %} + {% if messages %} + {% for category,message in messages %} +
    +

    {{ message }}

    +
    + {% endfor %} + {% endif %} + {% endwith %} +

    {% trans %}Recevez par courriel un lien organisateur {{ of_the_meeting }}, actif une semaine, à envoyer aux participants.{% endtrans %}

    +
    + {% include 'meeting/csrf.html' %} +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +{% endif %} +
    +
    + {% if mail_meeting %} + +
    +
    +

    {% trans %}Vous essayez de rejoindre {{ a_meeting }}{% endtrans %}

    +

    {% trans %}Pour rejoindre {{ a_meeting_to_which }} vous êtes invité, cliquez sur le lien que vous a transmis l'organisateur/modérateur.{% endtrans %}

    +

    +
    +
    + {% endif %} +
    +
    +{% endif %} diff --git a/web/b3desk/templates/layout.html b/web/b3desk/templates/layout.html new file mode 100644 index 00000000..275323d1 --- /dev/null +++ b/web/b3desk/templates/layout.html @@ -0,0 +1,85 @@ + + + + + + + + + + {{ config["TITLE"] }} + + + + + + + + + + + + + +
    + {% block header %} + {% include 'header.html' %} + {% endblock %} +
    + {% with messages = get_flashed_messages(with_categories=true, category_filter=["error","success", "message", "warning"]) %} + {% if messages %} + {% for category,message in messages %} +
    +

    {{ message }}

    +
    + {% endfor %} + {% endif %} + {% endwith %} + {% block jumbotron %}{% endblock %} +
    +
    +
    + {% block main %}{% endblock %} +
    +
    +
    +
    + + {% block footer %} + {% include 'footer.html' %} + {% endblock %} + + + + + + + {% if config.get("MATOMO_SITE_ID") and config.get("MATOMO_URL") %} + + {% endif %} + {% block js %}{% endblock %} +
    + + diff --git a/web/b3desk/templates/meeting/card.html b/web/b3desk/templates/meeting/card.html new file mode 100644 index 00000000..5626c549 --- /dev/null +++ b/web/b3desk/templates/meeting/card.html @@ -0,0 +1,9 @@ +
    +
    +

    {{ meeting.name }}

    + {% include 'meeting/row.html' %} +
    +
    +{% include 'meeting/modals/delete.html' %} +{% include 'meeting/modals/invite.html' %} +{% include 'meeting/modals/recordings.html' %} diff --git a/web/flaskr/templates/meeting/csrf.html b/web/b3desk/templates/meeting/csrf.html similarity index 100% rename from web/flaskr/templates/meeting/csrf.html rename to web/b3desk/templates/meeting/csrf.html diff --git a/web/b3desk/templates/meeting/edit.html b/web/b3desk/templates/meeting/edit.html new file mode 100644 index 00000000..e3305cbf --- /dev/null +++ b/web/b3desk/templates/meeting/edit.html @@ -0,0 +1,9 @@ +{% extends 'layout.html' %} + +{% block jumbotron %} +{% include 'meeting/jumbotron.html' %} +{% endblock %} + +{% block main %} +{% include 'meeting/form.html' %} +{% endblock %} diff --git a/web/b3desk/templates/meeting/end.html b/web/b3desk/templates/meeting/end.html new file mode 100644 index 00000000..4aa32d58 --- /dev/null +++ b/web/b3desk/templates/meeting/end.html @@ -0,0 +1,14 @@ +{% extends 'layout.html' %} + +{% block main %} +

    +{{ this_meeting.capitalize() }} est actuellement en cours avec les anciens paramètres.
    +Souhaitez-vous y mettre fin pour permettre la prise en compte immédiate de ces nouveaux paramètres ? Les éventuels participants seront déconnectés. +

    + +
    + {{ form.hidden_tag() }} + + Patienter jusqu'à la fin {{ of_the_meeting }} +
    +{% endblock %} diff --git a/web/b3desk/templates/meeting/externalUpload.html b/web/b3desk/templates/meeting/externalUpload.html new file mode 100644 index 00000000..4c102dc2 --- /dev/null +++ b/web/b3desk/templates/meeting/externalUpload.html @@ -0,0 +1,67 @@ + +
    + + +
    + + + +
    diff --git a/web/b3desk/templates/meeting/files.html b/web/b3desk/templates/meeting/files.html new file mode 100644 index 00000000..4c2999ae --- /dev/null +++ b/web/b3desk/templates/meeting/files.html @@ -0,0 +1,229 @@ +{% macro render_field(field, generate_button=False) %} +
    + {% if field.type == "BooleanField" %} +
    + {{ field(value="on")}} + {{ field.label(class_="fr-label") }} +

    {{ field.description }}

    +
    + {% else %} +
    + {{ field.label(class_="fr-label") }} +

    {{ field.description }}

    + {% if field.errors %} + {% for error in field.errors %} +

    {{ error }}

    + {% endfor %} + {% endif %} + {% if generate_button %} +
    +
    + {{ field(class_="fr-input") }} +
    +
    + +
    +
    + {% else %} + {{ field(class_="fr-input", **kwargs) }} + {% endif %} +
    + {% endif %} +
    +{% endmacro %} + + + + + +

    Gestion des {{ meeting_presentation }}s associées à {{ meeting.name }}

    + + + +
    + {% if form.errors %} +

    Enregistrement impossible car certains champs sont mal renseignés.

    + {% endif %} +
    + + +
    +
    +
    +
    +
    + +
    +
    +
    + {% include 'meeting/csrf.html' %} + {% include 'meeting/id.html' %} +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    +
    + {% include 'meeting/csrf.html' %} + {% include 'meeting/id.html' %} +
    + {{ render_field(form.url) }} + +
    +
    +
    +
    +
    +
    +
    +
    + + +
    + +
    +

    Vous pouvez ajouter un fichier :

    +
    + +
      +
    • + +
    • + {% if user.nc_login and user.nc_token and user.nc_locator %} +
    • + +
    • +
    • + +
    • + {% endif %} +
    + +
    +
    + + +
    + +
    +
    + + + + + + + + + + + + + + {% for file in meeting.files %} + {% if (user.nc_login and user.nc_token and user.nc_locator) or file.url %} + + +
    +
    +
    +
    +
    + +
    +
    +

    + Supprimer +

    +

    Voulez-vous vraiment supprimer le fichier {{ file.short_title }} ?

    +
    + +
    +
    +
    +
    +
    + + + + + + + + + + {% endif %} + {% endfor %} + +
    Vos fichiers associés sont :
    DéfautTéléchargeableTitreAjouté leSupprimerTélécharger
    +
    + {% if file.is_default %} + + + {% else %} + + + {% endif %} +
    +
    +
    + {% if file.is_downloadable %} + + + {% else %} + + + {% endif %} +
    +
    {{ file.short_title }}{{ file.created_at }} + + + + + +
    +
    + {% if not meeting.files|length %} +

    Aucun document de présentation n'est prévu pour cette réunion actuellement

    + {% endif %} +
    +
    + + diff --git a/web/b3desk/templates/meeting/filesform.html b/web/b3desk/templates/meeting/filesform.html new file mode 100644 index 00000000..cdb8bf92 --- /dev/null +++ b/web/b3desk/templates/meeting/filesform.html @@ -0,0 +1,22 @@ +{% extends 'layout.html' %} + +{% block main %} +{% include 'meeting/files.html' %} +{% endblock %} + +{% block js %} + + + +{% endblock %} diff --git a/web/flaskr/templates/meeting/form.html b/web/b3desk/templates/meeting/form.html similarity index 98% rename from web/flaskr/templates/meeting/form.html rename to web/b3desk/templates/meeting/form.html index 857ee8f3..83c70ed3 100644 --- a/web/flaskr/templates/meeting/form.html +++ b/web/b3desk/templates/meeting/form.html @@ -38,7 +38,7 @@

    {% trans %}Modifier{% endtrans %} {{meeting.name }}{% trans %}Créer{% endtrans %} {{ a_meeting }}

    {% endif %} -
    + {% if form.errors %}

    {% trans %}Enregistrement impossible car certains champs sont mal renseignés.{% endtrans %}

    {% endif %} diff --git a/web/b3desk/templates/meeting/id.html b/web/b3desk/templates/meeting/id.html new file mode 100644 index 00000000..f6f66ac2 --- /dev/null +++ b/web/b3desk/templates/meeting/id.html @@ -0,0 +1,3 @@ +{% if meeting is not none %} + +{% endif %} diff --git a/web/b3desk/templates/meeting/join.html b/web/b3desk/templates/meeting/join.html new file mode 100644 index 00000000..f084ddf0 --- /dev/null +++ b/web/b3desk/templates/meeting/join.html @@ -0,0 +1,72 @@ +{% extends 'layout.html' %} + +{% block jumbotron %} +{% include 'rie.html' %} +{% endblock %} + +{% block main %} +

    {% trans %}Rejoindre {{ the_meeting }}{% endtrans %}

    + + + {% include 'meeting/csrf.html' %} + + + + +
    +
    +
    + + {% if role != Role.authenticated %}

    {% trans %}Vous pouvez également préciser votre service ou votre fonction.{% endtrans %}

    {% endif %} + +
    +
    + + {% if role == Role.authenticated %} +
    +
    + +

    Si ce champ est rempli, il sera affiché dans BBB.

    + +
    +
    +

    Le nom affiché sera «  ».

    + {% endif %} + +
    +
    + +
    +
    + + {% if role != Role.authenticated and not user %} +
    +
    + {% trans %}Vous êtes propriétaire de cette salle ?{% endtrans %} + + {% trans %}S’identifier{% endtrans %} + +
    +
    + {% endif %} +
    +
    + +{% if role == Role.authenticated %} + +{% endif %} +{% endblock %} diff --git a/web/flaskr/templates/meeting/joinmail.html b/web/b3desk/templates/meeting/joinmail.html similarity index 57% rename from web/flaskr/templates/meeting/joinmail.html rename to web/b3desk/templates/meeting/joinmail.html index 294ad9a3..95096a40 100644 --- a/web/flaskr/templates/meeting/joinmail.html +++ b/web/b3desk/templates/meeting/joinmail.html @@ -1,9 +1,9 @@ {% extends 'layout.html' %} {% block jumbotron %} - {% include 'rie.html' %} +{% include 'rie.html' %} {% endblock %} {% block main %} - {% include 'meeting/signinmail.html' %} +{% include 'meeting/signinmail.html' %} {% endblock %} diff --git a/web/flaskr/templates/meeting/jumbotron.html b/web/b3desk/templates/meeting/jumbotron.html similarity index 50% rename from web/flaskr/templates/meeting/jumbotron.html rename to web/b3desk/templates/meeting/jumbotron.html index d84b45c1..0d567bfb 100644 --- a/web/flaskr/templates/meeting/jumbotron.html +++ b/web/b3desk/templates/meeting/jumbotron.html @@ -1,10 +1,10 @@
    - {% if meeting is not none %} + {% if meeting is not none %}

    {% trans %}Webinaire{% endtrans %} {{ meeting.name }}

    - {% else %} + {% else %}

    {% trans %}Nouveau webinaire{% endtrans %}

    - {% endif %} - - {% trans %}Retour au tableau de bord{% endtrans %} - + {% endif %} + + {% trans %}Retour au tableau de bord{% endtrans %} +
    diff --git a/web/b3desk/templates/meeting/list.html b/web/b3desk/templates/meeting/list.html new file mode 100644 index 00000000..118475b4 --- /dev/null +++ b/web/b3desk/templates/meeting/list.html @@ -0,0 +1,57 @@ +
    +
    +
    +

    {% trans %}Mes salles de {{ some_meetings }}{% endtrans %}

    + {% if can_create_meetings == true %} + + {% endif %} +
    +
    + {% if not can_create_meetings %} +
    +

    + + {% trans %}Vous avez atteint la limite des {{ max_meetings_per_user }} {{ meeting_label }}s. Pour pouvoir en créer davantage, veuillez supprimer des {{ meeting_label }}s inactives.{% endtrans %} +

    +
    + {% endif %} + + {% if not user.meetings %} +
    +
    +
    +
    +

    Vous n'avez pas encore créé de salle de {{ some_meetings }} permanente. Vous pouvez créer votre salle permanente ou accéder à une salle temporaire plus bas.

    + + Créer une salle permanente + +

    + En créant une salle de réunion permanente, vous pouvez créer une base de documents permanente, choisir d'ajouter une salle d'attente, de bloquer les micros et les caméras ouverts ou fermés, d'afficher ou non les espaces de discussions privés et publiques, ou encore accéder aux enregistrements à la fin de votre réunion. +

    +
    +
    + {% else %} + {% for meeting in user.meetings %} +
    +
    +

    {{ meeting.name }}

    + {% include 'meeting/row.html' %} +
    +
    + {% include 'meeting/modals/delete.html' %} + {% include 'meeting/modals/invite.html' %} + {% include 'meeting/modals/recordings.html' %} + {% endfor %} + {% if user.meetings|length and config.get("SATISFACTION_POLL_URL") %} + + {% endif %} +
    +{% endif %} diff --git a/web/flaskr/templates/meeting/mailtest.html b/web/b3desk/templates/meeting/mailtest.html similarity index 91% rename from web/flaskr/templates/meeting/mailtest.html rename to web/b3desk/templates/meeting/mailtest.html index 0e429bf4..08950ee0 100644 --- a/web/flaskr/templates/meeting/mailtest.html +++ b/web/b3desk/templates/meeting/mailtest.html @@ -1,3 +1,3 @@

    {{ url }}

    -
    + diff --git a/web/flaskr/templates/meeting/mailto/mail_body.txt b/web/b3desk/templates/meeting/mailto/mail_body.txt similarity index 76% rename from web/flaskr/templates/meeting/mailto/mail_body.txt rename to web/b3desk/templates/meeting/mailto/mail_body.txt index 7b178190..ce5dcddb 100644 --- a/web/flaskr/templates/meeting/mailto/mail_body.txt +++ b/web/b3desk/templates/meeting/mailto/mail_body.txt @@ -1,6 +1,6 @@ Vous êtes invité en tant que : -{% if role == 'moderator' %} +{% if role == Role.moderator %} {% trans %}Modérateur{% endtrans %} {% else %} {% trans %}Participant{% endtrans %} @@ -12,15 +12,15 @@ Vous êtes invité en tant que : --- {% trans %}Le lien pour s'y inscrire est le suivant :{% endtrans %} -{% if role == 'moderator' %} -{{ meeting.moderator_signin_url }} +{% if role == Role.moderator %} +{{ meeting.get_signin_url(Role.moderator) }} {% else %} -{{ meeting.attendee_signin_url }} +{{ meeting.get_signin_url(Role.attendee) }} {% endif %} --- {% trans %}Le mot de passe de {{ this_meeting }} est :{% endtrans %} -{% if role == 'moderator' %} +{% if role == Role.moderator %} {{ meeting.moderatorPW }} {% else %} {{ meeting.attendeePW }} diff --git a/web/flaskr/templates/meeting/mailto/mail_href.txt b/web/b3desk/templates/meeting/mailto/mail_href.txt similarity index 100% rename from web/flaskr/templates/meeting/mailto/mail_href.txt rename to web/b3desk/templates/meeting/mailto/mail_href.txt diff --git a/web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt b/web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt similarity index 100% rename from web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt rename to web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt diff --git a/web/flaskr/templates/meeting/mailto/mail_subject.txt b/web/b3desk/templates/meeting/mailto/mail_subject.txt similarity index 100% rename from web/flaskr/templates/meeting/mailto/mail_subject.txt rename to web/b3desk/templates/meeting/mailto/mail_subject.txt diff --git a/web/b3desk/templates/meeting/modals/delete.html b/web/b3desk/templates/meeting/modals/delete.html new file mode 100644 index 00000000..bc86de8c --- /dev/null +++ b/web/b3desk/templates/meeting/modals/delete.html @@ -0,0 +1,47 @@ + + +
    +
    +
    +
    +
    + +
    +
    +

    + + Supprimer "{{ meeting.name }}" ? +

    +

    Voulez-vous vraiment supprimer {{ the_meeting }} "{{ meeting.name }}" ?

    +
    +
    +
    +

    La suppression est définitive

    +
    +

    Si vous supprimez cette salle, tous les médias (documents importés et enregistrements) qui lui sont rattachés seront supprimés.

    +
    +
    +
    + +
    +
    +
    +
    +
    diff --git a/web/b3desk/templates/meeting/modals/invite.html b/web/b3desk/templates/meeting/modals/invite.html new file mode 100644 index 00000000..0f113c8a --- /dev/null +++ b/web/b3desk/templates/meeting/modals/invite.html @@ -0,0 +1,72 @@ + + +
    +
    +
    +
    +
    + +
    +
    +

    + + Inviter les modérateurs +

    +

    En leur envoyant l’adresse ci-dessous :

    +
    +
    + {{ meeting.get_signin_url(Role.moderator) }} +
    +
    + +
    +
    +

    +
    + Rejoindre {{ the_meeting }} en tant que modérateur principal +

    +

    + Inviter les participants

    +

    En leur envoyant l’adresse ci-dessous :

    +
    +
    + {{ meeting.get_signin_url(Role.attendee) }} +
    +
    + +
    +
    +

    +
    + Rejoindre {{ the_meeting }} en tant que participant +

    + +

    + Inviter les participants authentifiés {% if config.OIDC_ATTENDEE_SERVICE_NAME %}via {{ config.OIDC_ATTENDEE_SERVICE_NAME }} {% endif %}

    +

    En leur envoyant l’adresse ci-dessous :

    +
    +
    + {{ meeting.get_signin_url(Role.authenticated) }} +
    +
    + +
    +
    +

    +
    + Rejoindre {{ the_meeting }} en tant que participant authentifié +

    +
    +
    +
    +
    +
    +
    diff --git a/web/b3desk/templates/meeting/modals/recordings.html b/web/b3desk/templates/meeting/modals/recordings.html new file mode 100644 index 00000000..f8426236 --- /dev/null +++ b/web/b3desk/templates/meeting/modals/recordings.html @@ -0,0 +1,54 @@ + + diff --git a/web/b3desk/templates/meeting/recordings.html b/web/b3desk/templates/meeting/recordings.html new file mode 100644 index 00000000..9c6a826b --- /dev/null +++ b/web/b3desk/templates/meeting/recordings.html @@ -0,0 +1,159 @@ +{% extends 'layout.html' %} + +{% block jumbotron %} +{% endblock %} + +{% block main %} +

    {% trans meeting_name=meeting.name %}Enregistrements de {{meeting_name }}{% endtrans %}

    + +
    + {% if meeting.is_running() %} +

    + {% trans this_meeting=this_meeting.capitalize() %}{{ this_meeting }} est toujours en cours{% endtrans %}. + {% trans %}Si un enregistrement est en cours, il ne sera encodé qu'après la fin {{ of_the_meeting }}{% endtrans %}. +

    + {% endif %} +

    {% trans %}Après la fin d'{{ a_meeting }}, l'encodage de l'enregistrement peut prendre autant de temps que la durée {{ of_the_meeting }}.{% endtrans %}

    +

    {% trans %}Si aucun modérateur ne met fin {{ of_the_meeting }}, un délai supplémentaire de plusieurs minutes s'ajoute après que tous les utilisateurs l'aient quitté.{% endtrans %}

    +

    {% trans duration=config["RECORDING_DURATION"]|timedeltaformat %}Les enregistrements sont conservés pour une période de {{ duration }}.{% endtrans %}

    + {% for recording in meeting.get_recordings() %} + {% set recording_name = recording.name or recording.start_date.strftime("%d/%m/%Y") %} +

    + {{ recording_name }} + +

    + {% trans start_date=recording.start_date|dateformat, expiration_date=(recording.end_date+config["RECORDING_DURATION"])|dateformat %} + Enregistré le {{ start_date }} - + Expire le {{ expiration_date }} + {% endtrans %} +
    + + + + + + + {% set playback = recording.playbacks.get("presentation") %} + {% if playback %} + + + + + {% endif %} + +
    {% trans %}Visuels{% endtrans %}{% trans %}Actions{% endtrans %}
    +
    + {% for i in playback.images %} + {% if loop.index is le(2) %} +
    + {{ i.alt }} +
    + {% endif %} + {% endfor %} +
    +
    +
    + + + {% if recording.playbacks.get("video") %} + mp4 + {% endif %} + +
    +
    +
    + + + + +
    +
    +
    +
    +
    + +
    +
    +

    + + Supprimer "{{ recording_name }}" ? +

    +

    Voulez-vous vraiment supprimer l'enregistrement {{ recording_name }} de {{ meeting.name }} ?

    +
    + +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    + +
    +
    +
    + {% include 'meeting/csrf.html' %} +
    + {{ form.name.label(class_="fr-label") }} +

    {{ form.name.description }}

    + {% if form.name.errors %} + {% for error in form.name.errors %} +

    {{ error }}

    + {% endfor %} + {% endif %} + {{ form.name(value=recording_name, class_="fr-input") }} +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
    +
    +
    +
    +
    + + {% endfor %} +
    + +{% endblock %} diff --git a/web/b3desk/templates/meeting/row.html b/web/b3desk/templates/meeting/row.html new file mode 100644 index 00000000..e74a4613 --- /dev/null +++ b/web/b3desk/templates/meeting/row.html @@ -0,0 +1,55 @@ +
    + {% if config.get("SHORTY") %} +
    + + + {% if mailto %} + + {% endif %} + +
    +
    + + + {% if mailto %} + + {% endif %} + +
    +
    + + {% if config.get("FILE_SHARING") %} + + {% endif %} + +
    + {% else %} +
    + {% trans %}Lancer{% endtrans %} + +
    + + {% endif %} +
    diff --git a/web/b3desk/templates/meeting/show.html b/web/b3desk/templates/meeting/show.html new file mode 100644 index 00000000..00690947 --- /dev/null +++ b/web/b3desk/templates/meeting/show.html @@ -0,0 +1,9 @@ +{% extends 'layout.html' %} + +{% block jumbotron %} +{% include 'jumbotron.html' %} +{% endblock %} + +{% block main %} +{% include 'meeting/card.html' %} +{% endblock %} diff --git a/web/flaskr/templates/meeting/signin_links.html b/web/b3desk/templates/meeting/signin_links.html similarity index 100% rename from web/flaskr/templates/meeting/signin_links.html rename to web/b3desk/templates/meeting/signin_links.html diff --git a/web/flaskr/templates/meeting/signin_mail_link.html b/web/b3desk/templates/meeting/signin_mail_link.html similarity index 100% rename from web/flaskr/templates/meeting/signin_mail_link.html rename to web/b3desk/templates/meeting/signin_mail_link.html diff --git a/web/flaskr/templates/meeting/signinmail.html b/web/b3desk/templates/meeting/signinmail.html similarity index 95% rename from web/flaskr/templates/meeting/signinmail.html rename to web/b3desk/templates/meeting/signinmail.html index 8e066362..0dbd3b52 100644 --- a/web/flaskr/templates/meeting/signinmail.html +++ b/web/b3desk/templates/meeting/signinmail.html @@ -1,5 +1,5 @@

    {% trans %}Rejoindre {{ the_meeting }}{% endtrans %}

    -
    + {% include 'meeting/csrf.html' %} diff --git a/web/b3desk/templates/meeting/submit.html b/web/b3desk/templates/meeting/submit.html new file mode 100644 index 00000000..85c4075c --- /dev/null +++ b/web/b3desk/templates/meeting/submit.html @@ -0,0 +1,8 @@ +
    + {% if meeting is not none %} + + {% else %} + + {% endif %} + {% trans %}Annuler{% endtrans %} +
    diff --git a/web/flaskr/templates/meeting/wait.html b/web/b3desk/templates/meeting/wait.html similarity index 68% rename from web/flaskr/templates/meeting/wait.html rename to web/b3desk/templates/meeting/wait.html index 27211477..7ae08200 100644 --- a/web/flaskr/templates/meeting/wait.html +++ b/web/b3desk/templates/meeting/wait.html @@ -18,13 +18,21 @@

    - {% trans %}Votre hôte n’est pas encore arrivé. Vous entrerez automatiquement dans la salle de visio-conférence dès qu’il sera présent.{% endtrans %} + {% if role == Role.moderator %} + {% trans %} + La salle de visio-conférence est en cours de création. Vous entrerez automatiquement dans la salle dès qu'elle sera opérationnelle. + {% endtrans %} + {% else %} + {% trans %} + Votre hôte n’est pas encore arrivé. Vous entrerez automatiquement dans la salle de visio-conférence dès qu’il sera présent. + {% endtrans %} + {% endif %}

    - + {% include 'meeting/csrf.html' %} - + diff --git a/web/flaskr/templates/meeting/wizard.html b/web/b3desk/templates/meeting/wizard.html similarity index 72% rename from web/flaskr/templates/meeting/wizard.html rename to web/b3desk/templates/meeting/wizard.html index ce0a17ca..df9391ed 100644 --- a/web/flaskr/templates/meeting/wizard.html +++ b/web/b3desk/templates/meeting/wizard.html @@ -4,5 +4,5 @@ {% endblock %} {% block main %} - {% include 'meeting/form.html' %} +{% include 'meeting/form.html' %} {% endblock %} diff --git a/web/flaskr/templates/page.html b/web/b3desk/templates/page.html similarity index 100% rename from web/flaskr/templates/page.html rename to web/b3desk/templates/page.html diff --git a/web/b3desk/templates/redirections.html b/web/b3desk/templates/redirections.html new file mode 100644 index 00000000..9ee67870 --- /dev/null +++ b/web/b3desk/templates/redirections.html @@ -0,0 +1,13 @@ + + +
    +

    {% trans %}Autres profils{% endtrans %}

    + {% for link in redirection_links %} +

    {{ link.text }}

    + {% endfor %} +
    + diff --git a/web/flaskr/templates/rie.html b/web/b3desk/templates/rie.html similarity index 76% rename from web/flaskr/templates/rie.html rename to web/b3desk/templates/rie.html index e335a003..3aba52a5 100644 --- a/web/flaskr/templates/rie.html +++ b/web/b3desk/templates/rie.html @@ -2,6 +2,6 @@ {% endif %} diff --git a/web/b3desk/templates/static-layout.html b/web/b3desk/templates/static-layout.html new file mode 100644 index 00000000..87a135a8 --- /dev/null +++ b/web/b3desk/templates/static-layout.html @@ -0,0 +1,60 @@ + + + + + + + + + + {{ config["TITLE"] }} + + + + + + + + + +
    + {% block header %} + {% include 'header.html' %} + {% endblock %} +
    +
    +
    + {% block main %}{% endblock %} +
    +
    +
    + + {% block footer %} + {% include 'footer.html' %} + {% endblock %} + + + + + + + + {% if config.get("MATOMO_SITE_ID") and config.get("MATOMO_URL") %} + + {% endif %} + {% block js %}{% endblock %} +
    + + diff --git a/web/b3desk/templates/tools.html b/web/b3desk/templates/tools.html new file mode 100644 index 00000000..6db2a127 --- /dev/null +++ b/web/b3desk/templates/tools.html @@ -0,0 +1,46 @@ + diff --git a/web/flaskr/templates/welcome.html b/web/b3desk/templates/welcome.html similarity index 60% rename from web/flaskr/templates/welcome.html rename to web/b3desk/templates/welcome.html index a426f7c7..07208ffb 100644 --- a/web/flaskr/templates/welcome.html +++ b/web/b3desk/templates/welcome.html @@ -1,9 +1,9 @@ {% extends 'layout.html' %} {% block jumbotron %} - {% include 'jumbotron.html' %} +{% include 'jumbotron.html' %} {% endblock %} {% block main %} - {% include 'page.html' %} +{% include 'page.html' %} {% endblock %} diff --git a/web/b3desk/utils.py b/web/b3desk/utils.py new file mode 100644 index 00000000..7b51e180 --- /dev/null +++ b/web/b3desk/utils.py @@ -0,0 +1,127 @@ +import random +import re +import smtplib +import string +from email.message import EmailMessage +from email.mime.text import MIMEText + +from flask import abort +from flask import current_app +from flask import render_template +from flask import request +from flask import url_for +from netaddr import IPAddress +from netaddr import IPNetwork +from slugify import slugify +from werkzeug.routing import BaseConverter + +from b3desk.models import db +from b3desk.models.roles import Role + + +def secret_key(): + return current_app.config["SECRET_KEY"] + + +def is_rie(): + """Checks wether the request was made from inside the state network "Réseau + Interministériel de l’État".""" + if not request.remote_addr: + return False + + return current_app.config["RIE_NETWORK_IPS"] and any( + IPAddress(request.remote_addr) in IPNetwork(str(network_ip)) + for network_ip in current_app.config["RIE_NETWORK_IPS"] + if network_ip + ) + + +def is_accepted_email(email): + for regex in current_app.config["EMAIL_WHITELIST"]: + if re.search(regex, email): + return True + return False + + +def is_valid_email(email): + if not email or not re.search( + r"^([a-zA-Z0-9_\-\.']+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$", email + ): + return False + return True + + +def get_random_alphanumeric_string(length): + letters_and_digits = string.ascii_letters + string.digits + result_str = "".join(random.choice(letters_and_digits) for i in range(length)) + return result_str + + +def send_quick_meeting_mail(meeting, to_email): + smtp_from = current_app.config["SMTP_FROM"] + smtp_host = current_app.config["SMTP_HOST"] + smtp_port = current_app.config["SMTP_PORT"] + smtp_ssl = current_app.config["SMTP_SSL"] + smtp_starttls = current_app.config["SMTP_STARTTLS"] + smtp_username = current_app.config["SMTP_USERNAME"] + smtp_password = current_app.config["SMTP_PASSWORD"] + wordings = current_app.config["WORDINGS"] + msg = EmailMessage() + content = render_template( + "meeting/mailto/mail_quick_meeting_body.txt", + role=Role.moderator, + moderator_mail_signin_url=meeting.get_mail_signin_url(), + welcome_url=url_for("public.welcome", _external=True), + meeting=meeting, + ) + msg["Subject"] = str(wordings["meeting_mail_subject"]) + msg["From"] = smtp_from + msg["To"] = to_email + html = MIMEText(content, "html") + msg.make_mixed() # This converts the message to multipart/mixed + msg.attach(html) + + connection_func = smtplib.SMTP_SSL if smtp_ssl else smtplib.SMTP + with connection_func(smtp_host, smtp_port) as smtp: + if smtp_starttls: + smtp.starttls() + if smtp_username: + smtp.login(smtp_username, smtp_password) + smtp.send_message(msg) + + +def model_converter(model): + class ModelConverter(BaseConverter): + def __init__(self, *args, required=True, **kwargs): + self.required = required + super().__init__(self, *args, **kwargs) + + def to_url(self, instance): + return str(instance.id) + + def to_python(self, identifier): + instance = db.session.get(model, identifier) + if self.required and not instance: + abort(404) + + return instance + + return ModelConverter + + +def enum_converter(enum): + class EnumConverter(BaseConverter): + def __init__(self, *args, required=True, **kwargs): + self.required = required + super().__init__(self, *args, **kwargs) + + def to_url(self, instance): + return slugify(instance.value) + + def to_python(self, identifier): + for item in enum: + if identifier == slugify(item.value): + return item + abort(404) + + return EnumConverter diff --git a/web/b3desk/wsgi.py b/web/b3desk/wsgi.py new file mode 100644 index 00000000..49b207f2 --- /dev/null +++ b/web/b3desk/wsgi.py @@ -0,0 +1,3 @@ +from b3desk import create_app + +app = create_app() diff --git a/web/flaskr/__init__.py b/web/flaskr/__init__.py deleted file mode 100755 index f4371874..00000000 --- a/web/flaskr/__init__.py +++ /dev/null @@ -1,122 +0,0 @@ -# +----------------------------------------------------------------------------+ -# | BBB-VISIO | -# +----------------------------------------------------------------------------+ -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the European Union Public License 1.2 version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. -import logging -import os - -from flask import Flask -from flask import request -from flask import session -from flask_babel import Babel -from flask_migrate import Migrate -from flask_wtf.csrf import CSRFProtect -from flaskr.utils import is_rie - -from .common.extensions import cache - -CRITICAL_VARS = ["OIDC_ISSUER", "OIDC_CLIENT_SECRET", "BIGBLUEBUTTON_SECRET"] -LANGUAGES = ["en", "fr"] - - -def setup_cache(app): - cache.init_app( - app, - config={ - "CACHE_TYPE": "flask_caching.backends.filesystem", - "CACHE_DIR": "/tmp/flask-caching", - }, - ) - - -def setup_logging(app, test_config=None, gunicorn_logging=False): - if gunicorn_logging: - gunicorn_logger = logging.getLogger("gunicorn.error") - app.logger.handlers = gunicorn_logger.handlers - app.logger.setLevel(gunicorn_logger.level) - app.config.from_pyfile("config.py") - if test_config: - app.config.from_mapping(test_config) - - -def setup_i18n(app): - babel = Babel(app) - - @babel.localeselector - def get_locale(): - if request.args.get("lang"): - session["lang"] = request.args["lang"] - return session.get("lang", "fr") - - -def setup_csrf(app): - csrf = CSRFProtect() - csrf.init_app(app) - - -def setup_database(app): - with app.app_context(): - import flaskr.routes - - app.register_blueprint(flaskr.routes.bp) - from .models import db - - db.init_app(app) - Migrate(app, db, compare_type=True) - - -def setup_jinja(app): - @app.context_processor - def global_processor(): - return { - "config": app.config, - "beta": app.config["BETA"], - "documentation_link": app.config["DOCUMENTATION_LINK"], - "is_rie": is_rie(), - "version": "1.1.6", - "LANGUAGES": LANGUAGES, - **app.config["WORDINGS"], - } - - -def setup_error_pages(app): - from flask import render_template - - @app.errorhandler(400) - def bad_request(error): - return render_template("errors/400.html", error=error), 400 - - @app.errorhandler(403) - def not_authorized(error): - return render_template("errors/403.html", error=error), 403 - - @app.errorhandler(404) - def not_found(error): - return render_template("errors/404.html", error=error), 404 - - @app.errorhandler(500) - def internal_error(error): - return render_template("errors/500.html", error=error), 500 - - -def create_app(test_config=None, gunicorn_logging=False): - # create and configure the app - app = Flask(__name__, instance_relative_config=True) - setup_cache(app) - setup_logging(app, test_config, gunicorn_logging) - setup_i18n(app) - setup_csrf(app) - setup_database(app) - setup_jinja(app) - setup_error_pages(app) - - # ensure the instance folder exists - os.makedirs(app.instance_path, exist_ok=True) - - return app diff --git a/web/flaskr/common/extensions.py b/web/flaskr/common/extensions.py deleted file mode 100644 index c017decd..00000000 --- a/web/flaskr/common/extensions.py +++ /dev/null @@ -1,3 +0,0 @@ -from flask_caching import Cache - -cache = Cache() diff --git a/web/flaskr/models.py b/web/flaskr/models.py deleted file mode 100755 index 6da052fe..00000000 --- a/web/flaskr/models.py +++ /dev/null @@ -1,787 +0,0 @@ -# +----------------------------------------------------------------------------+ -# | BBB-VISIO | -# +----------------------------------------------------------------------------+ -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the European Union Public License 1.2 version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. -import hashlib -import os -from datetime import date -from datetime import datetime -from datetime import timedelta -from datetime import timezone -from xml.etree import ElementTree - -import requests -from flask import current_app -from flask import render_template -from flask import url_for -from flask_sqlalchemy import SQLAlchemy -from flaskr.tasks import background_upload -from flaskr.utils import secret_key -from sqlalchemy_utils import EncryptedType - - -db = SQLAlchemy() - -MODERATOR_ONLY_MESSAGE_MAXLENGTH = 150 - - -def sigchld_handler(): - os.wait() - print("ok") - - -def get_user_nc_credentials(username): - if ( - not current_app.config["NC_LOGIN_API_KEY"] - or not current_app.config["NC_LOGIN_API_URL"] - or not current_app.config["FILE_SHARING"] - or not username - ): - print( - "File sharing deactivated or unable to perform, no connection to Nextcloud instance" - ) - return {"nctoken": None, "nclocator": None, "nclogin": None} - postData = {"username": username} - postHeaders = {"X-API-KEY": current_app.config["NC_LOGIN_API_KEY"]} - print( - "Retrieve NC credentials from NC_LOGIN_API_URL %s " - % current_app.config["NC_LOGIN_API_URL"] - ) - try: - response = requests.post( - current_app.config["NC_LOGIN_API_URL"], json=postData, headers=postHeaders - ) - data = response.json() - return data - except requests.exceptions.RequestException: - print("Cannot contact NC, returning None values") - return {"nctoken": None, "nclocator": None, "nclogin": None} - - -def get_or_create_user(user_info): - # preferred_username is login from keycloak, REQUIRED for nc_login connexion - # data is conveyed like following : - # user logs in to keycloak - # visio-agent retrives preferred_username from keycloack ( aka keycloak LOGIN, which is immutable ) - # visio-agent calls EDNAT API for NC_DATA retrieval, passing LOGIN as postData - # visio-agent can now connect to remote NC with NC_DATA - if current_app.config["FILE_SHARING"]: - preferred_username = user_info["preferred_username"] - else: - preferred_username = None - given_name = user_info["given_name"] - family_name = user_info["family_name"] - email = user_info["email"].lower() - - user = User.query.filter_by(email=email).first() - - if user is None: - data = get_user_nc_credentials(preferred_username) - nc_locator, nc_token, nc_login = ( - data["nclocator"], - data["nctoken"], - preferred_username, - ) - if nc_locator is None or nc_login is None or nc_token is None: - nc_last_auto_enroll = None - else: - nc_last_auto_enroll = datetime.now().strftime( - current_app.config["TIME_FORMAT"] - ) - user = User( - email=email, - given_name=given_name, - family_name=family_name, - nc_locator=nc_locator, - nc_login=nc_login, - nc_token=nc_token, - nc_last_auto_enroll=nc_last_auto_enroll, - last_connection_utc_datetime=datetime.utcnow(), - ) - user.save() - else: - user_has_changed = False - if ( - not user.nc_last_auto_enroll - or not user.nc_locator - or not user.nc_token - or ( - (datetime.now() - user.nc_last_auto_enroll).days - > current_app.config["NC_LOGIN_TIMEDELTA_DAYS"] - ) - ): - data = get_user_nc_credentials(preferred_username) - nc_locator, nc_token, nc_login = ( - data["nclocator"], - data["nctoken"], - preferred_username, - ) - if nc_locator is None or nc_login is None or nc_token is None: - nc_last_auto_enroll = None - else: - nc_last_auto_enroll = datetime.now().strftime( - current_app.config["TIME_FORMAT"] - ) - user.nc_token = nc_token - user.nc_login = nc_login - user.nc_locator = nc_locator - user.nc_last_auto_enroll = nc_last_auto_enroll - user_has_changed = True - - if user.given_name != given_name: - user.given_name = given_name - user_has_changed = True - if user.family_name != family_name: - user.family_name = family_name - user_has_changed = True - if ( - not user.last_connection_utc_datetime - or user.last_connection_utc_datetime.date() < date.today() - ): - user.last_connection_utc_datetime = datetime.utcnow() - user_has_changed = True - if user_has_changed: - user.save() - return user - - -class User(db.Model): - id = db.Column(db.Integer, primary_key=True) - email = db.Column(db.Unicode(150), unique=True) - given_name = db.Column(db.Unicode(50)) - family_name = db.Column(db.Unicode(50)) - nc_locator = db.Column(db.Unicode(255)) - nc_login = db.Column(db.Unicode(255)) - nc_token = db.Column(db.Unicode(255)) - nc_last_auto_enroll = db.Column(db.DateTime) - last_connection_utc_datetime = db.Column(db.DateTime) - - meetings = db.relationship("Meeting", back_populates="user") - - @property - def fullname(self): - return f"{self.given_name} {self.family_name}" - - @property - def hash(self): - s = f"{self.email}|{secret_key()}" - return hashlib.sha1(s.encode("utf-8")).hexdigest() - - @property - def can_create_meetings(self): - return len(self.meetings) < current_app.config["MAX_MEETINGS_PER_USER"] - - def save(self): - db.session.add(self) - db.session.commit() - - def disable_nextcloud(self): - self.nc_login = None - self.nc_locator = None - self.nc_token = None - self.nc_last_auto_enroll = None - self.save() - - -class BBB: - """Interface to BBB API""" - - def __init__(self, meeting): - self.meeting = meeting - - def get_params_with_checksum(self, action, params): - request = requests.Request( - "GET", - "{}/{}".format(current_app.config["BIGBLUEBUTTON_ENDPOINT"], action), - params=params, - ) - pr = request.prepare() - bigbluebutton_secret = current_app.config["BIGBLUEBUTTON_SECRET"] - s = "{}{}".format( - pr.url.replace("?", "").replace( - current_app.config["BIGBLUEBUTTON_ENDPOINT"] + "/", "" - ), - bigbluebutton_secret, - ) - params["checksum"] = hashlib.sha1(s.encode("utf-8")).hexdigest() - return params - - def get_url(self, action): - bbb_endpoint = current_app.config["BIGBLUEBUTTON_ENDPOINT"] - return f"{bbb_endpoint}/{action}" - - def is_meeting_running(self): - action = "isMeetingRunning" - params = self.get_params_with_checksum( - action, {"meetingID": self.meeting.meetingID} - ) - r = requests.get(self.get_url(action), params=params) - d = {c.tag: c.text for c in ElementTree.fromstring(r.content)} - return d and d["returncode"] == "SUCCESS" and d["running"] == "true" - - def insertDocsNoDefault(self): - # meeting has started, we can now add files by using insertDocument API - # ADDING ALL FILES EXCEPT DEFAULT - SERVER_FQDN = current_app.config["SERVER_FQDN"] - SECRET_KEY = current_app.config["SECRET_KEY"] - BIGBLUEBUTTON_ENDPOINT = current_app.config["BIGBLUEBUTTON_ENDPOINT"] - BIGBLUEBUTTON_SECRET = current_app.config["BIGBLUEBUTTON_SECRET"] - - insertAction = "insertDocument" - xml_beg = " " - xml_end = " " - xml_mid = "" - for meeting_file in self.meeting.files: - if meeting_file.is_default: - continue - elif meeting_file.url: - xml_mid += f"" - else: # file is not URL hence it was uploaded to nextcloud: - filehash = hashlib.sha1( - f"{SECRET_KEY}-0-{meeting_file.id}-{SECRET_KEY}".encode() - ).hexdigest() - xml_mid += f"" - - xml = xml_beg + xml_mid + xml_end - params = {"meetingID": self.meeting.meetingID} - request = requests.Request( - "POST", - f"{BIGBLUEBUTTON_ENDPOINT}/{insertAction}", - params=params, - ) - pr = request.prepare() - bigbluebutton_secret = BIGBLUEBUTTON_SECRET - s = "{}{}".format( - pr.url.replace("?", "").replace(BIGBLUEBUTTON_ENDPOINT + "/", ""), - bigbluebutton_secret, - ) - params["checksum"] = hashlib.sha1(s.encode("utf-8")).hexdigest() - - requests.post( - f"{BIGBLUEBUTTON_ENDPOINT}/{insertAction}", - headers={"Content-Type": "application/xml"}, - data=xml, - params=params, - ) - return {} - - def create(self): - action = "create" - insertAction = "insertDocument" - params = { - "meetingID": self.meeting.meetingID, - "name": self.meeting.name, - "uploadExternalUrl": current_app.config["SERVER_FQDN"] - + "/meeting/" - + str(self.meeting.id) - + "/externalUpload", - "uploadExternalDescription": current_app.config[ - "EXTERNAL_UPLOAD_DESCRIPTION" - ], - } - if (param := self.meeting.record) is not None: - params["record"] = str(param).lower() - if (param := self.meeting.autoStartRecording) is not None: - params["autoStartRecording"] = str(param).lower() - if (param := self.meeting.allowStartStopRecording) is not None: - params["allowStartStopRecording"] = str(param).lower() - if (param := self.meeting.webcamsOnlyForModerator) is not None: - params["webcamsOnlyForModerator"] = str(param).lower() - if (param := self.meeting.muteOnStart) is not None: - params["muteOnStart"] = str(param).lower() - if (param := self.meeting.lockSettingsDisableCam) is not None: - params["lockSettingsDisableCam"] = str(param).lower() - if (param := self.meeting.lockSettingsDisableMic) is not None: - params["lockSettingsDisableMic"] = str(param).lower() - if (param := self.meeting.allowModsToUnmuteUsers) is not None: - params["allowModsToUnmuteUsers"] = str(param).lower() - if (param := self.meeting.lockSettingsDisablePrivateChat) is not None: - params["lockSettingsDisablePrivateChat"] = str(param).lower() - if (param := self.meeting.lockSettingsDisablePublicChat) is not None: - params["lockSettingsDisablePublicChat"] = str(param).lower() - if (param := self.meeting.lockSettingsDisableNote) is not None: - params["lockSettingsDisableNote"] = str(param).lower() - if param := self.meeting.attendeePW: - params["attendeePW"] = param - if param := self.meeting.moderatorPW: - params["moderatorPW"] = param - if param := self.meeting.welcome: - params["welcome"] = param - if param := self.meeting.maxParticipants: - params["maxParticipants"] = str(param) - if param := self.meeting.logoutUrl: - params["logoutURL"] = param - if param := self.meeting.duration: - params["duration"] = str(param) - bigbluebutton_analytics_callback_url = current_app.config[ - "BIGBLUEBUTTON_ANALYTICS_CALLBACK_URL" - ] - if bigbluebutton_analytics_callback_url: - # bbb will call this endpoint when meeting ends - params.update( - { - "meetingKeepEvents": "true", - "meta_analytics-callback-url": bigbluebutton_analytics_callback_url, - } - ) - if self.meeting.attendeePW is None: - # if no attendeePW it a meeting create with a mail (not logged in) - params["moderatorOnlyMessage"] = render_template( - "meeting/signin_mail_link.html", - main_message=self.meeting.moderatorOnlyMessage, - link=self.meeting.get_mail_signin_url(), - ) - else: - quick_meeting_moderator_link_introduction = current_app.config[ - "QUICK_MEETING_MODERATOR_LINK_INTRODUCTION" - ] - quick_meeting_attendee_link_introduction = current_app.config[ - "QUICK_MEETING_ATTENDEE_LINK_INTRODUCTION" - ] - params["moderatorOnlyMessage"] = render_template( - "meeting/signin_links.html", - moderator_message=self.meeting.moderatorOnlyMessage, - moderator_link_introduction=quick_meeting_moderator_link_introduction, - moderator_signin_url=self.meeting.get_signin_url("moderator"), - attendee_link_introduction=quick_meeting_attendee_link_introduction, - attendee_signin_url=self.meeting.get_signin_url("attendee"), - ) - params["guestPolicy"] = ( - "ASK_MODERATOR" if self.meeting.guestPolicy else "ALWAYS_ACCEPT" - ) - - params = self.get_params_with_checksum(action, params) - if current_app.config["FILE_SHARING"]: - # ADDING DEFAULT FILE TO MEETING - SECRET_KEY = current_app.config["SECRET_KEY"] - xml_beg = " " - xml_end = " " - xml_mid = "" - - if self.meeting.default_file: - meeting_file = self.meeting.default_file - if meeting_file.url: - xml_mid += f"" - else: # file is not URL nor NC hence it was uploaded - filehash = hashlib.sha1( - f"{SECRET_KEY}-0-{meeting_file.id}-{SECRET_KEY}".encode() - ).hexdigest() - xml_mid += f"" - - xml = xml_beg + xml_mid + xml_end - r = requests.post( - self.get_url(action), - params=params, - headers={"Content-Type": "application/xml"}, - data=xml if self.meeting.default_file else None, - ) - ## BEGINNING OF TASK CELERY - aka background_upload for meeting_files - params = {} - xml = "" - # ADDING ALL FILES EXCEPT DEFAULT - non_default_meeting_files = [ - meeting_file - for meeting_file in self.meeting.files - if not meeting_file.is_default - ] - if non_default_meeting_files: - SERVER_FQDN = current_app.config["SERVER_FQDN"] - BIGBLUEBUTTON_ENDPOINT = current_app.config["BIGBLUEBUTTON_ENDPOINT"] - BIGBLUEBUTTON_SECRET = current_app.config["BIGBLUEBUTTON_SECRET"] - - insertAction = "insertDocument" - xml_beg = " " - xml_end = " " - xml_mid = "" - for meeting_file in non_default_meeting_files: - if meeting_file.url: - xml_mid += f"" - else: # file is not URL nor NC hence it was uploaded - filehash = hashlib.sha1( - f"{SECRET_KEY}-0-{meeting_file.id}-{SECRET_KEY}".encode() - ).hexdigest() - xml_mid += f"" - - xml = xml_beg + xml_mid + xml_end - params = {"meetingID": self.meeting.meetingID} - request = requests.Request( - "POST", - f"{BIGBLUEBUTTON_ENDPOINT}/{insertAction}", - params=params, - ) - pr = request.prepare() - bigbluebutton_secret = BIGBLUEBUTTON_SECRET - s = "{}{}".format( - pr.url.replace("?", "").replace(BIGBLUEBUTTON_ENDPOINT + "/", ""), - bigbluebutton_secret, - ) - params["checksum"] = hashlib.sha1(s.encode("utf-8")).hexdigest() - background_upload.delay( - f"{BIGBLUEBUTTON_ENDPOINT}/{insertAction}", xml, params - ) - - d = {c.tag: c.text for c in ElementTree.fromstring(r.content)} - return d - else: - r = requests.post(self.get_url(action), params=params) - d = {c.tag: c.text for c in ElementTree.fromstring(r.content)} - return d - - def delete_recordings(self, recording_ids): - """DeleteRecordings BBB API: https://docs.bigbluebutton.org/dev/api.html#deleterecordings""" - action = "deleteRecordings" - params = self.get_params_with_checksum(action, {"recordID": recording_ids}) - response = requests.get(self.get_url(action), params=params) - d = { - child.tag: child.text for child in ElementTree.fromstring(response.content) - } - return d - - def get_meeting_info(self): - action = "getMeetingInfo" - params = self.get_params_with_checksum( - action, {"meetingID": self.meeting.meetingID} - ) - resp = requests.get(self.get_url(action), params=params) - return {c.tag: c.text for c in ElementTree.fromstring(resp.content)} - - def get_recordings(self): - action = "getRecordings" - params = self.get_params_with_checksum( - action, {"meetingID": self.meeting.meetingID} - ) - response = requests.get(self.get_url(action), params=params) - root = ElementTree.fromstring(response.content) - return_code = root.find("returncode").text - recordings = root.find("recordings") - result = [] - if return_code != "FAILED": - try: - for recording in recordings.iter("recording"): - d = {} - d["recordID"] = recording.find("recordID").text - name = recording.find("metadata").find("name") - d["name"] = name.text if name is not None else None - d["participants"] = int(recording.find("participants").text) - d["playbacks"] = {} - playback = recording.find("playback") - for format in playback.iter("format"): - images = [] - preview = format.find("preview") - if preview is not None: - for i in ( - format.find("preview").find("images").iter("image") - ): - image = {k: v for k, v in i.attrib.items()} - image["url"] = i.text - images.append(image) - type = format.find("type").text - if type in ("presentation", "video"): - d["playbacks"][type] = { - "url": format.find("url").text, - "images": images, - } - d["start_date"] = datetime.fromtimestamp( - int(recording.find("startTime").text) / 1000.0, tz=timezone.utc - ).replace(microsecond=0) - result.append(d) - except Exception as e: - print(e) - return result - - def update_recordings(self, recording_ids, metadata): - """updateRecordings BBB API: https://docs.bigbluebutton.org/dev/api.html#updaterecordings""" - action = "updateRecordings" - meta = {f"meta_{key}": value for (key, value) in metadata.items()} - params = self.get_params_with_checksum( - action, {"recordID": ",".join(recording_ids), **meta} - ) - response = requests.get(self.get_url(action), params=params) - d = { - child.tag: child.text for child in ElementTree.fromstring(response.content) - } - return d - - def prepare_request_to_join_bbb(self, meeting_role, fullname): - """Join BBB API: https://docs.bigbluebutton.org/dev/api.html#join""" - params = { - "fullName": fullname, - "meetingID": self.meeting.meetingID, - "redirect": "true", - } - if meeting_role == "attendee": - params["role"] = "viewer" - params["guest"] = "true" - elif meeting_role == "authenticated": - params["role"] = "viewer" - elif meeting_role == "moderator": - params["role"] = "moderator" - action = "join" - params = self.get_params_with_checksum(action, params) - request = requests.Request("GET", self.get_url(action), params=params) - pr = request.prepare() - return pr - - def end(self): - action = "end" - params = self.get_params_with_checksum( - action, {"meetingID": self.meeting.meetingID} - ) - requests.get(self.get_url(action), params=params) - - -class MeetingFiles(db.Model): - id = db.Column(db.Integer, primary_key=True) - title = db.Column(db.Unicode(4096)) - url = db.Column(db.Unicode(4096)) - nc_path = db.Column(db.Unicode(4096)) - meeting_id = db.Column(db.Integer, db.ForeignKey("meeting.id"), nullable=False) - is_default = db.Column(db.Boolean, default=False) - is_downloadable = db.Column(db.Boolean, default=False) - created_at = db.Column(db.Date) - - meeting = db.relationship("Meeting", back_populates="files") - - @property - def short_title(self): - return ( - self.title - if len(self.title) < 70 - else f"{self.title[:30]}...{self.title[-30:]}" - ) - - def update(self): - db.session.commit() - - def save(self): - db.session.add(self) - db.session.commit() - - -class MeetingFilesExternal(db.Model): - id = db.Column(db.Integer, primary_key=True) - title = db.Column(db.Unicode(4096)) - nc_path = db.Column(db.Unicode(4096)) - meeting_id = db.Column(db.Integer, db.ForeignKey("meeting.id"), nullable=False) - - meeting = db.relationship("Meeting", back_populates="externalFiles") - - def update(self): - db.session.commit() - - def save(self): - db.session.add(self) - db.session.commit() - - -class Meeting(db.Model): - id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) - - user = db.relationship("User", back_populates="meetings") - files = db.relationship("MeetingFiles", back_populates="meeting") - externalFiles = db.relationship("MeetingFilesExternal", back_populates="meeting") - - # BBB params - name = db.Column(db.Unicode(150)) - attendeePW = db.Column(EncryptedType(db.Unicode(50), secret_key())) - moderatorPW = db.Column(EncryptedType(db.Unicode(50), secret_key())) - welcome = db.Column(db.UnicodeText()) - dialNumber = db.Column(db.Unicode(50)) - voiceBridge = db.Column(db.Unicode(50)) - maxParticipants = db.Column(db.Integer) - logoutUrl = db.Column(db.Unicode(250)) - record = db.Column(db.Boolean, unique=False, default=True) - duration = db.Column(db.Integer) - moderatorOnlyMessage = db.Column(db.Unicode(MODERATOR_ONLY_MESSAGE_MAXLENGTH)) - autoStartRecording = db.Column(db.Boolean, unique=False, default=True) - allowStartStopRecording = db.Column(db.Boolean, unique=False, default=True) - webcamsOnlyForModerator = db.Column(db.Boolean, unique=False, default=True) - muteOnStart = db.Column(db.Boolean, unique=False, default=True) - lockSettingsDisableCam = db.Column(db.Boolean, unique=False, default=True) - lockSettingsDisableMic = db.Column(db.Boolean, unique=False, default=True) - allowModsToUnmuteUsers = db.Column(db.Boolean, unique=False, default=False) - lockSettingsDisablePrivateChat = db.Column(db.Boolean, unique=False, default=True) - lockSettingsDisablePublicChat = db.Column(db.Boolean, unique=False, default=True) - lockSettingsDisableNote = db.Column(db.Boolean, unique=False, default=True) - guestPolicy = db.Column(db.Boolean, unique=False, default=True) - logo = db.Column(db.Unicode(200)) - user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) - - user = db.relationship("User") - - _bbb = None - - @property - def bbb(self): - if not self._bbb: - self._bbb = BBB(self) - return self._bbb - - @property - def default_file(self): - for mfile in self.files: - if mfile.is_default: - return mfile - return None - - @property - def meetingID(self): - if self.id is not None: - fid = "meeting-persistent-%i" % (self.id) - else: - fid = "meeting-vanish-%s" % (self.fake_id) - return "{}--{}".format(fid, self.user.hash if self.user else "") - - @property - def fake_id(self): - if self.id is not None: - return self.id - else: - try: - return self._fake_id - except: - return None - - @fake_id.setter - def fake_id(self, fake_value): - self._fake_id = fake_value - - @fake_id.deleter - def fake_id(self): - del self._fake_id - - def get_hash(self, role): - s = f"{self.meetingID}|{self.attendeePW}|{self.name}|{role}" - return hashlib.sha1(s.encode("utf-8")).hexdigest() - - def is_meeting_running(self): - return self.bbb.is_meeting_running() - - def create_bbb(self): - result = self.bbb.create() - if result and result["returncode"] == "SUCCESS": - if self.id is None: - self.attendeePW = result["attendeePW"] - self.moderatorPW = result["moderatorPW"] - return result if result else {} - - def save(self): - db.session.add(self) - db.session.commit() - - def delete_recordings(self, recording_ids): - return self.bbb.delete_recordings(recording_ids) - - def delete_all_recordings(self): - recordings = self.get_recordings() - if not recordings: - return {} - recording_ids = ",".join( - [recording.get("recordID", "") for recording in recordings] - ) - return self.delete_recordings(recording_ids) - - def get_recordings(self): - return self.bbb.get_recordings() - - def update_recording_name(self, recording_id, name): - return self.bbb.update_recordings( - recording_ids=[recording_id], metadata={"name": name} - ) - - def get_join_url(self, meeting_role, fullname, fullname_suffix="", create=False): - is_meeting_available = self.is_meeting_running() - should_create_room = ( - not is_meeting_available and (meeting_role == "moderator") and create - ) - if should_create_room: - d = self.create_bbb() - if "returncode" in d and d["returncode"] == "SUCCESS": - is_meeting_available = True - if is_meeting_available: - nickname = ( - f"{fullname} - {fullname_suffix}" if fullname_suffix else fullname - ) - return self.bbb.prepare_request_to_join_bbb(meeting_role, nickname).url - return url_for( - "routes.waiting_meeting", - meeting_fake_id=self.fake_id, - user_id=self.user.id, - h=self.get_hash(meeting_role), - fullname=fullname, - fullname_suffix=fullname_suffix, - ) - - def get_signin_url(self, meeting_role): - return current_app.config["SERVER_FQDN"] + url_for( - "routes.signin_meeting", - meeting_fake_id=self.fake_id, - user_id=self.user.id, - h=self.get_hash(meeting_role), - ) - - def get_mail_signin_hash(self, meeting_id, expiration_epoch): - s = f"{meeting_id}-{expiration_epoch}" - return hashlib.sha256( - s.encode("utf-8") + secret_key().encode("utf-8") - ).hexdigest() - - def get_mail_signin_url(self): - expiration = str((datetime.now() + timedelta(weeks=1)).timestamp()).split(".")[ - 0 - ] # remove milliseconds - hash_param = self.get_mail_signin_hash(self.fake_id, expiration) - return current_app.config["SERVER_FQDN"] + url_for( - "routes.signin_mail_meeting", - meeting_fake_id=self.fake_id, - expiration=expiration, - h=hash_param, - ) - - def get_data_as_dict(self, fullname, fetch_recording=False): - if self.id is None: - d = {} - else: - d = { - c.name: getattr(self, c.name) - for c in self.__table__.columns - if c.name != "slideshows" - } - if fetch_recording: - d["recordings"] = self.get_recordings() - d["running"] = self.is_meeting_running() - d["attendee_signin_url"] = self.get_signin_url("attendee") - d["moderator_signin_url"] = self.get_signin_url("moderator") - d["authenticated_attendee_signin_url"] = self.get_signin_url( - "authenticated" - ) - d["moderator_join_url"] = self.get_join_url("moderator", fullname) - d["attendee_join_url"] = self.get_join_url("attendee", fullname) - return d - - def get_role(self, hashed_role, user_id=None): - if user_id and self.user.id == user_id: - return "moderator" - elif self.get_hash("attendee") == hashed_role: - role = "attendee" - elif self.get_hash("moderator") == hashed_role: - role = "moderator" - elif self.get_hash("authenticated") == hashed_role: - role = ( - "authenticated" - if current_app.config["OIDC_ATTENDEE_ENABLED"] - else "attendee" - ) - else: - role = None - return role - - def end_bbb(self): - self.bbb.end() diff --git a/web/flaskr/routes.py b/web/flaskr/routes.py deleted file mode 100755 index ab09d6e7..00000000 --- a/web/flaskr/routes.py +++ /dev/null @@ -1,1547 +0,0 @@ -# +----------------------------------------------------------------------------+ -# | BBB-VISIO | -# +----------------------------------------------------------------------------+ -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the European Union Public License 1.2 version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. -import hashlib -import os -import random -import re -import secrets -import smtplib -import string -import uuid -from datetime import date -from datetime import datetime -from email.message import EmailMessage -from email.mime.text import MIMEText -from pathlib import Path - -import filetype -import requests -from flask import abort -from flask import Blueprint -from flask import current_app -from flask import flash -from flask import jsonify -from flask import make_response -from flask import redirect -from flask import render_template -from flask import request -from flask import send_file -from flask import send_from_directory -from flask import session -from flask import url_for -from flask_babel import lazy_gettext -from flask_pyoidc import OIDCAuthentication -from flask_pyoidc.provider_configuration import ClientMetadata -from flask_pyoidc.provider_configuration import ProviderConfiguration -from flask_pyoidc.user_session import UserSession -from flaskr.forms import EndMeetingForm -from flaskr.forms import JoinMailMeetingForm -from flaskr.forms import JoinMeetingAsRoleForm -from flaskr.forms import JoinMeetingForm -from flaskr.forms import MeetingFilesForm -from flaskr.forms import MeetingForm -from flaskr.forms import MeetingWithRecordForm -from flaskr.forms import RecordingForm -from flaskr.forms import ShowMeetingForm -from flaskr.models import db -from flaskr.models import get_or_create_user -from flaskr.models import Meeting -from flaskr.models import MeetingFiles -from flaskr.models import MeetingFilesExternal -from flaskr.models import User -from sqlalchemy import exc -from webdav3.client import Client as webdavClient -from webdav3.exceptions import WebDavException -from werkzeug.utils import secure_filename - -from .common.extensions import cache -from .templates.content import FAQ_CONTENT - - -bp = Blueprint("routes", __name__) - - -user_provider_configuration = ProviderConfiguration( - issuer=current_app.config["OIDC_ISSUER"], - userinfo_http_method=current_app.config["OIDC_USERINFO_HTTP_METHOD"], - client_metadata=ClientMetadata( - client_id=current_app.config["OIDC_CLIENT_ID"], - client_secret=current_app.config["OIDC_CLIENT_SECRET"], - token_endpoint_auth_method=current_app.config["OIDC_CLIENT_AUTH_METHOD"], - introspection_endpoint_auth_method=current_app.config.get( - "OIDC_INTROSPECTION_AUTH_METHOD" - ), - post_logout_redirect_uris=[f'{current_app.config.get("SERVER_FQDN")}/logout'], - ), - auth_request_params={"scope": current_app.config["OIDC_SCOPES"]}, -) -attendee_provider_configuration = ProviderConfiguration( - issuer=current_app.config.get("OIDC_ATTENDEE_ISSUER"), - userinfo_http_method=current_app.config.get("OIDC_ATTENDEE_USERINFO_HTTP_METHOD"), - client_metadata=ClientMetadata( - client_id=current_app.config.get("OIDC_ATTENDEE_CLIENT_ID"), - client_secret=current_app.config.get("OIDC_ATTENDEE_CLIENT_SECRET"), - token_endpoint_auth_method=current_app.config.get( - "OIDC_ATTENDEE_CLIENT_AUTH_METHOD" - ), - introspection_endpoint_auth_method=current_app.config.get( - "OIDC_ATTENDEE_INTROSPECTION_AUTH_METHOD", - ), - post_logout_redirect_uris=[f'{current_app.config.get("SERVER_FQDN")}/logout'], - ), - auth_request_params={"scope": current_app.config["OIDC_ATTENDEE_SCOPES"]}, -) - -auth = OIDCAuthentication( - { - "default": user_provider_configuration, - "attendee": attendee_provider_configuration, - }, - current_app, -) - - -def is_accepted_email(email): - for regex in current_app.config["EMAIL_WHITELIST"]: - if re.search(regex, email): - return True - return False - - -def is_valid_email(email): - if not email or not re.search( - r"^([a-zA-Z0-9_\-\.']+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$", email - ): - return False - return True - - -def get_random_alphanumeric_string(length): - letters_and_digits = string.ascii_letters + string.digits - result_str = "".join(random.choice(letters_and_digits) for i in range(length)) - return result_str - - -def get_quick_meeting_from_fake_id(fake_id): - try: - user_id_str, random_string = fake_id.split("-") - user = User.query.get(int(user_id_str)) - return get_quick_meeting_from_user_and_random_string(user, random_string) - except: - return None - - -def get_quick_meeting_from_user_and_random_string(user, random_string=None): - if random_string is None: - random_string = get_random_alphanumeric_string(8) - m = Meeting() - m.duration = current_app.config["DEFAULT_MEETING_DURATION"] - m.user = user - m.name = current_app.config["QUICK_MEETING_DEFAULT_NAME"] - m.fake_id = random_string - m.moderatorPW = f"{user.hash}-{random_string}" - m.attendeePW = f"{random_string}-{random_string}" - m.moderatorOnlyMessage = current_app.config[ - "QUICK_MEETING_MODERATOR_WELCOME_MESSAGE" - ] - m.logoutUrl = ( - current_app.config["QUICK_MEETING_LOGOUT_URL"] - or current_app.config["SERVER_FQDN"] - ) - return m - - -def get_meeting_from_meeting_id_and_user_id(meeting_fake_id, user_id): - if meeting_fake_id.isdigit(): - try: - meeting = Meeting.query.get(meeting_fake_id) - except: - try: - user = User.query.get(user_id) - meeting = get_quick_meeting_from_user_and_random_string( - user, random_string=meeting_fake_id - ) - except: - meeting = None - else: - try: - user = User.query.get(user_id) - meeting = get_quick_meeting_from_user_and_random_string( - user, random_string=meeting_fake_id - ) - except: - meeting = None - - return meeting - - -def get_fake_user(): - return User(email=current_app.config["SMTP_FROM"]) - - -def get_current_user(): - user_session = UserSession(session) - current_app.logger.debug( - f"User authenticated with token: {user_session.access_token}" - ) - info = user_session.userinfo - return get_or_create_user(info) - - -def has_user_session(): - user_session = UserSession(dict(session), "default") - return user_session.is_authenticated() - - -@bp.context_processor -def global_processor(): - if has_user_session(): - user = get_current_user() - return { - "user": user, - "fullname": user.fullname, - } - else: - return { - "user": None, - "fullname": "", - } - - -def add_mailto_links(meeting_data): - d = meeting_data - d["moderator_mailto_href"] = render_template( - "meeting/mailto/mail_href.txt", meeting=meeting_data, role="moderator" - ).replace("\n", "%0D%0A") - d["attendee_mailto_href"] = render_template( - "meeting/mailto/mail_href.txt", meeting=meeting_data, role="attendee" - ).replace("\n", "%0D%0A") - return d - - -@cache.cached( - timeout=current_app.config["STATS_CACHE_DURATION"], key_prefix="meetings_stats" -) -def get_meetings_stats(): - response = requests.get(current_app.config["STATS_URL"]) - if response.status_code != 200: - return None - try: - stats_array = response.content.decode(encoding="utf-8").split("\n") - stats_array = [row.split(",") for row in stats_array] - participantCount = int(stats_array[current_app.config["STATS_INDEX"]][1]) - runningCount = int(stats_array[current_app.config["STATS_INDEX"]][2]) - except Exception: - return None - - result = {"participantCount": participantCount, "runningCount": runningCount} - return result - - -@bp.route("/api/meetings", methods=["GET"]) -@auth.token_auth("default") -def api_meetings(): - client = auth.clients["default"] - access_token = auth._parse_access_token(request) - userinfo = client.userinfo_request(access_token).to_dict() - user = get_or_create_user(userinfo) - return { - "meetings": [ - { - "name": m.name, - "moderator_url": m.get_signin_url("moderator"), - "attendee_url": m.get_signin_url("attendee"), - } - for m in user.meetings - ] - } - - -# called by NextcloudfilePicker when documents should be added to a running room: -@bp.route("/meeting/files//insertDocuments", methods=["POST"]) -@auth.oidc_auth("default") -def insertDocuments(meeting_id): - from flask import request - - get_current_user() - meeting = Meeting.query.get(meeting_id) - files_title = request.get_json() - secret_key = current_app.config["SECRET_KEY"] - - xml_beg = " " - xml_end = " " - xml_mid = "" - # @FIX We ONLY send the documents that have been uploaded NOW, not ALL of them for this meetingid ;) - for cur_file in files_title: - id = add_external_meeting_file_nextcloud(cur_file, meeting_id) - filehash = hashlib.sha1( - f"{secret_key}-1-{id}-{secret_key}".encode() - ).hexdigest() - xml_mid += f"" - - bbb_endpoint = current_app.config["BIGBLUEBUTTON_ENDPOINT"] - xml = xml_beg + xml_mid + xml_end - params = {"meetingID": meeting.meetingID} - request = requests.Request( - "POST", - "{}/{}".format(current_app.config["BIGBLUEBUTTON_ENDPOINT"], "insertDocument"), - params=params, - ) - pr = request.prepare() - bigbluebutton_secret = current_app.config["BIGBLUEBUTTON_SECRET"] - s = "{}{}".format( - pr.url.replace("?", "").replace( - current_app.config["BIGBLUEBUTTON_ENDPOINT"] + "/", "" - ), - bigbluebutton_secret, - ) - params["checksum"] = hashlib.sha1(s.encode("utf-8")).hexdigest() - requests.post( - f"{bbb_endpoint}/insertDocument", - headers={"Content-Type": "application/xml"}, - data=xml, - params=params, - ) - return jsonify(status=200, msg="SUCCESS") - - -@bp.route("/mentions_legales") -def mentions_legales(): - return render_template( - "footer/mentions_legales.html", - service_title=current_app.config["SERVICE_TITLE"], - service_tagline=current_app.config["SERVICE_TAGLINE"], - ) - - -@bp.route("/cgu") -def cgu(): - return render_template( - "footer/cgu.html", - service_title=current_app.config["SERVICE_TITLE"], - service_tagline=current_app.config["SERVICE_TAGLINE"], - ) - - -@bp.route("/donnees_personnelles") -def donnees_personnelles(): - return render_template( - "footer/donnees_personnelles.html", - service_title=current_app.config["SERVICE_TITLE"], - service_tagline=current_app.config["SERVICE_TAGLINE"], - ) - - -@bp.route("/accessibilite") -def accessibilite(): - return render_template( - "footer/accessibilite.html", - service_title=current_app.config["SERVICE_TITLE"], - service_tagline=current_app.config["SERVICE_TAGLINE"], - ) - - -@bp.route("/documentation") -def documentation(): - if current_app.config["DOCUMENTATION_LINK"]["is_external"]: - return redirect(current_app.config["DOCUMENTATION_LINK"]["url"]) - return render_template( - "footer/documentation.html", - ) - - -@bp.route("/faq") -def faq(): - return render_template( - "faq.html", - contents=FAQ_CONTENT, - ) - - -@bp.route("/") -def index(): - if has_user_session(): - return redirect(url_for("routes.welcome")) - else: - return redirect(url_for("routes.home")) - - -@bp.route("/home") -def home(): - if has_user_session(): - return redirect(url_for("routes.welcome")) - - stats = get_meetings_stats() - return render_template( - "index.html", - stats=stats, - mail_meeting=current_app.config["MAIL_MEETING"], - max_participants=current_app.config["MAX_PARTICIPANTS"], - ) - - -@bp.route("/welcome") -@auth.oidc_auth("default") -def welcome(): - user = get_current_user() - stats = get_meetings_stats() - return render_template( - "welcome.html", - title=current_app.config["TITLE"], - stats=stats, - max_participants=current_app.config["MAX_PARTICIPANTS"], - meetings=[ - add_mailto_links(m.get_data_as_dict(user.fullname)) for m in user.meetings - ], - can_create_meetings=user.can_create_meetings, - max_meetings_per_user=current_app.config["MAX_MEETINGS_PER_USER"], - mailto=current_app.config["MAILTO_LINKS"], - quick_meeting=current_app.config["QUICK_MEETING"], - shorty=current_app.config["SHORTY"], - file_sharing=current_app.config["FILE_SHARING"], - clipboard=current_app.config["CLIPBOARD"], - recording=current_app.config["RECORDING"], - ) - - -def get_mail_meeting(random_string=None): - # only used for mail meeting - if random_string is None: - random_string = get_random_alphanumeric_string(8) - m = Meeting() - m.duration = current_app.config["DEFAULT_MEETING_DURATION"] - m.name = current_app.config["QUICK_MEETING_DEFAULT_NAME"] - m.moderatorPW = "{}-{}".format( - random_string, - random_string, - ) # it is only usefull for bbb - m.fake_id = random_string - m.moderatorOnlyMessage = current_app.config["MAIL_MODERATOR_WELCOME_MESSAGE"] - m.logoutUrl = ( - current_app.config["QUICK_MEETING_LOGOUT_URL"] - or current_app.config["SERVER_FQDN"] - ) - return m - - -@bp.route("/meeting/mail", methods=["POST"]) -def quick_mail_meeting(): - #### Almost the same as quick meeting but we do not redirect to join - email = request.form.get("mail") - if not is_valid_email(email): - flash( - lazy_gettext( - "Courriel invalide. Avez vous bien tapé votre email ? Vous pouvez réessayer." - ), - "error_login", - ) - return redirect(url_for("routes.index")) - if not is_accepted_email(email): - flash( - lazy_gettext( - "Ce courriel ne correspond pas à un service de l'État. Si vous appartenez à un service de l'État mais votre courriel n'est pas reconnu par Webinaire, contactez-nous pour que nous le rajoutions!" - ), - "error_login", - ) - return redirect(url_for("routes.index")) - user = User( - id=email - ) # this user can probably be removed if we created adock function - m = get_quick_meeting_from_user_and_random_string(user) - _send_mail(m, email) - flash( - lazy_gettext("Vous avez reçu un courriel pour vous connecter"), "success_login" - ) - return redirect(url_for("routes.index")) - - -def _send_mail(meeting, to_email): - smtp_from = current_app.config["SMTP_FROM"] - smtp_host = current_app.config["SMTP_HOST"] - smtp_port = current_app.config["SMTP_PORT"] - smtp_ssl = current_app.config["SMTP_SSL"] - smtp_username = current_app.config["SMTP_USERNAME"] - smtp_password = current_app.config["SMTP_PASSWORD"] - wordings = current_app.config["WORDINGS"] - msg = EmailMessage() - content = render_template( - "meeting/mailto/mail_quick_meeting_body.txt", - role="moderator", - moderator_mail_signin_url=meeting.get_mail_signin_url(), - welcome_url=current_app.config["SERVER_FQDN"] + "/welcome", - meeting=meeting, - ) - msg["Subject"] = wordings["meeting_mail_subject"] - msg["From"] = smtp_from - msg["To"] = to_email - html = MIMEText(content, "html") - msg.make_mixed() # This converts the message to multipart/mixed - msg.attach(html) - - if smtp_ssl: - s = smtplib.SMTP_SSL(smtp_host, smtp_port) - else: - s = smtplib.SMTP(smtp_host, smtp_port) - if smtp_username: - # in dev, no need for username - s.login(smtp_username, smtp_password) - s.send_message(msg) - s.quit() - - -@bp.route("/meeting/quick", methods=["GET"]) -@auth.oidc_auth("default") -def quick_meeting(): - user = get_current_user() - fullname = user.fullname - m = get_quick_meeting_from_user_and_random_string(user) - return redirect(m.get_join_url("moderator", fullname, create=True)) - - -@bp.route("/meeting/show/", methods=["GET"]) -@auth.oidc_auth("default") -def show_meeting(meeting_id): - form = ShowMeetingForm(data={"meeting_id": meeting_id}) - if not form.validate(): - flash( - lazy_gettext("Vous ne pouvez pas voir cet élément (identifiant incorrect)"), - "warning", - ) - return redirect(url_for("routes.welcome")) - user = get_current_user() - meeting = Meeting.query.get(meeting_id) - if meeting.user_id == user.id: - return render_template( - "meeting/show.html", - meeting=add_mailto_links(meeting.get_data_as_dict(user.fullname)), - ) - flash(lazy_gettext("Vous ne pouvez pas consulter cet élément"), "warning") - return redirect(url_for("routes.welcome")) - - -@bp.route("/meeting/recordings/", methods=["GET"]) -@auth.oidc_auth("default") -def show_meeting_recording(meeting_id): - form = ShowMeetingForm(data={"meeting_id": meeting_id}) - if not form.validate(): - flash( - lazy_gettext("Vous ne pouvez pas voir cet élément (identifiant incorrect)"), - "warning", - ) - return redirect(url_for("routes.welcome")) - user = get_current_user() - meeting = Meeting.query.get(meeting_id) - if meeting.user_id == user.id: - meeting_dict = meeting.get_data_as_dict(user.fullname, fetch_recording=True) - form = RecordingForm() - return render_template( - "meeting/recordings.html", - meeting=add_mailto_links(meeting_dict), - form=form, - ) - flash(lazy_gettext("Vous ne pouvez pas consulter cet élément"), "warning") - return redirect(url_for("routes.welcome")) - - -@bp.route("/meeting//recordings/", methods=["POST"]) -@auth.oidc_auth("default") -def update_recording_name(meeting_id, recording_id): - user = get_current_user() - meeting = Meeting.query.get(meeting_id) or abort(404) - if meeting.user_id == user.id: - form = RecordingForm(request.form) - form.validate() or abort(403) - result = meeting.update_recording_name(recording_id, form.data["name"]) - return_code = result.get("returncode") - if return_code == "SUCCESS": - flash("Enregistrement renommé", "success") - else: - message = result.get("message", "") - flash( - "Nous n'avons pas pu modifier cet enregistrement : {code}, {message}".format( - code=return_code, message=message - ), - "error", - ) - else: - flash("Vous ne pouvez pas modifier cet enregistrement", "error") - return redirect(url_for("routes.show_meeting_recording", meeting_id=meeting_id)) - - -@bp.route("/meeting/new", methods=["GET"]) -@auth.oidc_auth("default") -def new_meeting(): - user = get_current_user() - if not user.can_create_meetings: - return redirect(url_for("routes.welcome")) - - form = MeetingWithRecordForm() if current_app.config["RECORDING"] else MeetingForm() - - return render_template( - "meeting/wizard.html", - meeting=None, - form=form, - recording=current_app.config["RECORDING"], - ) - - -@bp.route("/meeting/edit/", methods=["GET"]) -@auth.oidc_auth("default") -def edit_meeting(meeting_id): - user = get_current_user() - meeting = Meeting.query.get(meeting_id) - - form = ( - MeetingWithRecordForm(obj=meeting) - if current_app.config["RECORDING"] - else MeetingForm(obj=meeting) - ) - if meeting and meeting.user_id == user.id: - return render_template( - "meeting/wizard.html", - meeting=meeting, - form=form, - recording=current_app.config["RECORDING"], - ) - flash("Vous ne pouvez pas modifier cet élément", "warning") - return redirect(url_for("routes.welcome")) - - -@bp.route("/meeting/files/", methods=["GET"]) -@auth.oidc_auth("default") -def edit_meeting_files(meeting_id): - user = get_current_user() - meeting = Meeting.query.get(meeting_id) - - form = MeetingFilesForm() - - if current_app.config["FILE_SHARING"]: - # we test webdav connection here, with a simple 'list' command - if user.nc_login and user.nc_token and user.nc_locator: - options = { - "webdav_root": f"/remote.php/dav/files/{user.nc_login}/", - "webdav_hostname": user.nc_locator, - "webdav_verbose": True, - "webdav_token": user.nc_token, - } - try: - client = webdavClient(options) - client.list() - except WebDavException as exception: - print("webdav call failed, we disable user data", flush=True) - print(exception, flush=True) - user.disable_nextcloud() - - if user is not None and meeting.user_id == user.id: - return render_template( - "meeting/filesform.html", - meeting=meeting, - form=form, - fqdn=current_app.config["SERVER_FQDN"], - beta=current_app.config["BETA"], - ) - flash(lazy_gettext("Vous ne pouvez pas modifier cet élément"), "warning") - return redirect(url_for("routes.welcome")) - - -@bp.route("/meeting/files//", methods=["GET"]) -@auth.oidc_auth("default") -def download_meeting_files(meeting_id, file_id): - user = get_current_user() - meeting = Meeting.query.get(meeting_id) - - TMP_DOWNLOAD_DIR = current_app.config["TMP_DOWNLOAD_DIR"] - Path(TMP_DOWNLOAD_DIR).mkdir(parents=True, exist_ok=True) - tmpName = f'{current_app.config["TMP_DOWNLOAD_DIR"]}{secrets.token_urlsafe(32)}' - fileToSend = None - if user is not None and meeting.user_id == user.id: - for curFile in meeting.files: - if curFile.id == file_id: - fileToSend = curFile - break - if not fileToSend: - return jsonify(status=404, msg="file not found") - if curFile.url: - response = requests.get(curFile.url) - open(tmpName, "wb").write(response.content) - return send_file(tmpName, as_attachment=True, download_name=curFile.title) - else: - # get file from nextcloud WEBDAV and send it - try: - davUser = { - "nc_locator": user.nc_locator, - "nc_login": user.nc_login, - "nc_token": user.nc_token, - } - options = { - "webdav_root": f"/remote.php/dav/files/{davUser['nc_login']}/", - "webdav_hostname": davUser["nc_locator"], - "webdav_verbose": True, - "webdav_token": davUser["nc_token"], - } - client = webdavClient(options) - kwargs = { - "remote_path": curFile.nc_path, - "local_path": f"{tmpName}", - } - client.download_sync(**kwargs) - return send_file( - tmpName, as_attachment=True, download_name=curFile.title - ) - except WebDavException as exception: - user.disable_nextcloud() - print("webdav call encountered following exception : %s" % exception) - flash("Le fichier ne semble pas accessible", "error") - return redirect(url_for("routes.welcome")) - return redirect(url_for("routes.welcome")) - - -@bp.route("/meeting/files//toggledownload", methods=["POST"]) -@auth.oidc_auth("default") -def toggledownload(meeting_id): - user = get_current_user() - data = request.get_json() - - if user is None: - return redirect(url_for("routes.welcome")) - meeting = Meeting.query.get(meeting_id) - meeting_file = MeetingFiles.query.get(data["id"]) - if meeting_file is not None and meeting.user_id == user.id: - meeting_file.is_downloadable = data["value"] - meeting_file.save() - - return jsonify(status=200, id=data["id"]) - return redirect(url_for("routes.welcome")) - - -@bp.route("/meeting/files//default", methods=["POST"]) -@auth.oidc_auth("default") -def set_meeting_default_file(meeting_id): - user = get_current_user() - data = request.get_json() - - meeting = Meeting.query.get(meeting_id) - if meeting.user_id == user.id: - actual_default_file = meeting.default_file - if actual_default_file: - actual_default_file.is_default = False - - meetingFile = MeetingFiles() - meeting_file = meetingFile.query.get(data["id"]) - meeting_file.is_default = True - - if actual_default_file: - actual_default_file.save() - meeting_file.save() - - return jsonify(status=200, id=data["id"]) - - -def removeDropzoneFile(absolutePath): - os.remove(absolutePath) - - -# called when a file has been uploaded : send it to nextcloud -def add_meeting_file_dropzone(title, meeting_id, is_default): - user = get_current_user() - # should be in /tmp/visioagent/dropzone/USER_ID-TITLE - DROPZONE_DIR = os.path.join(current_app.config["UPLOAD_DIR"], "dropzone") - Path(DROPZONE_DIR).mkdir(parents=True, exist_ok=True) - dropzone_path = os.path.join(DROPZONE_DIR, f"{user.id}-{meeting_id}-{title}") - metadata = os.stat(dropzone_path) - if int(metadata.st_size) > int(current_app.config["MAX_SIZE_UPLOAD"]): - return jsonify( - status=500, - isfrom="dropzone", - msg=f"Fichier {title} TROP VOLUMINEUX, ne pas dépasser 20Mo", - ) - - options = { - "webdav_root": f"/remote.php/dav/files/{user.nc_login}/", - "webdav_hostname": user.nc_locator, - "webdav_verbose": True, - "webdav_token": user.nc_token, - } - try: - client = webdavClient(options) - client.mkdir("visio-agents") # does not fail if dir already exists - # Upload resource - nc_path = os.path.join("/visio-agents/" + title) - kwargs = { - "remote_path": nc_path, - "local_path": dropzone_path, - } - client.upload_sync(**kwargs) - - meetingFile = MeetingFiles() - meetingFile.nc_path = nc_path - - meetingFile.title = title - meetingFile.created_at = date.today() - meetingFile.meeting_id = meeting_id - except WebDavException as exception: - user.disable_nextcloud() - print("ERROR %s" % exception) - return jsonify( - status=500, isfrom="dropzone", msg="La connexion avec Nextcloud est rompue" - ) - - try: - # test for is_default-file absence at the latest time possible - meeting = Meeting.query.get(meeting_id) - if len(meeting.files) == 0 and not meeting.default_file: - meetingFile.is_default = True - else: - meetingFile.is_default = False - - meetingFile.save() - current_app.config["SECRET_KEY"] - meetingFile.update() - # file has been associated AND uploaded to nextcloud, we can safely remove it from visio-agent tmp directory - removeDropzoneFile(dropzone_path) - return jsonify( - status=200, - isfrom="dropzone", - isDefault=is_default, - title=meetingFile.short_title, - id=meetingFile.id, - created_at=meetingFile.created_at.strftime( - current_app.config["TIME_FORMAT"] - ), - ) - except exc.SQLAlchemyError as error: - print("ERROR %s" % error) - return jsonify(status=500, isfrom="dropzone", msg="File already exists") - - -def add_meeting_file_URL(url, meeting_id, is_default): - get_current_user() - title = url.rsplit("/", 1)[-1] - - # test MAX_SIZE_UPLOAD for 20Mo - metadata = requests.head(url) - if not metadata.ok: - return jsonify( - status=404, - isfrom="url", - msg=f"Fichier {title} NON DISPONIBLE, veuillez vérifier l'URL proposée", - ) - - if int(metadata.headers["content-length"]) > int( - current_app.config["MAX_SIZE_UPLOAD"] - ): - return jsonify( - status=500, - isfrom="url", - msg=f"Fichier {title} TROP VOLUMINEUX, ne pas dépasser 20Mo", - ) - - meetingFile = MeetingFiles() - - meetingFile.title = title - meetingFile.created_at = date.today() - meetingFile.meeting_id = meeting_id - meetingFile.url = url - meetingFile.is_default = is_default - - requests.get(url) - - try: - meetingFile.save() - return jsonify( - status=200, - isfrom="url", - isDefault=is_default, - title=meetingFile.short_title, - id=meetingFile.id, - created_at=meetingFile.created_at.strftime( - current_app.config["TIME_FORMAT"] - ), - ) - except exc.SQLAlchemyError as error: - print("ERROR %s" % error) - return jsonify(status=500, isfrom="url", msg="File already exists") - - -def add_meeting_file_nextcloud(path, meeting_id, is_default): - user = get_current_user() - - options = { - "webdav_root": f"/remote.php/dav/files/{user.nc_login}/", - "webdav_hostname": user.nc_locator, - "webdav_verbose": True, - "webdav_token": user.nc_token, - } - try: - client = webdavClient(options) - metadata = client.info(path) - except WebDavException: - user.disable_nextcloud() - return jsonify( - status=500, - isfrom="nextcloud", - msg="La connexion avec Nextcloud semble rompue", - ) - if int(metadata["size"]) > int(current_app.config["MAX_SIZE_UPLOAD"]): - return jsonify( - status=500, - isfrom="nextcloud", - msg=f"Fichier {path} TROP VOLUMINEUX, ne pas dépasser 20Mo", - ) - - meetingFile = MeetingFiles() - - meetingFile.title = path - meetingFile.created_at = date.today() - meetingFile.meeting_id = meeting_id - meetingFile.nc_path = path - meetingFile.is_default = is_default - current_app.config["SECRET_KEY"] - - try: - meetingFile.save() - return jsonify( - status=200, - isfrom="nextcloud", - isDefault=is_default, - title=meetingFile.short_title, - id=meetingFile.id, - created_at=meetingFile.created_at.strftime( - current_app.config["TIME_FORMAT"] - ), - ) - except exc.SQLAlchemyError as error: - print("ERROR %s" % error) - return jsonify(status=500, isfrom="nextcloud", msg="File already exists") - - -def add_external_meeting_file_nextcloud(path, meeting_id): - get_current_user() - - externalMeetingFile = MeetingFilesExternal() - - externalMeetingFile.title = path - externalMeetingFile.meeting_id = meeting_id - externalMeetingFile.nc_path = path - - externalMeetingFile.save() - return externalMeetingFile.id - - -@bp.route("/meeting/files/", methods=["POST"]) -@auth.oidc_auth("default") -def add_meeting_files(meeting_id): - user = get_current_user() - meeting = Meeting.query.get(meeting_id) - - data = request.get_json() - is_default = False - if len(meeting.files) == 0: - is_default = True - if meeting.user_id == user.id: - print(data) - if data["from"] == "nextcloud": - print("associating meeting with file from nextcloud") - return add_meeting_file_nextcloud(data["value"], meeting_id, is_default) - if data["from"] == "URL": - print("associating meeting with file from url") - return add_meeting_file_URL(data["value"], meeting_id, is_default) - if data["from"] == "dropzone": - print("associating meeting with file from dropzone") - return add_meeting_file_dropzone( - secure_filename(data["value"]), meeting_id, is_default - ) - else: - return make_response(jsonify("no file provided"), 200) - - return jsonify(status=500, msg="Vous ne pouvez pas modifier cet élément") - - -# for dropzone multiple files uploading at once -@bp.route("/meeting/files//dropzone", methods=["POST"]) -@auth.oidc_auth("default") -def add_dropzone_files(meeting_id): - user = get_current_user() - - meeting = Meeting.query.get(meeting_id) - if meeting and user and meeting.user_id == user.id: - return upload(user, meeting_id, request.files["dropzoneFiles"]) - else: - flash("Traitement de requête impossible", "error") - return redirect(url_for("routes.welcome")) - - -# for dropzone chunk file by file validation -# shamelessly taken from https://stackoverflow.com/questions/44727052/handling-large-file-uploads-with-flask -def upload(user, meeting_id, file): - DROPZONE_DIR = os.path.join(current_app.config["UPLOAD_DIR"], "dropzone") - Path(DROPZONE_DIR).mkdir(parents=True, exist_ok=True) - save_path = os.path.join( - DROPZONE_DIR, secure_filename(f"{user.id}-{meeting_id}-{file.filename}") - ) - current_chunk = int(request.form["dzchunkindex"]) - - # If the file already exists it's ok if we are appending to it, - # but not if it's new file that would overwrite the existing one - if os.path.exists(save_path) and current_chunk == 0: - # 400 and 500s will tell dropzone that an error occurred and show an error - return make_response(("File already exists", 500)) - - try: - with open(save_path, "ab") as f: - f.seek(int(request.form["dzchunkbyteoffset"])) - f.write(file.stream.read()) - except OSError: - return make_response( - ("Not sure why, but we couldn't write the file to disk", 500) - ) - - total_chunks = int(request.form["dztotalchunkcount"]) - - if current_chunk + 1 == total_chunks: - # This was the last chunk, the file should be complete and the size we expect - mimetype = filetype.guess(save_path) - if mimetype.mime not in current_app.config["ALLOWED_MIME_TYPES_SERVER_SIDE"]: - return make_response(("Filetype not allowed", 500)) - if os.path.getsize(save_path) != int(request.form["dztotalfilesize"]): - return make_response(("Size mismatch", 500)) - - return make_response(("Chunk upload successful", 200)) - - -@bp.route("/meeting/files/delete", methods=["POST"]) -@auth.oidc_auth("default") -def delete_meeting_file(): - user = get_current_user() - data = request.get_json() - meeting_file_id = data["id"] - meetingFile = MeetingFiles() - meeting_file = meetingFile.query.get(meeting_file_id) - meeting = Meeting() - cur_meeting = meeting.query.get(meeting_file.meeting_id) - - if cur_meeting.user_id == user.id: - db.session.delete(meeting_file) - db.session.commit() - newDefaultId = None - if meeting_file.is_default: - cur_meeting = meeting.query.get(meeting_file.meeting_id) - if len(cur_meeting.files) > 0: - cur_meeting.files[0].is_default = True - newDefaultId = cur_meeting.files[0].id - cur_meeting.save() - return jsonify( - status=200, - newDefaultId=newDefaultId, - id=data["id"], - msg="Fichier supprimé avec succès", - ) - return jsonify( - status=500, id=data["id"], msg="Vous ne pouvez pas supprimer cet élément" - ) - - -@bp.route("/meeting/save", methods=["POST"]) -@auth.oidc_auth("default") -def save_meeting(): - user = get_current_user() - form = ( - MeetingWithRecordForm(request.form) - if current_app.config["RECORDING"] - else MeetingForm(request.form) - ) - - is_new_meeting = not form.data["id"] - if not user.can_create_meetings and is_new_meeting: - return redirect(url_for("routes.welcome")) - - if not form.validate(): - flash("Le formulaire contient des erreurs", "error") - return render_template( - "meeting/wizard.html", - meeting=None if is_new_meeting else Meeting.query.get(form.id.data), - form=form, - recording=current_app.config["RECORDING"], - ) - - if is_new_meeting: - meeting = Meeting() - meeting.user = user - else: - meeting_id = form.data["id"] - meeting = Meeting.query.get(meeting_id) - del form.id - del form.name - if form.data.get("allowStartStopRecording") or form.data.get("autoStartRecording"): - meeting.record = True - else: - meeting.record = False - form.populate_obj(meeting) - meeting.save() - flash( - lazy_gettext( - "%(meeting_name)s modifications prises en compte", meeting_name=meeting.name - ), - "success", - ) - - if meeting.is_meeting_running(): - EndMeetingForm() - EndMeetingForm.meeting_id.data = meeting.id - return render_template( - "meeting/end.html", - meeting=meeting, - form=EndMeetingForm(data={"meeting_id": meeting_id}), - ) - return redirect(url_for("routes.welcome")) - - -@bp.route("/meeting/end", methods=["POST"]) -@auth.oidc_auth("default") -def end_meeting(): - user = get_current_user() - form = EndMeetingForm(request.form) - - meeting_id = form.data["meeting_id"] - meeting = Meeting.query.get(meeting_id) or abort(404) - - if user == meeting.user: - meeting.end_bbb() - flash( - f"{current_app.config['WORDING_MEETING'].capitalize()} « {meeting.name} » terminé(e)", - "success", - ) - return redirect(url_for("routes.welcome")) - - -@bp.route("/meeting/create/", methods=["GET"]) -@auth.oidc_auth("default") -def create_meeting(meeting_id): - user = get_current_user() - m = Meeting.query.get(meeting_id) - if m.user_id == user.id: - m.create_bbb() - m.save() - return redirect(url_for("routes.welcome")) - - -# draft for insertDocument calls to BBB API -# @TODO: can we remove this def entirely? -@bp.route("/insertDoc/", methods=["GET"]) -def insertDoc(token): - # select good file from token - # get file through NC credentials - HOW POSSIBLE ? - # return file as response to BBB server - - m = MeetingFiles.query.filter_by(download_hash=token).one() - secret_key = current_app.config["SECRET_KEY"] - if ( - m - or m.token - != hashlib.sha1(f"{secret_key}{m.id}{secret_key}".encode()).hexdigest() - ): - make_response("NOT OK", 500) - - params = {"meetingID": m.meeting.meetingID} - action = "insertDocument" - req = requests.Request( - "POST", - "{}/{}".format(current_app.config["BIGBLUEBUTTON_ENDPOINT"], action), - params=params, - ) - headers = {"Content-Type": "application/xml"} - pr = req.prepare() - bigbluebutton_secret = current_app.config["BIGBLUEBUTTON_SECRET"] - s = "{}{}".format( - pr.url.replace("?", "").replace( - current_app.config["BIGBLUEBUTTON_ENDPOINT"] + "/", "" - ), - bigbluebutton_secret, - ) - params["checksum"] = hashlib.sha1(s.encode("utf-8")).hexdigest() - - # xml now use - xml = f" " - - requests.post( - f"{current_app.config['BIGBLUEBUTTON_ENDPOINT']}/insertDocument", - data=xml, - headers=headers, - params=params, - ) - - return make_response("ok", 200) - - -@bp.route("/meeting//externalUpload") -@auth.oidc_auth("default") -def externalUpload(meeting_id): - user = get_current_user() - meeting = Meeting.query.get(meeting_id) - if ( - meeting is not None - and meeting.is_meeting_running() is True - and user is not None - and meeting.user_id == user.id - ): - return render_template("meeting/externalUpload.html", meeting=meeting) - else: - return redirect(url_for("routes.welcome")) - - -@bp.route("/ncdownload///", methods=["GET"]) -# @auth.token_auth(provider_name="default") - must be accessible by BBB serveur, so no auth -def ncdownload(isexternal, mfid, mftoken): - secret_key = current_app.config["SECRET_KEY"] - # select good file from token - # get file through NC credentials - HOW POSSIBLE ? - # return file as response to BBB server - # isexternal tells if the file has been chosen earlier from the visio-agent interface (0) or if it has been uploaded from BBB itself (1) - if str(isexternal) == "0": - isexternal = "0" - meeting_file = MeetingFiles.query.filter_by(id=mfid).one_or_none() - else: - isexternal = "1" - meeting_file = MeetingFilesExternal.query.filter_by(id=mfid).one_or_none() - - if not meeting_file: - return make_response("Bad token provided, no file matching", 404) - - # the hash token consist of the sha1 of "secret key - 0/1 (internal/external) - id in the DB - secret key" - if ( - mftoken - != hashlib.sha1( - f"{secret_key}-{isexternal}-{mfid}-{secret_key}".encode() - ).hexdigest() - ): - return make_response("Bad token provided, no file matching", 404) - - # download the file using webdavClient from the Nextcloud to a temporary folder (that will need cleaning) - options = { - "webdav_root": f"/remote.php/dav/files/{meeting_file.meeting.user.nc_login}/", - "webdav_hostname": meeting_file.meeting.user.nc_locator, - "webdav_verbose": True, - "webdav_token": meeting_file.meeting.user.nc_token, - } - try: - client = webdavClient(options) - TMP_DOWNLOAD_DIR = current_app.config["TMP_DOWNLOAD_DIR"] - Path(TMP_DOWNLOAD_DIR).mkdir(parents=True, exist_ok=True) - uniqfile = str(uuid.uuid4()) - tmpName = f"{TMP_DOWNLOAD_DIR}{uniqfile}" - kwargs = { - "remote_path": meeting_file.nc_path, - "local_path": tmpName, - } - client.download_sync(**kwargs) - except WebDavException: - meeting_file.meeting.user.disable_nextcloud() - return jsonify(status=500, msg="La connexion avec Nextcloud semble rompue") - # send the downloaded file to the BBB: - return send_from_directory(TMP_DOWNLOAD_DIR, uniqfile) - - -@bp.route( - "/meeting/signinmail//expiration//hash/", - methods=["GET"], -) -def signin_mail_meeting(meeting_fake_id, expiration, h): - meeting = get_mail_meeting(meeting_fake_id) - wordings = current_app.config["WORDINGS"] - - if meeting is None: - flash( - lazy_gettext( - "Aucune %(meeting_label)s ne correspond à ces paramètres", - meeting_label=wordings["meeting_label"], - ), - "success", - ) - return redirect(url_for("routes.index")) - - hash_matches = meeting.get_mail_signin_hash(meeting_fake_id, expiration) == h - if not hash_matches: - flash(lazy_gettext("Lien invalide"), "error") - return redirect(url_for("routes.index")) - - is_expired = datetime.fromtimestamp(float(expiration)) < datetime.now() - if is_expired: - flash(lazy_gettext("Lien expiré"), "error") - return redirect(url_for("routes.index")) - - return render_template( - "meeting/joinmail.html", - meeting=meeting, - meeting_fake_id=meeting.fake_id, - expiration=expiration, - user_id="fakeuserId", - h=h, - role="moderator", - ) - - -@bp.route( - "/meeting/signin//creator//hash/", methods=["GET"] -) -def signin_meeting(meeting_fake_id, user_id, h): - meeting = get_meeting_from_meeting_id_and_user_id(meeting_fake_id, user_id) - wordings = current_app.config["WORDINGS"] - if meeting is None: - flash( - lazy_gettext( - "Aucune %(meeting_label)s ne correspond à ces paramètres", - meeting_label=wordings["meeting_label"], - ), - "success", - ) - return redirect(url_for("routes.index")) - - current_user_id = get_current_user().id if has_user_session() else None - role = meeting.get_role(h, current_user_id) - - if role == "authenticated": - return redirect( - url_for("routes.join_meeting_as_authenticated", meeting_id=meeting_fake_id) - ) - elif not role: - return redirect(url_for("routes.index")) - return render_template( - "meeting/join.html", - meeting=meeting, - meeting_fake_id=meeting_fake_id, - user_id=user_id, - h=h, - role=role, - ) - - -@bp.route( - "/meeting/auth//creator//hash/", methods=["GET"] -) -@auth.oidc_auth("default") -def authenticate_then_signin_meeting(meeting_fake_id, user_id, h): - return redirect( - url_for( - "routes.signin_meeting", - meeting_fake_id=meeting_fake_id, - user_id=user_id, - h=h, - ) - ) - - -@bp.route( - "/meeting/wait//creator//hash//fullname/fullname_suffix/", -) -@bp.route( - "/meeting/wait//creator//hash//fullname//fullname_suffix/", -) -@bp.route( - "/meeting/wait//creator//hash//fullname/fullname_suffix/", -) -@bp.route( - "/meeting/wait//creator//hash//fullname//fullname_suffix/", -) -def waiting_meeting(meeting_fake_id, user_id, h, fullname="", fullname_suffix=""): - meeting = get_meeting_from_meeting_id_and_user_id(meeting_fake_id, user_id) - if meeting is None: - return redirect(url_for("routes.index")) - - current_user_id = get_current_user().id if has_user_session() else None - role = meeting.get_role(h, current_user_id) - if not role: - return redirect(url_for("routes.index")) - return render_template( - "meeting/wait.html", - meeting=meeting, - meeting_fake_id=meeting_fake_id, - user_id=user_id, - h=h, - role=role, - fullname=fullname, - fullname_suffix=fullname_suffix, - ) - - -@bp.route("/meeting/join", methods=["POST"]) -def join_meeting(): - form = JoinMeetingForm(request.form) - if not form.validate(): - return redirect(url_for("routes.index")) - fullname = form["fullname"].data - meeting_fake_id = form["meeting_fake_id"].data - user_id = form["user_id"].data - h = form["h"].data - meeting = get_meeting_from_meeting_id_and_user_id(meeting_fake_id, user_id) - if meeting is None: - return redirect(url_for("routes.index")) - - current_user_id = get_current_user().id if has_user_session() else None - role = meeting.get_role(h, current_user_id) - fullname_suffix = form["fullname_suffix"].data - if role == "authenticated": - fullname = get_authenticated_attendee_fullname() - elif not role: - return redirect(url_for("routes.index")) - return redirect( - meeting.get_join_url( - role, fullname, fullname_suffix=fullname_suffix, create=True - ) - ) - - -@bp.route("/meeting/joinmail", methods=["POST"]) -def join_mail_meeting(): - form = JoinMailMeetingForm(request.form) - if not form.validate(): - flash("Lien invalide", "error") - return redirect(url_for("routes.index")) - fullname = form["fullname"].data - meeting_fake_id = form["meeting_fake_id"].data - form["user_id"].data - expiration = form["expiration"].data - h = form["h"].data - - meeting = get_mail_meeting(meeting_fake_id) - if meeting is None: - flash( - lazy_gettext( - "%(meeting_label)s inexistante", - meeting_label=current_app.config["WORDINGS"][ - "meeting_label" - ].capitalize(), - ), - "error", - ) - return redirect(url_for("routes.index")) - - hash_matches = meeting.get_mail_signin_hash(meeting_fake_id, expiration) == h - if not hash_matches: - flash(lazy_gettext("Lien invalide"), "error") - return redirect(url_for("routes.index")) - - is_expired = datetime.fromtimestamp(expiration) < datetime.now() - if is_expired: - flash(lazy_gettext("Lien expiré"), "error") - return redirect(url_for("routes.index")) - - return redirect(meeting.get_join_url("moderator", fullname, create=True)) - - -def get_authenticated_attendee_fullname(): - attendee_session = UserSession(session) - attendee_info = attendee_session.userinfo - given_name = attendee_info.get("given_name", "") - family_name = attendee_info.get("family_name", "") - fullname = f"{given_name} {family_name}".strip() - return fullname - - -@bp.route("/meeting/join//authenticated", methods=["GET"]) -@auth.oidc_auth("attendee") -def join_meeting_as_authenticated(meeting_id): - meeting = Meeting.query.get(meeting_id) or abort(404) - role = "authenticated" - fullname = get_authenticated_attendee_fullname() - return redirect( - url_for( - "routes.waiting_meeting", - meeting_fake_id=meeting_id, - user_id=meeting.user.id, - h=meeting.get_hash(role), - fullname=fullname, - ) - ) - - -@bp.route("/meeting/join//", methods=["GET"]) -@auth.oidc_auth("default") -def join_meeting_as_role(meeting_id, role): - user = get_current_user() - form = JoinMeetingAsRoleForm(data={"meeting_id": meeting_id, "role": role}) - if not form.validate(): - abort(404) - meeting = Meeting.query.get(meeting_id) or abort(404) - if meeting.user_id == user.id: - return redirect(meeting.get_join_url(role, user.fullname, create=True)) - else: - flash(lazy_gettext("Accès non autorisé"), "error") - return redirect(url_for("routes.index")) - - -@bp.route("/meeting/delete", methods=["POST", "GET"]) -@auth.oidc_auth("default") -def delete_meeting(): - if request.method == "POST": - user = get_current_user() - meeting_id = request.form["id"] - meeting = Meeting.query.get(meeting_id) - - if meeting.user_id == user.id: - for meeting_file in meeting.files: - db.session.delete(meeting_file) - for meeting_file_external in meeting.externalFiles: - db.session.delete(meeting_file_external) - - data = meeting.delete_all_recordings() - return_code = data.get("returncode", "SUCCESS") - if return_code != "SUCCESS": - message = data.get("message", "") - flash( - "Nous n'avons pas pu supprimer les vidéos de cette " - + current_app.config["WORDINGS"]["meeting_label"] - + f" : {message}", - "error", - ) - else: - db.session.delete(meeting) - db.session.commit() - flash(lazy_gettext("Élément supprimé"), "success") - else: - flash(lazy_gettext("Vous ne pouvez pas supprimer cet élément"), "error") - return redirect(url_for("routes.welcome")) - - -@bp.route("/meeting/video/delete", methods=["POST"]) -@auth.oidc_auth("default") -def delete_video_meeting(): - if request.method == "POST": - user = get_current_user() - meeting_id = request.form["id"] - meeting = Meeting.query.get(meeting_id) - if meeting.user_id == user.id: - recordID = request.form["recordID"] - data = meeting.delete_recordings(recordID) - return_code = data.get("returncode") - if return_code == "SUCCESS": - flash(lazy_gettext("Vidéo supprimée"), "success") - else: - message = data.get("message", "") - flash( - lazy_gettext( - "Nous n'avons pas pu supprimer cette vidéo : %(code)s, %(message)s", - code=return_code, - message=message, - ), - "error", - ) - else: - flash( - lazy_gettext("Vous ne pouvez pas supprimer cette enregistrement"), - "error", - ) - return redirect(url_for("routes.welcome")) - - -@bp.route("/logout") -@auth.oidc_logout -def logout(): - return redirect(url_for("routes.index")) diff --git a/web/flaskr/templates/brand.html b/web/flaskr/templates/brand.html deleted file mode 100644 index d1f0b38b..00000000 --- a/web/flaskr/templates/brand.html +++ /dev/null @@ -1,28 +0,0 @@ - diff --git a/web/flaskr/templates/empty.html b/web/flaskr/templates/empty.html deleted file mode 100644 index ef885576..00000000 --- a/web/flaskr/templates/empty.html +++ /dev/null @@ -1,3 +0,0 @@ -

    - {% trans %}Vous devez vous identifier pour consulter la liste des visioconférences.{% endtrans %} -

    diff --git a/web/flaskr/templates/errors/400.html b/web/flaskr/templates/errors/400.html deleted file mode 100644 index d42677d6..00000000 --- a/web/flaskr/templates/errors/400.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends 'layout.html' %} - -{% block main %} -
    -
    -
    -

    {% trans %}Erreur 400{% endtrans %}

    -

    - {% if error %} - {{ error }} - {% else %} - {% trans %}La requête que vous avez effectué est invalide. Vous pouvez retourner à l’accueil.{% endtrans %} - {% endif %} -

    -
    -
    -
    -{% endblock %} diff --git a/web/flaskr/templates/errors/403.html b/web/flaskr/templates/errors/403.html deleted file mode 100644 index c0d4c6ae..00000000 --- a/web/flaskr/templates/errors/403.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends 'layout.html' %} - -{% block main %} -
    -
    -
    -

    {% trans %}Erreur 403{% endtrans %}

    -

    {% trans %}Vous n’êtes pas autorisé à accéder cette page. Vous pouvez retourner à l’accueil.{% endtrans %}

    -
    -
    -
    -{% endblock %} diff --git a/web/flaskr/templates/errors/404.html b/web/flaskr/templates/errors/404.html deleted file mode 100644 index 1306577e..00000000 --- a/web/flaskr/templates/errors/404.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends 'layout.html' %} - -{% block main %} -
    -
    -
    -

    {% trans %}Erreur 404{% endtrans %}

    -

    {% trans %}Cette page n'existe pas. Vous pouvez retourner à l’accueil.{% endtrans %}

    -
    -
    -
    -{% endblock %} diff --git a/web/flaskr/templates/errors/500.html b/web/flaskr/templates/errors/500.html deleted file mode 100644 index d572dd92..00000000 --- a/web/flaskr/templates/errors/500.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends 'layout.html' %} - -{% block main %} -
    -
    -
    -

    {% trans %}Erreur 500{% endtrans %}

    -

    {% trans %}Le serveur a rencontré une erreur interne, veuillez réessayer ultérieurement.{% endtrans %}

    -
    -
    -
    -{% endblock %} diff --git a/web/flaskr/templates/faq.html b/web/flaskr/templates/faq.html deleted file mode 100644 index cc486f4e..00000000 --- a/web/flaskr/templates/faq.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends 'static-layout.html' %} - -{% block main %} -

    {% trans %}FAQ - Modalités d'accès{% endtrans %}

    -
      - {% for content in contents %} -
      -

      - -

      -
      -
      -
      - {{content["description"]}} -
      -
      -
      -
      - {% endfor %} -
    -{% endblock %} diff --git a/web/flaskr/templates/footer.html b/web/flaskr/templates/footer.html deleted file mode 100644 index ed88b0ab..00000000 --- a/web/flaskr/templates/footer.html +++ /dev/null @@ -1,52 +0,0 @@ - diff --git a/web/flaskr/templates/footer/accessibilite.html b/web/flaskr/templates/footer/accessibilite.html deleted file mode 100644 index f96c8735..00000000 --- a/web/flaskr/templates/footer/accessibilite.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends 'static-layout.html' %} - -{% block main %} -
    -

    {% trans %}Accessibilité{% endtrans %}

    -

    {% trans %}Le site webinaire.numerique.gouv.fr est développé selon les recommendations du référentiel général d’amélioration d’accessibilité pour être accessible à tous les usagers quel que soit le matériel ou le logiciel utilisé pour naviguer sur internet.{% endtrans %}

    -

    {% trans %}Cependant, aucun audit formel n’a été effectué.{% endtrans %}

    - -

    {% trans %}Droit à compensation{% endtrans %}

    -

    {% trans %}Dans l’attente d’une mise en conformité totale, vous pouvez obtenir une version accessible des documents ou des informations qui y seraient contenues en envoyant un courriel à contact@webinaire.numerique.gouv.fr en indiquant le nom du document concerné et/ou les informations que vous souhaiteriez obtenir. Les informations demandées vous seront transmises dans les plus bref délais.{% endtrans %}

    - -

    {% trans %}Amélioration et contact{% endtrans %}

    -

    {% trans %}Vous pouvez nous aider à améliorer l’accessibilité du site en nous signalant les problèmes éventuels que vous rencontrez. Pour ce faire, envoyez-nous un courriel à contact@webinaire.numerique.gouv.fr .{% endtrans %}

    - -

    {% trans %}Défenseur des droits{% endtrans %}

    -

    {% trans %}Si vous constatez un défaut d'accessibilité vous empêchant d'accéder à un contenu ou une fonctionnalité du site, que vous nous le signalez et que vous ne parvenez pas à obtenir une réponse rapide de notre part, vous êtes en droit de faire parvenir vos doléances ou une demande de saisine au Défenseur des droits. Plusieurs moyens sont à votre disposition :{% endtrans %}

    - -{% endblock %} diff --git a/web/flaskr/templates/footer/documentation.html b/web/flaskr/templates/footer/documentation.html deleted file mode 100644 index 98180f22..00000000 --- a/web/flaskr/templates/footer/documentation.html +++ /dev/null @@ -1,89 +0,0 @@ -{% extends 'static-layout.html' %} - -{% block main %} -

    {% trans %}Documentation{% endtrans %}

    -

    {% trans %}Guides utilisateurs{% endtrans %}

    - {% if documentation_page_subtitle %} -

    {{ documentation_page_subtitle }}

    - {% endif %} -
  • {% trans %}Présentation des nouveautés de la v2.4{% endtrans %}
  • -
    - -
    -
  • {% trans %}Créer {{ an_improvised_meeting }}{% endtrans %}
  • -
  • {% trans %}Participer à {{ a_meeting }}{% endtrans %}
  • -
  • {% trans %}Créer et paramétrer une salle de {{ meeting_label }}{% endtrans %}
  • -
  • {% trans %}Activer le matériel dans le navigateur{% endtrans %}
  • -
  • {% trans %}Gérer les utilisateurs{% endtrans %}
  • -
  • {% trans %}Gérer les documents{% endtrans %}
  • -
  • {% trans %}Gestion des {{ private_meetings }}{% endtrans %}
  • -
  • {% trans %}Déléguer la création de {{ meeting_label }}{% endtrans %}
  • -
  • {% trans %}Enregistrer {{ a_meeting }}{% endtrans %}
  • -
  • {% trans %}Créer un sondage{% endtrans %}
  • -
  • {% trans %}Joindre {{ a_meeting }} par téléphone{% endtrans %}
  • -
  • {% trans %}Afficher le tableau de bord{% endtrans %}
  • -
  • {% trans %}Gérer la mise en page{% endtrans %}
  • -
  • {% trans %}Contrôle du volume{% endtrans %}
  • -
    - - - - - - - - - - - - - - - - - -
    1 caméra5 caméras10 caméras20 caméras30 caméras
    350 personnes250 personnes150 personnes100 personnesmaximum 50 personnes
    -

    Documentation technique

    - -

    L'ensemble de ces services requiére d'ouverture de ports UDP notamment dans les pare-feux

    - - -

    Le service BigBlueButton est composé de 3 types de services : -

      -
    • le service BigBlueButton
    • -
    • le service TURN/STUN qui permet, en méthode de contournement, lorsque les ports UDP sont bloqués d'encapsuler le flux UDP dans un flux 443/TCP/DTLS embarqué par les serveurs de web-visio BigBlueButton
    • -
    • le service Scalelite sur des serveurs dédiés qui servent à répartir les salles sur l'ensemble des serveurs BBB
    • -
    -

    - -

    -Ces ports sont : -

      -
    • Serveurs BBB/scalelite -
        -
      • TCP/IP ports 80/443 (HTTP/HTTPS)
      • -
      • UDP la plage de ports 16384 - 32768
      • -
      • TCP/IP ports 443 service TURN (TCP/DTLS) dont il faut positionner en exclusion du proxy les FQDN/IP
      • -
      -
    • -
    -

    -
    - -

    Serveurs TURN

    -

    Depuis la version 2.6 de BigBlueButton le service TURN est embarqué directement dans chaque serveur BigBlueButton et non plus une grappe de serveurs TURN dédiés.

    - -

    Fichiers avec les IP et FQDN des serveurs BBB

    - -{% endblock %} diff --git a/web/flaskr/templates/footer/donnees_personnelles.html b/web/flaskr/templates/footer/donnees_personnelles.html deleted file mode 100644 index 902f6bb6..00000000 --- a/web/flaskr/templates/footer/donnees_personnelles.html +++ /dev/null @@ -1,100 +0,0 @@ -{% extends 'static-layout.html' %} - -{% block main %} -
    -

    {% trans %}Données personnelles{% endtrans %}

    - -

    {% trans %}Gestion des cookies{% endtrans %}

    -

    {% trans %}À propos des cookies / traceurs{% endtrans %}

    -

    {% trans %}Afin de permettre aux applications Web de fournir des services, des « cookies » (« traceurs » en français) peuvent être utilisés.{% endtrans %}

    - -

    {% trans %}Qu’est-ce qu’un « cookie » ?{% endtrans %}

    -

    {% trans %}Un « cookie » est un fichier de taille limitée, généralement constitué de lettres et de chiffres, envoyé par le serveur internet au fichier cookie du navigateur situé sur le disque dur de votre ordinateur.{% endtrans %}

    - -

    {% trans %}Quels types de « cookies » sont utilisés par la le Webinaire de de l’Etat ?{% endtrans %}

    -

    {% trans %}Les cookies servent à l’authentification sur le site Webinaire/Visio-ecoles/colleges/lycees/agents{% endtrans %}

    -

    {% trans %}Il n’y a pas de cookie de mesure d’audience{% endtrans %}

    -

    {% trans %}Informations complémentaires sur les « cookies »{% endtrans %}

    -

    http://www.cnil.fr/vos-droits/vos-traces/les-cookies/

    - -

    {% trans %}Quelle sécurité pour vos données personnelles ?{% endtrans %}

    -

    {% trans %}Nous veillons à prendre les mesures physiques, techniques et organisationnelles appropriées pour garantir la sécurité et la confidentialité de vos données personnelles.{% endtrans %}

    - -

    {% trans %}Politique de confidentialité{% endtrans %}

    -

    {% trans %}Dans le cadre de l’utilisation du Webinaire, des données à caractère personnel vous concernant font l’objet d’un traitement par la DINUM (Direction Interministérielle du Numérique, ci-après « Nous »).{% endtrans %}

    -

    {% trans %}La présente politique décrit nos engagements en ce qui concerne le traitement de vos données, conformément au Règlement européen sur la protection des données (Règlement UE n° 2026/679 du 27 avril 2016, ci-après « RGPD ») et à la loi n° 78-17 du 6 janvier 1978 modifiée relative à l’informatique, aux fichiers et aux libertés (ci-après loi « Informatique et Libertés »).{% endtrans %}

    - -

    {% trans %}Quel est notre rôle ?{% endtrans %}

    -

    {% trans %}Le Webinaire est un service en ligne proposé aux agents de l’Etat destiné à faciliter le travail à distance par l’organisation et la tenue de réunions, de conférences et de formations en ligne.{% endtrans %}

    -

    {% trans %}La DINUM est responsable de traitement des informations traitées dans le cadre du Service et, à ce titre, s’engage à respecter les obligations inhérentes à ce traitement, notamment celles relevant de la loi n° 78-17 du 6 janvier 1978 relative à l’informatique aux fichiers et aux libertés.{% endtrans %}

    -

    {% trans %}Les organisateurs qui procèdent aux invitations et à l’enregistrement des webinaires sont responsables des traitements ultérieurs qu’ils réalisent à partir de ces enregistrements. Il leur appartient de vous délivrer une information sur ces traitements.{% endtrans %}

    - -

    {% trans %}Quels sont les traitements de données mis en œuvre ?{% endtrans %}

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {% trans %}Finalité du traitement{% endtrans %}{% trans %}Base légale du traitement{% endtrans %}{% trans %}Catégorie de données personnelles traitées{% endtrans %}{% trans %}Durée de conservation{% endtrans %}
    {% trans %}Gestion des comptes des organisateurs de webinaires{% endtrans %}{% trans %}Article 6-1(e) RGPD : exécution d’une mission de service public{% endtrans %}{% trans %}Données d’identification :{% endtrans %} - • {% trans %}Nom{% endtrans %} - • {% trans %}Prénom{% endtrans %} - • {% trans %}Adresse électronique{% endtrans %}{% trans %}Les données sont supprimées après une période de 12 mois d’inactivité du compte ou au moment de la désactivation du compte (1ère moe planifiée au plus tard en 12/22).{% endtrans %}
    {% trans %}Enregistrement des webinaires à des fins de partage et de rediffusion{% endtrans %}{% trans %}Article 6-1(e) RGPD : exécution d’une mission de service public{% endtrans %}{% trans %}Enregistrement vidéo des webinaires{% endtrans %}{% trans %}Les données d’enregistrement peuvent être supprimées à tout moment par l’organisateur. Elles sont automatiquement supprimées 12 mois après la date du webinaire (1ère moe planifiée au plus tard en 12/22).{% endtrans %}
    {% trans %}Outils de chat et de vote en ligne{% endtrans %}{% trans %}Article 6-1(e) RGPD : exécution d’une mission de service public{% endtrans %}{% trans %}Échanges écrits entre participants et résultats des votes en lignes{% endtrans %}{% trans %}Les données sont supprimées à l’issue de la session du webinaire.{% endtrans %}
    {% trans %}Gestion de la sécurité du Webinaire{% endtrans %}{% trans %}(Loi n° 2004-575 du 25 juin 2005 pour la confiance dans l’économie numérique, Décret n° 2021-1362 du 20 octobre 2021 relatif à la conservation des données permettant d’identifier toute personne ayant contribué à la création d’un contenu en ligne){% endtrans %}{% trans %}Données de connexion des utilisateurs du service (logs, adresse IP){% endtrans %}{% trans %}12 mois{% endtrans %}
    - -

    {% trans %}Quels sont les destinataires de vos données ?{% endtrans %}

    -

    {% trans %}Les destinataires de vos données personnelles sont les agents et salariées dûment habilitées de la DINUM et de nos sous-traitants qui interviennent pour l’hébergement, et l’infogérance du service.{% endtrans %}

    -

    {% trans %}Nous nous sommes assurés de la mise en œuvre par nos sous-traitants de garanties adéquates et du respect de conditions strictes de confidentialité, d’usage et de protection des données.{% endtrans %}

    -

    {% trans %}Les données collectées sur le Webinaire ne sont pas transférées en dehors de l’Union européenne.{% endtrans %}

    -

    {% trans %}Quels sont vos droits ?{% endtrans %}

    -

    {% trans %}Vous disposez d’un droit d’accès et de rectification des données à caractère personnel qui vous concernent. Vous disposez également d’un droit d’opposition et de limitation du traitement de vos données.{% endtrans %}

    -

    {% trans %}Pour exercer vos droits ou pour toute question sur le traitement de vos données, vous pouvez nous écrire à l’adresse : contact@webinaire.numerique.gouv.fr.{% endtrans %}

    -

    {% trans %}Vous pouvez également contacter le délégué à la protection des données (DPD) des services du Premier Ministre :{% endtrans %}

    - • {% trans %}par mail à dpd@pm.gouv.fr{% endtrans %}
    - • {% trans %}ou par courrier à l’adresse suivante :{% endtrans %}
    -

    {% trans %}Services du Premier Ministre{% endtrans %}

    -{% trans %}À l’attention du délégué à la protection des données (DPD)
    -56 rue de Varenne
    -75007 Paris{% endtrans %}
    -

    {% trans %}Si vous estimez, après nous avoir contactés, que vos droits Informatiques et Libertés ne sont pas respectés vous pouvez adresser une réclamation à la CNIL :{% endtrans %}

    -{% trans %}Commission nationale informatique et libertés
    -3 place de Fontenoy – TSA 80715 –
    -75334 PARIS CEDEX 07{% endtrans %}
    - -

    {% trans %}Les modalités de réclamation sont précisées sur le site de la CNIL : www.cnil.fr.{% endtrans %}

    - -

    {% trans %}Contactez le Délégué à la protection des données pour les services Écoles/Colléges/Lycées/Agents{% endtrans %}

    -

    {% trans %}Pour ce faire, envoyez un courriel à dpd[chez]education.gouv.fr{% endtrans %}

    -
    -{% endblock %} diff --git a/web/flaskr/templates/js_script.html b/web/flaskr/templates/js_script.html deleted file mode 100644 index e4ed2533..00000000 --- a/web/flaskr/templates/js_script.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/web/flaskr/templates/jumbotron.html b/web/flaskr/templates/jumbotron.html deleted file mode 100644 index 93dc2d6a..00000000 --- a/web/flaskr/templates/jumbotron.html +++ /dev/null @@ -1,116 +0,0 @@ -{% include 'rie.html' %} -{% if user %} -
    -
    -
    -
    - {% if quick_meeting == true %} -

    {% trans %}Lancer {{ a_meeting }}{% endtrans %}

    - {% trans %}Démarrer {{ a_meeting }} immédiatement{% endtrans %} -

    {{ welcome_page_subtitle }}

    - {% endif %} -
    -
    - {% if stats %} -
    -
    -

    - - {% trans trimmed count=stats["runningCount"]%} - Actuellement, il y a {{ count }} webinaire - {% pluralize %} - Actuellement, il y a {{ count }} webinaires - {% endtrans %} - {% trans trimmed count=stats["participantCount"]%} - et {{ count }} participant - {% pluralize %} - et {{ count }} participants - {% endtrans %} - {% trans %} sur une capacité moyenne pour la plateforme de {{ max_participants }} participants.{% endtrans %} - -

    -
    -
    - {% endif %} -
    -
    -{% else %} -
    -
    -
    -
    -

    {% trans %}Vous organisez régulièrement des {{ some_meetings }}{% endtrans %}

    -

    {% trans %}Vous êtes agent de l’État, créez un compte pour organiser et conserver vos {{ some_meetings }}.{% endtrans %}

    -

    {% trans %}Se connecter ou créer un compte{% endtrans %}

    -

    - {% if stats %} -

    - - {% trans trimmed count=stats["runningCount"]%} - Actuellement, il y a {{ count }} webinaire - {% pluralize %} - Actuellement, il y a {{ count }} webinaires - {% endtrans %} - {% trans trimmed count=stats["participantCount"]%} - et {{ count }} participant - {% pluralize %} - et {{ count }} participants - {% endtrans %} - {% trans %} sur une capacité moyenne pour la plateforme de {{ max_participants }} participants.{% endtrans %} - -

    - {% endif %} -
    -
    -
    -
    -
    -
    - {% if mail_meeting %} -
    -
    -
    -

    {% trans %}Démarrer {{ a_meeting }} en ligne immédiatement{% endtrans %}

    - {% with messages = get_flashed_messages(with_categories=true, category_filter=["error_login","success_login", "warning"]) %} - {% if messages %} - {% for category,message in messages %} -
    -

    {{ message }}

    -
    - {% endfor %} - {% endif %} - {% endwith %} -

    {% trans %}Recevez par courriel un lien organisateur {{ of_the_meeting }}, actif une semaine, à envoyer aux participants.{% endtrans %}

    - - {% include 'meeting/csrf.html' %} -
    -
    - - -
    -
    - -
    -
    - -
    -
    -
    -
    -
    - {% endif %} -
    -
    - {% if mail_meeting %} - -
    -
    -

    {% trans %}Vous essayez de rejoindre {{ a_meeting }}{% endtrans %}

    -

    {% trans %}Pour rejoindre {{ a_meeting_to_which }} vous êtes invité, cliquez sur le lien que vous a transmis l'organisateur/modérateur.{% endtrans %}

    -

    -
    -
    - {% endif %} -
    -
    -{% endif %} diff --git a/web/flaskr/templates/layout.html b/web/flaskr/templates/layout.html deleted file mode 100644 index 4aeeaae0..00000000 --- a/web/flaskr/templates/layout.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - {{title}} - - - - - - - - - - - - - -
    - {% block header %} - {% include 'header.html' %} - {% endblock %} -
    - {% with messages = get_flashed_messages(with_categories=true, category_filter=["error","success", "message", "warning"]) %} - {% if messages %} - {% for category,message in messages %} -
    -

    {{ message }}

    -
    - {% endfor %} - {% endif %} - {% endwith %} - {% block jumbotron %}{% endblock %} -
    -
    -
    - {% block main %}{% endblock %} -
    -
    -
    -
    - - {% block footer %} - {% include 'footer.html' %} - {% endblock %} - - - - - - - {% block js %}{% endblock %} -
    - - diff --git a/web/flaskr/templates/meeting/card.html b/web/flaskr/templates/meeting/card.html deleted file mode 100644 index fee73950..00000000 --- a/web/flaskr/templates/meeting/card.html +++ /dev/null @@ -1,7 +0,0 @@ -
    -
    -

    {{ meeting.name }}

    - {% include 'meeting/row.html' %} -
    -
    -{% include 'meeting/modals.html' %} diff --git a/web/flaskr/templates/meeting/edit.html b/web/flaskr/templates/meeting/edit.html deleted file mode 100644 index 14a0d3b7..00000000 --- a/web/flaskr/templates/meeting/edit.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends 'layout.html' %} - -{% block jumbotron %} - {% include 'meeting/jumbotron.html' %} -{% endblock %} - -{% block main %} - {% include 'meeting/form.html' %} -{% endblock %} - -{% block js %} - {% include 'meeting/js_script.html' %} -{% endblock %} diff --git a/web/flaskr/templates/meeting/end.html b/web/flaskr/templates/meeting/end.html deleted file mode 100644 index 74670620..00000000 --- a/web/flaskr/templates/meeting/end.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends 'layout.html' %} - -{% block main %} -

    - {{ this_meeting.capitalize() }} est actuellement en cours avec les anciens paramètres.
    - Souhaitez-vous y mettre fin pour permettre la prise en compte immédiate de ces nouveaux paramètres ? Les éventuels participants seront déconnectés. -

    - -
    - {{ form.hidden_tag() }} - - Patienter jusqu'à la fin {{ of_the_meeting }} -
    -{% endblock %} diff --git a/web/flaskr/templates/meeting/externalUpload.html b/web/flaskr/templates/meeting/externalUpload.html deleted file mode 100644 index fb1abc87..00000000 --- a/web/flaskr/templates/meeting/externalUpload.html +++ /dev/null @@ -1,68 +0,0 @@ - -
    - - -
    - - - -
    diff --git a/web/flaskr/templates/meeting/files.html b/web/flaskr/templates/meeting/files.html deleted file mode 100644 index 3b8a865a..00000000 --- a/web/flaskr/templates/meeting/files.html +++ /dev/null @@ -1,223 +0,0 @@ -{% macro render_field(field, generate_button=False) %} -
    - {% if field.type == "BooleanField" %} -
    - {{ field(value="on")}} - {{ field.label(class_="fr-label") }} -

    {{ field.description }}

    -
    - {% else %} -
    - {{ field.label(class_="fr-label") }} -

    {{ field.description }}

    - {% if field.errors %} - {% for error in field.errors %} -

    {{ error }}

    - {% endfor %} - {% endif %} - {% if generate_button %} -
    -
    - {{ field(class_="fr-input") }} -
    -
    - -
    -
    - {% else %} - {{ field(class_="fr-input", **kwargs) }} - {% endif %} -
    - {% endif %} -
    -{% endmacro %} - - - - - -

    Gestion des {{ meeting_presentation }}s associées à {{meeting.name }}

    - - - -
    -{% if form.errors %} -

    Enregistrement impossible car certains champs sont mal renseignés.

    -{% endif %} - -
    - - -
    -
    -
    -
    -
    - -
    -
    -
    - {% include 'meeting/csrf.html' %} - {% include 'meeting/id.html' %} -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
    - -
    -
    -
    - {% include 'meeting/csrf.html' %} - {% include 'meeting/id.html' %} -
    - {{ render_field(form.url) }} - -
    -
    -
    -
    -
    -
    -
    - -
    - - - -
    -

    Vous pouvez ajouter un fichier :

    -
    - -
      -
    • - -
    • - {% if user.nc_login and user.nc_token and user.nc_locator %} -
    • - -
    • -
    • - -
    • - {% endif %} -
    - -
    -
    - - -
    - -
    -
    - - - - - - - - - - - - - - {% for file in meeting.files %} - {% if (user.nc_login and user.nc_token and user.nc_locator) or file.url %} - - -
    -
    -
    -
    -
    - -
    -
    -

    - Supprimer -

    -

    Voulez-vous vraiment supprimer le fichier {{ file.short_title }} ?

    -
    - - - - {% include 'meeting/csrf.html' %} - -
    -
    -
    -
    -
    -
    - - - - - - - - - - {% endif %} - {% endfor %} - -
    Vos fichiers associés sont :
    DéfautTéléchargeableTitreAjouté leSupprimerTélécharger
    -
    - {% if file.is_default %} - - - {% else %} - - - {% endif %} -
    -
    -
    - {% if file.is_downloadable %} - - - {% else %} - - - {% endif %} -
    -
    {{ file.short_title }}{{ file.created_at }} - - - - - -
    -
    - {% if not meeting.files|length %} -

    Aucun document de présentation n'est prévu pour cette réunion actuellement

    - {% endif %} -
    -
    - - diff --git a/web/flaskr/templates/meeting/filesform.html b/web/flaskr/templates/meeting/filesform.html deleted file mode 100644 index 77c5e0f6..00000000 --- a/web/flaskr/templates/meeting/filesform.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends 'layout.html' %} - -{% block main %} - {% include 'meeting/files.html' %} -{% endblock %} - -{% block js %} - {% include 'meeting/js_script.html' %} -{% endblock %} diff --git a/web/flaskr/templates/meeting/id.html b/web/flaskr/templates/meeting/id.html deleted file mode 100644 index c68d69ab..00000000 --- a/web/flaskr/templates/meeting/id.html +++ /dev/null @@ -1,3 +0,0 @@ -{% if meeting is not none %} - -{% endif %} diff --git a/web/flaskr/templates/meeting/join.html b/web/flaskr/templates/meeting/join.html deleted file mode 100644 index 37e07118..00000000 --- a/web/flaskr/templates/meeting/join.html +++ /dev/null @@ -1,73 +0,0 @@ -{% extends 'layout.html' %} - -{% block jumbotron %} - {% include 'rie.html' %} -{% endblock %} - -{% block main %} -

    {% trans %}Rejoindre {{ the_meeting }}{% endtrans %}

    - -
    - {% include 'meeting/csrf.html' %} - - - - -
    -
    -
    - - {% if role != "authenticated" %}

    {% trans %}Vous pouvez également préciser votre service ou votre fonction.{% endtrans %}

    {% endif %} - -
    -
    - - {% if role == "authenticated" %} -
    -
    - -

    Si ce champ est rempli, il sera affiché dans BBB.

    - -
    -
    -

    Le nom affiché sera «  ».

    - {% endif %} - - {% if not retry_join_meeting %} -
    -
    - -
    -
    - {% endif %} - {% if role != "authenticated" and not user %} -
    -
    - {% trans %}Vous êtes propriétaire de cette salle ?{% endtrans %} - - {% trans %}S’identifier{% endtrans %} - -
    -
    - {% endif %} -
    -
    - - {% if role == "authenticated" %} - - {% endif %} -{% endblock %} diff --git a/web/flaskr/templates/meeting/js_script.html b/web/flaskr/templates/meeting/js_script.html deleted file mode 100644 index 720665b3..00000000 --- a/web/flaskr/templates/meeting/js_script.html +++ /dev/null @@ -1,455 +0,0 @@ - diff --git a/web/flaskr/templates/meeting/list.html b/web/flaskr/templates/meeting/list.html deleted file mode 100644 index 31b021eb..00000000 --- a/web/flaskr/templates/meeting/list.html +++ /dev/null @@ -1,30 +0,0 @@ -
    -

    {% trans %}Mes salles de {{ some_meetings }}{% endtrans %}

    - {% if can_create_meetings == true %} -

    {% trans %}Créer une salle de {{ meeting_label }} vous permet de conserver les réglages et le lien de la salle.{% endtrans %}

    - {% else %} -
    -

    - - {% trans %}Vous avez atteint la limite des {{ max_meetings_per_user }} {{ meeting_label }}s. Pour pouvoir en créer davantage, veuillez supprimer des {{ meeting_label }}s inactives.{% endtrans %} -

    -
    - {% endif %} - - {% for meeting in meetings %} -
    -
    -

    {{ meeting.name }}

    - {% include 'meeting/row.html' %} -
    -
    - {% include 'meeting/modals.html' %} - {% endfor %} - {% if meetings|length and config.get("SATISFACTION_POLL_URL") %} - - {% endif %} -
    diff --git a/web/flaskr/templates/meeting/modals.html b/web/flaskr/templates/meeting/modals.html deleted file mode 100644 index 927a2bd5..00000000 --- a/web/flaskr/templates/meeting/modals.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - diff --git a/web/flaskr/templates/meeting/recordings.html b/web/flaskr/templates/meeting/recordings.html deleted file mode 100644 index 7c1b84d9..00000000 --- a/web/flaskr/templates/meeting/recordings.html +++ /dev/null @@ -1,127 +0,0 @@ -{% extends 'layout.html' %} - -{% block jumbotron %} -{% endblock %} - -{% block main %} -

    {% trans meeting_name=meeting.name %}Enregistrements de {{meeting_name }}{% endtrans %}

    - -
    - {% if meeting.running %} -

    - {% trans this_meeting=this_meeting.capitalize() %}{{ this_meeting }} est toujours en cours{% endtrans %}. - {% trans %}Si un enregistrement est en cours, il ne sera encodé qu'après la fin {{ of_the_meeting }}{% endtrans %}. -

    - {% endif %} -

    {% trans %}Après la fin d'{{ a_meeting }}, l'encodage de l'enregistrement peut prendre autant de temps que la durée {{ of_the_meeting }}.{% endtrans %}

    -

    {% trans %}Si aucun modérateur ne met fin {{ of_the_meeting }}, un délai supplémentaire de plusieurs minutes s'ajoute après que tous les utilisateurs l'aient quitté.{% endtrans %}

    - {% for r in meeting.recordings %} - {% set recording_name = r.name or r.start_date.strftime("%d/%m/%Y") %} -

    - {{ recording_name }} - -

    -
    - - - - - - - {% set p = r.playbacks.get("presentation") %} - {% if p %} - - - - - {% endif %} - -
    {% trans %}Visuels{% endtrans %}{% trans %}Actions{% endtrans %}
    -
    - {% for i in p.images %} - {% if loop.index is le(2) %} -
    - {{ i.alt }} -
    - {% endif %} - {% endfor %} -
    -
    -
    - - - {% if r.playbacks.get("video") %} - mp4 - {% endif %} - -
    -
    -
    - - - - - - - - {% endfor %} -
    - -{% endblock %} - -{% block js %} - {% include 'meeting/js_script.html' %} -{% endblock %} diff --git a/web/flaskr/templates/meeting/row.html b/web/flaskr/templates/meeting/row.html deleted file mode 100644 index b9c40a55..00000000 --- a/web/flaskr/templates/meeting/row.html +++ /dev/null @@ -1,66 +0,0 @@ -
    - {% if shorty %} -
    - - - {% if mailto %} - - {% endif %} - -
    -
    - - - {% if mailto %} - - {% endif %} - -
    -
    - - {% if file_sharing %} - - {% endif %} - -
    - {% else %} -
    - {% trans %}Lancer{% endtrans %} - -
    -
    - {% if recording %} - - - - {% endif %} - - {% if file_sharing %} - - {% endif %} - -
    - {% endif %} -
    diff --git a/web/flaskr/templates/meeting/show.html b/web/flaskr/templates/meeting/show.html deleted file mode 100644 index ab4c65b2..00000000 --- a/web/flaskr/templates/meeting/show.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends 'layout.html' %} - -{% block jumbotron %} - {% include 'jumbotron.html' %} -{% endblock %} - -{% block main %} - {% include 'meeting/card.html' %} -{% endblock %} - -{% block js %} - {% include 'js_script.html' %} -{% endblock %} diff --git a/web/flaskr/templates/meeting/submit.html b/web/flaskr/templates/meeting/submit.html deleted file mode 100644 index da8df22b..00000000 --- a/web/flaskr/templates/meeting/submit.html +++ /dev/null @@ -1,8 +0,0 @@ -
    -{% if meeting is not none %} - -{% else %} - -{% endif %} - {% trans %}Annuler{% endtrans %} -
    diff --git a/web/flaskr/templates/redirections.html b/web/flaskr/templates/redirections.html deleted file mode 100644 index 4a634688..00000000 --- a/web/flaskr/templates/redirections.html +++ /dev/null @@ -1,15 +0,0 @@ - - -
    -

    {% trans %}Autres profils{% endtrans %}

    - {% for link in redirection_links %} -

    {{ link.text }}

    - {% endfor %} -
    - diff --git a/web/flaskr/templates/static-layout.html b/web/flaskr/templates/static-layout.html deleted file mode 100644 index c3a51fd0..00000000 --- a/web/flaskr/templates/static-layout.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - {{title}} - - - - - - - - - - -
    - {% block header %} - {% include 'header.html' %} - {% endblock %} -
    -
    -
    - {% block main %}{% endblock %} -
    -
    -
    - - {% block footer %} - {% include 'footer.html' %} - {% endblock %} - - - - - - - - - {% block js %}{% endblock %} -
    - - diff --git a/web/flaskr/templates/tools.html b/web/flaskr/templates/tools.html deleted file mode 100644 index fb24ec10..00000000 --- a/web/flaskr/templates/tools.html +++ /dev/null @@ -1,46 +0,0 @@ - diff --git a/web/flaskr/utils.py b/web/flaskr/utils.py deleted file mode 100644 index 849f0224..00000000 --- a/web/flaskr/utils.py +++ /dev/null @@ -1,23 +0,0 @@ -from flask import current_app -from flask import request -from netaddr import IPAddress -from netaddr import IPNetwork - - -def secret_key(): - return current_app.config["SECRET_KEY"] - - -def is_rie(): - """ - Checks wether the request was made from inside the state network - "Réseau Interministériel de l’État" - """ - if not request.remote_addr: - return False - - return any( - IPAddress(request.remote_addr) in IPNetwork(network_ip) - for network_ip in current_app.config.get("RIE_NETWORK_IPS", []) - if network_ip - ) diff --git a/web/flaskr/wsgi.py b/web/flaskr/wsgi.py deleted file mode 100644 index 999b4d77..00000000 --- a/web/flaskr/wsgi.py +++ /dev/null @@ -1,3 +0,0 @@ -from flaskr import create_app - -app = create_app() diff --git a/web/instance/config.py b/web/instance/config.py deleted file mode 100755 index cee584e7..00000000 --- a/web/instance/config.py +++ /dev/null @@ -1,589 +0,0 @@ -import json -import os - -from flask_babel import lazy_gettext - - -# App configuration -SECRET_KEY = os.environ.get("SECRET_KEY") -NC_LOGIN_TIMEDELTA_DAYS = int(os.environ.get("NC_LOGIN_TIMEDELTA_DAYS")) -REDIS_URL = os.environ.get("REDIS_URL") -NC_LOGIN_API_URL = os.environ.get("NC_LOGIN_API_URL") -NC_LOGIN_API_KEY = os.environ.get("NC_LOGIN_API_KEY") -UPLOAD_DIR = os.environ.get("UPLOAD_DIR") -TMP_DOWNLOAD_DIR = os.environ.get("TMP_DOWNLOAD_DIR") -MAX_SIZE_UPLOAD = os.environ.get("MAX_SIZE_UPLOAD") -TIME_FORMAT = os.environ.get("TIME_FORMAT") -TESTING = True -DEBUG = True -TITLE = os.environ.get("TITLE") -SERVER_FQDN = os.environ.get("SERVER_FQDN") -EXTERNAL_UPLOAD_DESCRIPTION = os.environ.get("EXTERNAL_UPLOAD_DESCRIPTION") -WTF_CSRF_TIME_LIMIT = int(os.environ.get("WTF_CSRF_TIME_LIMIT", 3600 * 12)) -MAX_MEETINGS_PER_USER = int(os.environ.get("MAX_MEETINGS_PER_USER", 50)) - -ALLOWED_MIME_TYPES_SERVER_SIDE = json.loads( - os.environ.get("ALLOWED_MIME_TYPES_SERVER_SIDE", "[]") or "[]" -) -ACCEPTED_FILES_CLIENT_SIDE = os.environ.get("ACCEPTED_FILES_CLIENT_SIDE", "") - -# Default OIDC Configuration -OIDC_ID_TOKEN_COOKIE_SECURE = False -OIDC_REQUIRE_VERIFIED_EMAIL = False -OIDC_USER_INFO_ENABLED = True -OIDC_OPENID_REALM = os.environ.get("OIDC_OPENID_REALM") -OIDC_SCOPES = ( - list(map(str.strip, os.environ["OIDC_SCOPES"].split(","))) - if os.environ.get("OIDC_SCOPES") - else [ - "openid", - "email", - "profile", - ] -) -OIDC_INTROSPECTION_AUTH_METHOD = os.environ.get( - "OIDC_INTROSPECTION_AUTH_METHOD", "client_secret_basic" -) -OIDC_USERINFO_HTTP_METHOD = os.environ.get("OIDC_USERINFO_HTTP_METHOD") -OIDC_INFO_REQUESTED_FIELDS = ["email", "given_name", "family_name"] -OIDC_ISSUER = os.environ.get("OIDC_ISSUER") -OIDC_AUTH_URI = os.environ.get("OIDC_AUTH_URI") -OIDC_USERINFO_URI = os.environ.get("OIDC_USERINFO_URI") -OIDC_TOKEN_URI = os.environ.get("OIDC_TOKEN_URI") -OIDC_CLIENT_ID = os.environ.get("OIDC_CLIENT_ID") -OIDC_CLIENT_SECRET = os.environ.get("OIDC_CLIENT_SECRET") -OIDC_CLIENT_AUTH_METHOD = os.environ.get("OIDC_CLIENT_AUTH_METHOD") -OIDC_REDIRECT_URI = os.environ.get("OIDC_REDIRECT_URI") -OIDC_SERVICE_NAME = os.environ.get("OIDC_SERVICE_NAME") - -# Attendee OIDC Configuration (back to default if empty) -OIDC_ATTENDEE_ENABLED = os.environ.get("OIDC_ATTENDEE_ENABLED") not in [ - 0, - False, - "0", - "false", - "False", - "off", - "OFF", -] -OIDC_ATTENDEE_ISSUER = os.environ.get("OIDC_ATTENDEE_ISSUER") or OIDC_ISSUER -OIDC_ATTENDEE_CLIENT_ID = os.environ.get("OIDC_ATTENDEE_CLIENT_ID") or OIDC_CLIENT_ID -OIDC_ATTENDEE_CLIENT_SECRET = ( - os.environ.get("OIDC_ATTENDEE_CLIENT_SECRET") or OIDC_CLIENT_SECRET -) -OIDC_ATTENDEE_CLIENT_AUTH_METHOD = ( - os.environ.get("OIDC_ATTENDEE_CLIENT_AUTH_METHOD") or OIDC_CLIENT_AUTH_METHOD -) -OIDC_ATTENDEE_INTROSPECTION_AUTH_METHOD = ( - os.environ.get("OIDC_ATTENDEE_INTROSPECTION_AUTH_METHOD") - or OIDC_INTROSPECTION_AUTH_METHOD -) -OIDC_ATTENDEE_USERINFO_HTTP_METHOD = ( - os.environ.get("OIDC_ATTENDEE_USERINFO_HTTP_METHOD") or OIDC_USERINFO_HTTP_METHOD -) -OIDC_ATTENDEE_SERVICE_NAME = ( - os.environ.get("OIDC_ATTENDEE_SERVICE_NAME") or OIDC_SERVICE_NAME -) -OIDC_ATTENDEE_SCOPES = ( - list(map(str.strip, os.environ["OIDC_ATTENDEE_SCOPES"].split(","))) - if os.environ.get("OIDC_ATTENDEE_SCOPES") - else OIDC_SCOPES -) - -# Links -DOCUMENTATION_LINK = { - "url": os.environ.get("DOCUMENTATION_LINK_URL"), - "label": os.environ.get("DOCUMENTATION_LINK_LABEL"), - "is_external": not os.environ.get("DOCUMENTATION_LINK_URL") - .lower() - .startswith(("/", SERVER_FQDN.lower())), -} -SERVICE_TITLE = os.environ.get("SERVICE_TITLE") -SERVICE_TAGLINE = os.environ.get("SERVICE_TAGLINE") - -MEETING_LOGOUT_URL = os.environ.get("MEETING_LOGOUT_URL", "") -SATISFACTION_POLL_URL = os.environ.get("SATISFACTION_POLL_URL") - -# Database configuration -SQLALCHEMY_DATABASE_URI = os.environ.get("SQLALCHEMY_DATABASE_URI") -SQLALCHEMY_TRACK_MODIFICATIONS = False - -# wording -MEETING_KEY_WORDING = os.environ.get("MEETING_KEY_WORDING", "reunion") - -AVAILABLE_WORDINGS = { - "MEETING": {"cours": "cours", "reunion": "réunion", "seminaire": "séminaire"}, - "MEETINGS": {"cours": "cours", "reunion": "réunions", "seminaire": "séminaires"}, - "A_MEETING": { - "cours": "un cours", - "reunion": "une réunion", - "seminaire": "un séminaire", - }, - "MY_MEETING": { - "cours": "mon cours", - "reunion": "ma réunion", - "seminaire": "mon séminaire", - }, - "THE_MEETING": { - "cours": "le cours", - "reunion": "la réunion", - "seminaire": "le séminaire", - }, - "OF_THE_MEETING": { - "cours": "du cours", - "reunion": "de la réunion", - "seminaire": "du séminaire", - }, - "THIS_MEETING": { - "cours": "ce cours", - "reunion": "cette réunion", - "seminaire": "ce séminaire", - }, - "TO_THE_MEETING": { - "cours": "au cours", - "reunion": "à la réunion", - "seminaire": "au séminaire", - }, - "IMPROVISED_MEETING": { - "cours": "cours improvisé", - "reunion": "réunion improvisée", - "seminaire": "séminaire improvisé", - }, - "AN_IMPROVISED_MEETING": { - "cours": "un cours improvisé", - "reunion": lazy_gettext("une réunion improvisée"), - "seminaire": "un séminaire improvisé", - }, - "A_QUICK_MEETING": { - "cours": "un cours immédiat", - "reunion": lazy_gettext("une réunion immédiate"), - "seminaire": "un séminaire immédiat", - }, - "PRIVATE_MEETINGS": { - "cours": "cours privés", - "reunion": lazy_gettext("réunions privées"), - "seminaire": "séminaires privés", - }, - "GOOD_MEETING": { - "cours": "bon cours", - "reunion": lazy_gettext("bonne réunion"), - "seminaire": "bon séminaire", - }, - "MEETING_UNDEFINED_ARTICLE": { - "cours": "un", - "reunion": lazy_gettext("une"), - "seminaire": "un", - }, - "A_MEETING_TO_WHICH": { - "cours": "un cours auquel", - "reunion": lazy_gettext("une réunion à laquelle"), - "seminaire": "un séminaire auquel", - }, - "WELCOME_PAGE_SUBTITLE": { - "cours": lazy_gettext( - "Créez un cours immédiatement avec des réglages standards. Ce cours ne sera pas enregistré dans votre liste de salons." - ), - "reunion": lazy_gettext( - "Créez une réunion immédiatement avec des réglages standards. Cette réunion ne sera pas enregistrée dans votre liste de salons." - ), - "seminaire": lazy_gettext( - "Créez un séminaire immédiatement avec des réglages standards. Ce séminaire ne sera pas enregistré dans votre liste de salons." - ), - }, - "MEETING_MAIL_SUBJECT": { - "cours": lazy_gettext( - "Invitation à un cours en ligne immédiat du Webinaire de l’Etat" - ), - "reunion": lazy_gettext( - "Invitation à une réunion en ligne immédiat du Webinaire de l’Etat" - ), - "seminaire": lazy_gettext( - "Invitation à un séminaire en ligne immédiat du Webinaire de l’Etat" - ), - }, -} - - -WORDING_A_MEETING = AVAILABLE_WORDINGS["A_MEETING"][MEETING_KEY_WORDING] -WORDING_MY_MEETING = AVAILABLE_WORDINGS["MY_MEETING"][MEETING_KEY_WORDING] -WORDING_THE_MEETING = AVAILABLE_WORDINGS["THE_MEETING"][MEETING_KEY_WORDING] -WORDING_OF_THE_MEETING = AVAILABLE_WORDINGS["OF_THE_MEETING"][MEETING_KEY_WORDING] -WORDING_MEETING = AVAILABLE_WORDINGS["MEETING"][MEETING_KEY_WORDING] -WORDING_MEETINGS = AVAILABLE_WORDINGS["MEETINGS"][MEETING_KEY_WORDING] -WORDING_THIS_MEETING = AVAILABLE_WORDINGS["THIS_MEETING"][MEETING_KEY_WORDING] -WORDING_TO_THE_MEETING = AVAILABLE_WORDINGS["TO_THE_MEETING"][MEETING_KEY_WORDING] -WORDING_IMPROVISED_MEETING = AVAILABLE_WORDINGS["IMPROVISED_MEETING"][ - MEETING_KEY_WORDING -] -WORDING_AN_IMPROVISED_MEETING = AVAILABLE_WORDINGS["AN_IMPROVISED_MEETING"][ - MEETING_KEY_WORDING -] -WORDING_A_QUICK_MEETING = AVAILABLE_WORDINGS["A_QUICK_MEETING"][MEETING_KEY_WORDING] -WORDING_PRIVATE_MEETINGS = AVAILABLE_WORDINGS["PRIVATE_MEETINGS"][MEETING_KEY_WORDING] -WORDING_GOOD_MEETING = AVAILABLE_WORDINGS["GOOD_MEETING"][MEETING_KEY_WORDING] -WORDING_MEETING_UNDEFINED_ARTICLE = AVAILABLE_WORDINGS["MEETING_UNDEFINED_ARTICLE"][ - MEETING_KEY_WORDING -] -WORDING_A_MEETING_TO_WHICH = AVAILABLE_WORDINGS["A_MEETING_TO_WHICH"][ - MEETING_KEY_WORDING -] -WELCOME_PAGE_SUBTITLE = AVAILABLE_WORDINGS["WELCOME_PAGE_SUBTITLE"][MEETING_KEY_WORDING] -MEETING_MAIL_SUBJECT = AVAILABLE_WORDINGS["MEETING_MAIL_SUBJECT"][MEETING_KEY_WORDING] - -WORDING_MEETING_PRESENTATION = os.environ.get( - "WORDING_MEETING_PRESENTATION", "présentation" -) -WORDING_UPLOAD_FILE = os.environ.get("WORDING_MEETING_UPLOAD_FILE", "envoyer") - -FILE_SHARING = os.environ.get("FILE_SHARING") == "on" - -DOCUMENTATION_PAGE_SUBTITLE = os.environ.get("DOCUMENTATION_PAGE_SUBTITLE") -WORDINGS = { - "a_meeting": WORDING_A_MEETING, - "the_meeting": WORDING_THE_MEETING, - "some_meetings": WORDING_MEETINGS, - "of_the_meeting": WORDING_OF_THE_MEETING, - "my_meeting": WORDING_MY_MEETING, - "this_meeting": WORDING_THIS_MEETING, - "meeting_label": WORDING_MEETING, - "meeting_presentation": WORDING_MEETING_PRESENTATION, - "upload_file_label": WORDING_UPLOAD_FILE, - "service_title": SERVICE_TITLE, - "service_tagline": SERVICE_TAGLINE, - "an_improvised_meeting": WORDING_AN_IMPROVISED_MEETING, - "private_meetings": WORDING_PRIVATE_MEETINGS, - "a_quick_meeting": WORDING_A_QUICK_MEETING, - "good_meeting": WORDING_GOOD_MEETING, - "to_the_meeting": WORDING_TO_THE_MEETING, - "meeting_undefined_article": WORDING_MEETING_UNDEFINED_ARTICLE, - "a_meeting_to_which": WORDING_A_MEETING_TO_WHICH, - "welcome_page_subtitle": WELCOME_PAGE_SUBTITLE, - "documentation_page_subtitle": DOCUMENTATION_PAGE_SUBTITLE, - "meeting_mail_subject": MEETING_MAIL_SUBJECT, -} - -# quick meeting -QUICK_MEETING = True -QUICK_MEETING_DEFAULT_NAME = WORDING_IMPROVISED_MEETING.capitalize() -QUICK_MEETING_MODERATOR_LINK_INTRODUCTION = lazy_gettext(" Lien Modérateur ") -QUICK_MEETING_ATTENDEE_LINK_INTRODUCTION = lazy_gettext(" Lien Participant ") -QUICK_MEETING_MODERATOR_WELCOME_MESSAGE = lazy_gettext( - "Bienvenue aux modérateurs. Pour inviter quelqu'un à %(this_meeting)s, envoyez-lui l'un de ces liens :", - this_meeting=WORDING_THIS_MEETING, -) -QUICK_MEETING_LOGOUT_URL = os.environ.get("QUICK_MEETING_LOGOUT_URL") -MAIL_MODERATOR_WELCOME_MESSAGE = lazy_gettext( - "Bienvenue. Pour inviter quelqu'un à %(this_meeting)s, envoyez-lui l'un de ces liens :", - this_meeting=WORDING_THIS_MEETING, -) -MAILTO_LINKS = False -SHORTY = False -CLIPBOARD = os.environ.get("CLIPBOARD") == "on" -RECORDING = os.environ.get("RECORDING") == "on" -BETA = os.environ.get("BETA") == "on" -MAIL_MEETING = os.environ.get("MAIL_MEETING") == "on" -SMTP_FROM = os.environ.get("SMTP_FROM") -SMTP_HOST = os.environ.get("SMTP_HOST") -SMTP_PORT = os.environ.get("SMTP_PORT") -SMTP_USERNAME = os.environ.get("SMTP_USERNAME") -SMTP_PASSWORD = os.environ.get("SMTP_PASSWORD") -SMTP_SSL = os.environ.get("SMTP_SSL") -EMAIL_WHITELIST = os.environ.get("EMAIL_WHITELIST") -DEFAULT_MEETING_DURATION = os.environ.get("DEFAULT_MEETING_DURATION", 280) - -RIE_NETWORK_IPS = os.environ.get("RIE_NETWORK_IPS", "").split(",") -MAX_PARTICIPANTS = os.environ.get("MAX_PARTICIPANTS", 200) -STATS_CACHE_DURATION = int(os.environ.get("STATS_CACHE_DURATION", 1800)) -STATS_URL = os.environ.get("STATS_URL") -STATS_INDEX = int(os.environ.get("STATS_INDEX", 2)) - -# Big Blue Button configuration -BIGBLUEBUTTON_ENDPOINT = os.environ.get("BIGBLUEBUTTON_ENDPOINT") -BIGBLUEBUTTON_SECRET = os.environ.get("BIGBLUEBUTTON_SECRET") -BIGBLUEBUTTON_ANALYTICS_CALLBACK_URL = os.environ.get( - "BIGBLUEBUTTON_ANALYTICS_CALLBACK_URL" -) - -BABEL_TRANSLATION_DIRECTORIES = "/opt/bbb-visio/translations" - -EMAIL_WHITELIST = [ - r".*@(.*\.|)ac-aix-marseille\.fr$", - r".*@(.*\.|)ac-amiens\.fr$", - r".*@(.*\.|)ac-besancon\.fr$", - r".*@(.*\.|)ac-bordeaux\.fr$", - r".*@(.*\.|)ac-caen\.fr$", - r".*@(.*\.|)ac-clermont\.fr$", - r".*@(.*\.|)ac-cned\.fr$", - r".*@(.*\.|)ac-corse\.fr$", - r".*@(.*\.|)ac-creteil\.fr$", - r".*@(.*\.|)ac-dijon\.fr$", - r".*@(.*\.|)ac-grenoble\.fr$", - r".*@(.*\.|)ac-guadeloupe\.fr$", - r".*@(.*\.|)ac-guyane\.fr$", - r".*@(.*\.|)ac-lille\.fr$", - r".*@(.*\.|)ac-limoges\.fr$", - r".*@(.*\.|)ac-lyon\.fr$", - r".*@(.*\.|)ac-martinique\.fr$", - r".*@(.*\.|)ac-mayotte\.fr$", - r".*@(.*\.|)ac-montpellier\.fr$", - r".*@(.*\.|)ac-nancy-metz\.fr$", - r".*@(.*\.|)ac-nantes\.fr$", - r".*@(.*\.|)ac-nice\.fr$", - r".*@(.*\.|)ac-normandie\.fr$", - r".*@(.*\.|)ac-noumea\.nc$", - r".*@(.*\.|)ac-orleans-tours\.fr$", - r".*@(.*\.|)ac-paris\.fr$", - r".*@(.*\.|)ac-poitiers\.fr$", - r".*@(.*\.|)ac-polynesie\.pf$", - r".*@(.*\.|)ac-reims\.fr$", - r".*@(.*\.|)ac-rennes\.fr$", - r".*@(.*\.|)ac-reunion\.fr$", - r".*@(.*\.|)ac-rouen\.fr$", - r".*@(.*\.|)ac-spm\.fr$", - r".*@(.*\.|)ac-strasbourg\.fr$", - r".*@(.*\.|)ac-toulouse\.fr$", - r".*@(.*\.|)ac-versailles\.fr$", - r".*@(.*\.|)ac-wf\.wf$", - r".*@(.*\.|)acnusa\.fr$", - r".*@(.*\.|)acte-etat-civil\.fr$", - r".*@(.*\.|)ademe\.fr$", - r".*@(.*\.|)aefe\.fr$", - r".*@(.*\.|)afd\.fr$", - r".*@(.*\.|)agencebio\.org$", - r".*@(.*\.|)agence-regionale-sante\.fr$", - r".*@(.*\.|)anfr\.fr$", - r".*@(.*\.|)anses\.fr$", - r".*@(.*\.|)ansm\.sante\.fr$", - r".*@(.*\.|)aphp\.fr$", - r".*@(.*\.|)apij-justice\.fr$", - r".*@(.*\.|)arcep\.fr$", - r".*@(.*\.|)ars\.sante\.fr$", - r".*@(.*\.|)asi-aeroports\.fr$", - r".*@(.*\.|)asn\.fr$", - r".*@(.*\.|)asp-public\.fr$", - r".*@(.*\.|)assemblee-afe\.fr$", - r".*@(.*\.|)assurance-maladie\.fr$", - r".*@(.*\.|)attachefiscal\.org$", - r".*@(.*\.|)autorite-statistique-publique\.fr$", - r".*@(.*\.|)autoritedelaconcurrence\.fr$", - r".*@(.*\.|)bea\.aero$", - r".*@(.*\.|)biomedecine\.fr$", - r".*@(.*\.|)bnf\.fr$", - r".*@bnu\.fr$", - r".*@(.*\.|)businessfrance\.fr$", - r".*@(.*\.|)cabinet\.education\.fr$", - r".*@(.*\.|)cades\.fr$", - r".*@(.*\.|)ccomptes\.fr$", - r".*@(.*\.|)ccsp\.fr$", - r".*@cea\.fr$", - r".*@(.*\.|)cerema\.fr$", - r".*@(.*\.|)ch-bagneres\.fr$", - r".*@(.*\.|)ch-fidesien\.fr$", - r".*@(.*\.|)ch-lannemezan\.fr$", - r".*@(.*\.|)ch-lourdes\.fr$", - r".*@(.*\.|)ch-tarbes-vic\.fr$", - r".*@(.*\.|)chateauversailles\.fr$", - r".*@(.*\.|)chr-metz-thionville\.fr$", - r".*@chu-amiens\.fr$", - r".*@chu-montpellier\.fr$", - r".*@(.*\.|)chu-nimes\.fr$", - r".*@(.*\.|)cirad\.fr$", - r".*@(.*\.|)cnccep\.fr$", - r".*@(.*\.|)cncdh\.fr$", - r".*@(.*\.|)cnctr\.fr$", - r".*@(.*\.|)cndaspe\.fr$", - r".*@cne2\.fr$", - r".*@(.*\.|)cnil\.fr$", - r".*@(.*\.|)cnis\.fr$", - r".*@(.*\.|)cnpf\.fr$", - r".*@(.*\.|)cnr-elysee\.fr$", - r".*@(.*\.|)comite-du-label\.fr$", - r".*@(.*\.|)comite-du-secret\.fr$", - r".*@(.*\.|)commission-refugies\.fr$", - r".*@(.*\.|)conseil-concurrence\.fr$", - r".*@(.*\.|)conseil-etat\.fr$", - r".*@(.*\.|)cor-retraites\.fr$", - r".*@cre\.fr$", - r".*@crenau\.archi\.fr$", - r".*@(.*\.|)csa\.fr$", - r".*@(.*\.|)csnp\.fr$", - r".*@(.*\.|)culture\.fr$", - r".*@(.*\.|)debatpublic\.fr$", - r".*@(.*\.|)defenseurdesdroits\.fr$", - r".*@(.*\.|)dialogue-trianon\.fr$", - r".*@(.*\.|)ecoledulouvre\.fr$", - r".*@(.*\.|)efs\.sante\.fr$", - r".*@(.*\.|)elysee\.fr$", - r".*@(.*\.|)enac\.fr$", - r".*@(.*\.|)enim\.eu$", - r".*@ensai\.fr$", - r".*@(.*\.|)enssib\.fr$", - r".*@(.*\.|)ensta-paristech\.fr$", - r".*@(.*\.|)epaf\.asso\.fr$", - r".*@(.*\.|)epms-le-littoral\.net$", - r".*@(.*\.|)epms-le-littoral\.org$", - r".*@(.*\.|)erafp\.fr$", - r".*@(.*\.|)espace.gouv\.fr$", - r".*@(.*\.|)europol\.europa\.eu$", - r".*@(.*\.|)europolhq\.net$", - r".*@(.*\.|)fete-gastronomie\.fr$", - r".*@(.*\.|)fnap-logement\.fr$", - r".*@(.*\.|)fr\.europol\.net$", - r".*@(.*\.|)franceagrimer\.fr$", - r".*@(.*\.|)francemobilites\.fr$", - r".*@(.*\.|)frenchmobility\.fr$", - r".*@fun-mooc\.fr$", - r".*@(.*\.|)gouv\.fr$", - r".*@(.*\.|)guimet\.fr$", - r".*@(.*\.|)granddebat\.fr$", - r".*@(.*\.|)has-sante\.fr$", - r".*@(.*\.|)hautconseilclimat\.fr$", - r".*@(.*\.|)hautconseildesbiotechnologies\.fr$", - r".*@(.*\.|)hceres\.fr$", - r".*@(.*\.|)hcf-famille\.fr$", - r".*@(.*\.|)hcfp\.fr$", - r".*@(.*\.|)hebergement2\.interieur-gouv\.fr$", - r".*@(.*\.|)hebergement\.interieur-gouv\.fr$", - r".*@(.*\.|)hopital-le-montaigu\.com$", - r".*@(.*\.|)i-carre\.net$", - r".*@ibcp\.fr$", - r".*@(.*\.|)idda13\.fr$", - r".*@(.*\.|)ifce\.fr$", - r".*@(.*\.|)ign\.fr$", - r".*@ihedn\.fr$", - r".*@(.*\.|)ihest\.fr$", - r".*@(.*\.|)inha\.fr$", - r".*@(.*\.|)inhesj\.fr$", - r".*@(.*\.|)injep\.fr$", - r".*@(.*\.|)inp\.fr$", - r".*@(.*\.|)inpi\.fr$", - r".*@(.*\.|)inra\.fr$", - r".*@(.*\.|)inrae\.fr$", - r".*@(.*\.|)inrap\.fr$", - r".*@(.*\.|)inria\.fr$", - r".*@(.*\.|)insee\.fr$", - r".*@(.*\.|)insep\.fr$", - r".*@(.*\.|)institutcancer\.fr$", - r".*@(.*\.|)ints\.fr$", - r".*@iralille\.fr$", - r".*@ira-lille\.fr$", - r".*@(.*\.|)irisa\.fr$", - r".*@(.*\.|)irstea\.fr$", - r".*@(.*\.|)juradm\.fr$", - r".*@(.*\.|)justice\.fr$", - r".*@(.*\.|)ladocumentationfrancaise\.fr$", - r".*@(.*\.|)loria\.fr$", - r".*@(.*\.|)louvre\.fr$", - r".*@(.*\.|)medecine-de-proximite\.fr$", - r".*@(.*\.|)meteofrance\.fr$", - r".*@(.*\.|)mrccfr\.eu$", - r".*@(.*\.|)mrscfr\.eu$", - r".*@(.*\.|)mucem\.org$", - r".*@(.*\.|)musee-orangerie\.fr$", - r".*@(.*\.|)musee-orsay\.fr$", - r".*@(.*\.|)museepicassoparis.fr$", - r".*@(.*\.|)musee-rodin\.fr$", - r".*@(.*\.|)nancy\.archi\.fr$", - r".*@nantes\.archi$", - r".*@nantes\.archi\.fr$", - r".*@(.*\.|)notification\.service-public\.fr$", - r".*@(.*\.|)odeadom\.fr$", - r".*@(.*\.|)ofgl\.fr$", - r".*@(.*\.|)ofii\.fr$", - r".*@(.*\.|)onf\.fr$", - r".*@(.*\.|)oniam\.fr$", - r".*@parcoursup\.fr$", - r".*@(.*\.|)pibude\.com$", - r".*@(.*\.|)point-info-famille\.fr$", - r".*@(.*\.|)pointinfofamille\.fr$", - r".*@(.*\.|)region-academique-aura\.fr$", - r".*@(.*\.|)region-academique-auvergne-rhone-alpes\.fr$", - r".*@(.*\.|)region-academique-bfc\.fr$", - r".*@(.*\.|)region-academique-bourgogne-franche-comte\.fr$", - r".*@(.*\.|)region-academique-bretagne\.fr$", - r".*@(.*\.|)region-academique-centre-val-de-loire\.fr$", - r".*@(.*\.|)region-academique-corse\.fr$", - r".*@(.*\.|)region-academique-grand-est\.fr$", - r".*@(.*\.|)region-academique-guadeloupe\.fr$", - r".*@(.*\.|)region-academique-guyane\.fr$", - r".*@(.*\.|)region-academique-hauts-de-france\.fr$", - r".*@(.*\.|)region-academique-idf\.fr$", - r".*@(.*\.|)region-academique-ile-de-france\.fr$", - r".*@(.*\.|)region-academique-martinique\.fr$", - r".*@(.*\.|)region-academique-mayotte\.fr$", - r".*@(.*\.|)region-academique-normandie\.fr$", - r".*@(.*\.|)region-academique-nouvelle-aquitaine\.fr$", - r".*@(.*\.|)region-academique-occitanie\.fr$", - r".*@(.*\.|)region-academique-paca\.fr$", - r".*@(.*\.|)region-academique-pays-de-la-loire\.fr$", - r".*@(.*\.|)region-academique-provence-alpes-cote-dazur\.fr$", - r".*@(.*\.|)region-academique-reunion\.fr$", - r".*@(.*\.|)regis-dgac\.net$", - r".*@renater\.fr$", - r".*@(.*\.|)santepubliquefrance\.fr$", - r".*@(.*\.|)service-eco\.fr$", - r".*@(.*\.|)service-public\.fr$", - r".*@(.*\.|)service-public\.fr\.preprod\.ext\.dila\.fr$", - r".*@(.*\.|)service-public\.fr\.qualif\.ext\.dila\.fr$", - r".*@(.*\.|)sevresciteceramique\.fr$", - r".*@(.*\.|)shom\.fr$", - r".*@societedugrandparis\.fr$", - r".*@(.*\.|)taaf\.fr$", - r".*@(.*\.|)telerecours\.fr$", - r".*@(.*\.|)theatre-odeon\.fr$", - r".*@(.*\.|)ugap\.fr$", - r".*@(.*\.|)unedic\.fr$", - r".*@univ-orleans\.fr$", - r".*@(.*\.|)univ-paris13\.fr$", - r".*@univ-perp\.fr$", - r".*@(.*\.|)vie-publique\.fr$", - r".*@(.*\.|)vnf\.fr$", - r".*@univ-ubs\.fr$", - r".*@sdis(?!00|20|69|75|96|97|98|99)[0-9]{2}.fr$", - r".*@sdis-vendee.fr$", - r".*@sdis21.org$", - r".*@sdis36.org$", - r".*@sdis67.com$", - r".*@sdis86.net$", - r".*@sdis97[1-3].fr$", - r".*@sdis976.fr$", - r".*@sdis974.re$", - r".*@(.*\.|)intranet-sdis11\.fr$", - r".*@pompiersparis\.fr$", - r".*@chu-angers\.fr$", - r".*@ensc-rennes\.fr$", - r".*@educagri\.fr$", - r".*@fiva\.fr$", - r".*@assurance-maladie\.fr$", - r".*@crous-aix-marseille\.fr$", - r".*@crous-amiens\.fr$", - r".*@crous-antillesguyane\.fr$", - r".*@crous-bordeaux\.fr$", - r".*@crous-bfc\.fr$", - r".*@crous-clermont\.fr$", - r".*@crous-corse\.fr$", - r".*@crous-creteil\.fr$", - r".*@crous-grenoble\.fr$", - r".*@crous-reunion\.fr$", - r".*@crous-lille\.fr$", - r".*@crous-limoges\.fr$", - r".*@crous-lorraine\.fr$", - r".*@crous-lyon\.fr$", - r".*@crous-montpellier\.fr$", - r".*@crous-nantes\.fr$", - r".*@crous-nice\.fr$", - r".*@crous-normandie\.fr$", - r".*@crous-orleans-tours\.fr$", - r".*@crous-paris\.fr$", - r".*@crous-poitiers\.fr$", - r".*@crous-reims\.fr$", - r".*@crous-strasbourg\.fr$", - r".*@crous-versailles\.fr$", - r".*@crous-rennes\.fr$", - r".*@crous-toulouse\.fr$", - r".*@(.*\.|)assemblee-nationale\.fr$", - r".*@(.*\.|)senat\.fr$", - r".*@ird.fr$", - r".*@ch-chatillon.fr$", - r".*@ch-buzancais.fr$", -] diff --git a/web/migrations/alembic_helpers.py b/web/migrations/alembic_helpers.py index ab1fd978..a6b84d3d 100644 --- a/web/migrations/alembic_helpers.py +++ b/web/migrations/alembic_helpers.py @@ -1,7 +1,7 @@ # Code based on https://github.com/talkpython/data-driven-web-apps-with-flask from alembic import op -from sqlalchemy import engine_from_config from sqlalchemy import MetaData +from sqlalchemy import engine_from_config def load_schema(): @@ -32,11 +32,9 @@ def table_does_not_exist(table): def table_has_column(table, column): schema = load_schema() has_column = False - print(table, flush=True) if table not in schema: return for s_column in schema[table]: - print(" %s" % s_column, flush=True) if column == s_column: has_column = True return has_column diff --git a/web/migrations/env.py b/web/migrations/env.py index 48a6609b..300611f0 100644 --- a/web/migrations/env.py +++ b/web/migrations/env.py @@ -34,14 +34,12 @@ def run_migrations_offline(): """Run migrations in 'offline' mode. - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. + This configures the context with just a URL and not an Engine, + though an Engine is acceptable here as well. By skipping the Engine + creation we don't even need a DBAPI to be available. + Calls to context.execute() here emit the given string to the script + output. """ url = config.get_main_option("sqlalchemy.url") context.configure(url=url, target_metadata=target_metadata, literal_binds=True) @@ -53,9 +51,8 @@ def run_migrations_offline(): def run_migrations_online(): """Run migrations in 'online' mode. - In this scenario we need to create an Engine - and associate a connection with the context. - + In this scenario we need to create an Engine and associate a + connection with the context. """ # this callback is used to prevent an auto-migration from being generated @@ -79,7 +76,7 @@ def process_revision_directives(context, revision, directives): connection=connection, target_metadata=target_metadata, process_revision_directives=process_revision_directives, - **current_app.extensions["migrate"].configure_args + **current_app.extensions["migrate"].configure_args, ) with context.begin_transaction(): diff --git a/web/migrations/versions/1094e771bd3f_create_meeting_files_table.py b/web/migrations/versions/1094e771bd3f_create_meeting_files_table.py index 7c6522a3..bd7c607a 100644 --- a/web/migrations/versions/1094e771bd3f_create_meeting_files_table.py +++ b/web/migrations/versions/1094e771bd3f_create_meeting_files_table.py @@ -1,10 +1,10 @@ -"""create_meeting_files_table +"""create_meeting_files_table. Revision ID: 1094e771bd3f Revises: 8fe077ecfb10 Create Date: 2023-02-28 14:30:43.642893 - """ + import os import sys @@ -17,7 +17,6 @@ import alembic_helpers - # revision identifiers, used by Alembic. revision = "1094e771bd3f" down_revision = "8fe077ecfb10" diff --git a/web/migrations/versions/54f71a7705a8_initial_tables2.py b/web/migrations/versions/54f71a7705a8_initial_tables2.py index d861b77e..979ab6cb 100644 --- a/web/migrations/versions/54f71a7705a8_initial_tables2.py +++ b/web/migrations/versions/54f71a7705a8_initial_tables2.py @@ -1,10 +1,10 @@ -"""Initial tables2 +"""Initial tables2. Revision ID: 54f71a7705a8 Revises: Create Date: 2023-01-03 18:01:03.770238 - """ + import os import sys diff --git a/web/migrations/versions/65acbe9b0646_add_user_nextcloud_connection_info.py b/web/migrations/versions/65acbe9b0646_add_user_nextcloud_connection_info.py index 2b2cd880..df6c8065 100644 --- a/web/migrations/versions/65acbe9b0646_add_user_nextcloud_connection_info.py +++ b/web/migrations/versions/65acbe9b0646_add_user_nextcloud_connection_info.py @@ -1,10 +1,10 @@ -"""add_user_nextcloud_connection_info +"""add_user_nextcloud_connection_info. Revision ID: 65acbe9b0646 Revises: 1094e771bd3f Create Date: 2023-02-28 14:35:21.691915 - """ + import os import sys @@ -17,7 +17,6 @@ import alembic_helpers - # revision identifiers, used by Alembic. revision = "65acbe9b0646" down_revision = "1094e771bd3f" diff --git a/web/migrations/versions/7d80b9223a1e_guestpolicy_migration.py b/web/migrations/versions/7d80b9223a1e_guestpolicy_migration.py index 2bb82700..2c9467d4 100644 --- a/web/migrations/versions/7d80b9223a1e_guestpolicy_migration.py +++ b/web/migrations/versions/7d80b9223a1e_guestpolicy_migration.py @@ -1,10 +1,10 @@ -"""GuestPolicy migration +"""GuestPolicy migration. Revision ID: 7d80b9223a1e Revises: 54f71a7705a8 Create Date: 2023-02-28 14:29:28.456201 - """ + import os import sys @@ -17,7 +17,6 @@ import alembic_helpers - # revision identifiers, used by Alembic. revision = "7d80b9223a1e" down_revision = "54f71a7705a8" diff --git a/web/migrations/versions/8fe077ecfb10_add_last_connection_utc_datetime.py b/web/migrations/versions/8fe077ecfb10_add_last_connection_utc_datetime.py index b2e6a37f..08fa9abb 100644 --- a/web/migrations/versions/8fe077ecfb10_add_last_connection_utc_datetime.py +++ b/web/migrations/versions/8fe077ecfb10_add_last_connection_utc_datetime.py @@ -1,10 +1,10 @@ -"""add last_connection_utc_datetime +"""Add last_connection_utc_datetime. Revision ID: 8fe077ecfb10 Revises: 9aac3b5e1582 Create Date: 2022-08-12 09:09:47.674373 - """ + import os import sys @@ -17,7 +17,6 @@ import alembic_helpers - # revision identifiers, used by Alembic. revision = "8fe077ecfb10" down_revision = "9aac3b5e1582" diff --git a/web/migrations/versions/9aac3b5e1582_welcome_message_unbound.py b/web/migrations/versions/9aac3b5e1582_welcome_message_unbound.py index b54a7abb..2292b2a3 100644 --- a/web/migrations/versions/9aac3b5e1582_welcome_message_unbound.py +++ b/web/migrations/versions/9aac3b5e1582_welcome_message_unbound.py @@ -1,10 +1,10 @@ -"""Welcome message unbound +"""Welcome message unbound. Revision ID: 9aac3b5e1582 Revises: 7d80b9223a1e Create Date: 2021-05-06 17:44:17.835474 - """ + import os import sys diff --git a/web/migrations/versions/9d4ba8cf710a_remove_obsolete_meeting_attributes.py b/web/migrations/versions/9d4ba8cf710a_remove_obsolete_meeting_attributes.py index 9ce872c2..ccdc4f30 100644 --- a/web/migrations/versions/9d4ba8cf710a_remove_obsolete_meeting_attributes.py +++ b/web/migrations/versions/9d4ba8cf710a_remove_obsolete_meeting_attributes.py @@ -1,14 +1,13 @@ -"""remove obsolete meeting attributes +"""Remove obsolete meeting attributes. Revision ID: 9d4ba8cf710a Revises: 65acbe9b0646 Create Date: 2022-08-12 15:43:01.721995 - """ + import sqlalchemy as sa from alembic import op - # revision identifiers, used by Alembic. revision = "9d4ba8cf710a" down_revision = "65acbe9b0646" diff --git a/web/misc/gunicorn.py b/web/misc/gunicorn.py index 89f4b8f0..658c5b05 100644 --- a/web/misc/gunicorn.py +++ b/web/misc/gunicorn.py @@ -202,8 +202,8 @@ def when_ready(server): def worker_int(worker): worker.log.info("worker received INT or QUIT signal") ## get traceback info - import threading import sys + import threading import traceback id2name = {th.ident: th.name for th in threading.enumerate()} diff --git a/web/misc/run_webserver.sh b/web/misc/run_webserver.sh index 730f81d2..4f2658b1 100644 --- a/web/misc/run_webserver.sh +++ b/web/misc/run_webserver.sh @@ -1,6 +1,6 @@ #!/bin/bash # DB Migration -flask db upgrade >> /var/log/flask-migrate.log +flask db upgrade &>> /var/log/flask-migrate.log gunicorn --chdir /opt/bbb-visio --bind 0.0.0.0:5000 --log-level warning --access-logfile /var/log/gunicorn-access.log --error-logfile /var/log/gunicorn-error.log wsgi:app diff --git a/web/misc/wsgi.py b/web/misc/wsgi.py index 999b4d77..49b207f2 100644 --- a/web/misc/wsgi.py +++ b/web/misc/wsgi.py @@ -1,3 +1,3 @@ -from flaskr import create_app +from b3desk import create_app app = create_app() diff --git a/web/requirements.app.txt b/web/requirements.app.txt index 38ff8750..4cb192d2 100644 --- a/web/requirements.app.txt +++ b/web/requirements.app.txt @@ -1,72 +1,73 @@ -alembic==1.11.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -amqp==5.1.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -annotated-types==0.5.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -async-timeout==4.0.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -babel==2.12.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +alembic==1.13.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +amqp==5.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +annotated-types==0.6.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +async-timeout==4.0.3 ; python_full_version >= "3.8.1" and python_full_version < "3.11.3" +babel==2.14.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +backports-zoneinfo==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9" backports-zoneinfo[tzdata]==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9" -billiard==3.6.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +billiard==4.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +blinker==1.7.0 ; python_full_version >= "3.8.1" and python_version < "4.0" cachelib==0.9.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -celery==5.2.7 ; python_full_version >= "3.8.1" and python_version < "4.0" -certifi==2023.7.22 ; python_full_version >= "3.8.1" and python_version < "4.0" -cffi==1.15.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -charset-normalizer==3.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -click-didyoumean==0.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +celery==5.3.6 ; python_full_version >= "3.8.1" and python_version < "4.0" +certifi==2024.2.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +cffi==1.16.0 ; python_full_version >= "3.8.1" and python_version < "4.0" and platform_python_implementation != "PyPy" +charset-normalizer==3.3.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +click-didyoumean==0.3.1 ; python_full_version >= "3.8.1" and python_version < "4.0" click-plugins==1.1.1 ; python_full_version >= "3.8.1" and python_version < "4.0" click-repl==0.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0" click==8.1.7 ; python_full_version >= "3.8.1" and python_version < "4.0" colorama==0.4.6 ; python_full_version >= "3.8.1" and python_version < "4.0" and platform_system == "Windows" -cryptography==41.0.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +cryptography==42.0.5 ; python_full_version >= "3.8.1" and python_version < "4.0" defusedxml==0.7.1 ; python_full_version >= "3.8.1" and python_version < "4.0" filetype==1.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -flask-babel==2.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -flask-caching==2.0.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -flask-migrate==3.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -flask-pyoidc==3.14.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-babel==4.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-caching==2.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-migrate==4.0.7 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-pyoidc==3.14.3 ; python_full_version >= "3.8.1" and python_version < "4.0" flask-sqlalchemy==3.0.5 ; python_full_version >= "3.8.1" and python_version < "4.0" flask-uploads==0.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -flask-wtf==1.1.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -flask==2.2.5 ; python_full_version >= "3.8.1" and python_version < "4.0" -future==0.18.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -gitdb==4.0.10 ; python_full_version >= "3.8.1" and python_version < "4.0" -gitpython==3.1.38 ; python_full_version >= "3.8.1" and python_version < "4.0" -greenlet==2.0.2 ; python_full_version >= "3.8.1" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" -gunicorn==20.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -idna==3.4 ; python_full_version >= "3.8.1" and python_version < "4.0" -importlib-metadata==6.8.0 ; python_full_version >= "3.8.1" and python_version < "3.10" -importlib-resources==6.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-wtf==1.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask==3.0.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +future==1.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +greenlet==3.0.3 ; python_full_version >= "3.8.1" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" +gunicorn==21.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +idna==3.6 ; python_full_version >= "3.8.1" and python_version < "4.0" +importlib-metadata==7.1.0 ; python_full_version >= "3.8.1" and python_version < "3.10" +importlib-resources==6.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" itsdangerous==2.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -jinja2==3.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -kombu==5.3.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -lxml==4.9.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -mako==1.2.4 ; python_full_version >= "3.8.1" and python_version < "4.0" -markupsafe==2.1.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -netaddr==0.8.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +jinja2==3.1.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +kombu==5.3.6 ; python_full_version >= "3.8.1" and python_version < "4.0" +lxml==5.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +mako==1.3.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +markupsafe==2.1.5 ; python_full_version >= "3.8.1" and python_version < "4.0" +netaddr==1.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" oic==1.6.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -prompt-toolkit==3.0.39 ; python_full_version >= "3.8.1" and python_version < "4.0" -psycopg2==2.9.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -pycparser==2.21 ; python_full_version >= "3.8.1" and python_version < "4.0" -pycryptodomex==3.18.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -pydantic-core==2.6.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -pydantic-settings==2.0.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -pydantic==2.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +packaging==24.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +prompt-toolkit==3.0.43 ; python_full_version >= "3.8.1" and python_version < "4.0" +psycopg2==2.9.9 ; python_full_version >= "3.8.1" and python_version < "4.0" +pycparser==2.22 ; python_full_version >= "3.8.1" and python_version < "4.0" and platform_python_implementation != "PyPy" +pycryptodomex==3.20.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pydantic-core==2.16.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +pydantic-settings==2.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +pydantic==2.6.4 ; python_full_version >= "3.8.1" and python_version < "4.0" pyjwkest==1.4.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -python-dateutil==2.8.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -python-dotenv==1.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -pytz==2023.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -redis==4.4.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +python-dateutil==2.9.0.post0 ; python_full_version >= "3.8.1" and python_version < "4.0" +python-dotenv==1.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +python-slugify==8.0.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +pytz==2024.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +redis==5.0.3 ; python_full_version >= "3.8.1" and python_version < "4.0" requests==2.31.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -setuptools==68.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" six==1.16.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -smmap==5.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -sqlalchemy-json==0.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -sqlalchemy-utils==0.38.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -sqlalchemy==1.4.31 ; python_full_version >= "3.8.1" and python_version < "4.0" -typing-extensions==4.7.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -tzdata==2023.3 ; python_full_version >= "3.8.1" and python_version < "3.9" -urllib3==2.0.4 ; python_full_version >= "3.8.1" and python_version < "4.0" -vine==5.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -wcwidth==0.2.6 ; python_full_version >= "3.8.1" and python_version < "4.0" +sqlalchemy-json==0.7.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +sqlalchemy-utils==0.41.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +sqlalchemy==1.4.52 ; python_full_version >= "3.8.1" and python_version < "4.0" +text-unidecode==1.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +typing-extensions==4.10.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +tzdata==2024.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +urllib3==2.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +vine==5.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +wcwidth==0.2.13 ; python_full_version >= "3.8.1" and python_version < "4.0" webdavclient3==3.14.6 ; python_full_version >= "3.8.1" and python_version < "4.0" -werkzeug==2.2.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -wtforms==3.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -zipp==3.16.2 ; python_full_version >= "3.8.1" and python_version < "3.10" +werkzeug==3.0.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +wtforms==3.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +zipp==3.18.1 ; python_full_version >= "3.8.1" and python_version < "3.10" diff --git a/web/requirements.dev.txt b/web/requirements.dev.txt index 3879eb9b..7d3b6cb1 100644 --- a/web/requirements.dev.txt +++ b/web/requirements.dev.txt @@ -1,50 +1,74 @@ -beautifulsoup4==4.12.2 ; python_full_version >= "3.8.1" and python_version < "4" -black==23.7.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -blinker==1.6.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +aiosmtpd==1.4.5 ; python_full_version >= "3.8.1" and python_version < "4" +annotated-types==0.6.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +atpublic==4.1.0 ; python_full_version >= "3.8.1" and python_version < "4" +attrs==23.2.0 ; python_full_version >= "3.8.1" and python_version < "4" +authlib==1.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +beautifulsoup4==4.12.3 ; python_full_version >= "3.8.1" and python_version < "4" +blinker==1.7.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +canaille[oidc]==0.0.44 ; python_full_version >= "3.8.1" and python_version < "4.0" +cffi==1.16.0 ; python_full_version >= "3.8.1" and python_version < "4" and platform_python_implementation != "PyPy" cfgv==3.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" click==8.1.7 ; python_full_version >= "3.8.1" and python_version < "4.0" colorama==0.4.6 ; python_full_version >= "3.8.1" and python_version < "4.0" and (sys_platform == "win32" or platform_system == "Windows") -coverage==7.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -coverage[toml]==7.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -distlib==0.3.7 ; python_full_version >= "3.8.1" and python_version < "4.0" -exceptiongroup==1.1.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -filelock==3.12.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -flake8==6.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -flask-webtest==0.1.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -flask==2.2.5 ; python_full_version >= "3.8.1" and python_version < "4.0" -freezegun==1.2.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -identify==2.5.27 ; python_full_version >= "3.8.1" and python_version < "4.0" -importlib-metadata==6.8.0 ; python_full_version >= "3.8.1" and python_version < "3.10" +coverage==7.4.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +coverage[toml]==7.4.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +cryptography==42.0.5 ; python_full_version >= "3.8.1" and python_version < "4" +cssselect==1.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +defusedxml==0.7.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +distlib==0.3.8 ; python_full_version >= "3.8.1" and python_version < "4.0" +enum-extend==0.1.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +exceptiongroup==1.2.0 ; python_full_version >= "3.8.1" and python_version < "3.11" +faker==24.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +filelock==3.13.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +flake8==7.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-webtest==0.1.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-wtf==1.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask==3.0.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +freezegun==1.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +identify==2.5.35 ; python_full_version >= "3.8.1" and python_version < "4.0" +importlib-metadata==7.1.0 ; python_full_version >= "3.8.1" and python_version < "3.10" iniconfig==2.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" itsdangerous==2.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -jinja2==3.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -markupsafe==2.1.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +jinja2==3.1.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +json5==0.9.24 ; python_full_version >= "3.8.1" and python_version < "4.0" +lxml==5.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +markupsafe==2.1.5 ; python_full_version >= "3.8.1" and python_version < "4.0" mccabe==0.7.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -mypy-extensions==1.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" nodeenv==1.8.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -packaging==23.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -pathspec==0.11.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -platformdirs==3.10.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -pluggy==1.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -pre-commit==3.3.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -pycodestyle==2.11.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -pyflakes==3.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -pytest-cov==4.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +packaging==24.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +platformdirs==4.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pluggy==1.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +portpicker==1.6.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pre-commit==3.5.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +psutil==5.9.8 ; python_full_version >= "3.8.1" and python_version < "4.0" +pycodestyle==2.11.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +pycparser==2.22 ; python_full_version >= "3.8.1" and python_version < "4" and platform_python_implementation != "PyPy" +pydantic-core==2.16.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +pydantic-settings==2.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +pydantic==2.6.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +pyflakes==3.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pyquery==2.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pytest-cov==5.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" pytest-dotenv==0.5.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -pytest-flask==1.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -pytest-mock==3.11.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -pytest==7.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -python-dateutil==2.8.2 ; python_full_version >= "3.8.1" and python_version < "4.0" -python-dotenv==1.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pytest-iam==0.0.8 ; python_full_version >= "3.8.1" and python_version < "4.0" +pytest-mock==3.14.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pytest-smtpd==0.1.0 ; python_full_version >= "3.8.1" and python_version < "4" +pytest==8.1.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +python-dateutil==2.9.0.post0 ; python_full_version >= "3.8.1" and python_version < "4.0" +python-dotenv==1.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" pyyaml==6.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" -setuptools==68.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +setuptools==69.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" six==1.16.0 ; python_full_version >= "3.8.1" and python_version < "4.0" -soupsieve==2.4.1 ; python_full_version >= "3.8.1" and python_version < "4" -tomli==2.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -typing-extensions==4.7.1 ; python_full_version >= "3.8.1" and python_version < "3.10" -virtualenv==20.24.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -waitress==2.1.2 ; python_full_version >= "3.8.1" and python_version < "4" +smtpdfix==0.5.1 ; python_full_version >= "3.8.1" and python_version < "4" +soupsieve==2.5 ; python_full_version >= "3.8.1" and python_version < "4" +sphinx-enum-extend==0.1.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +tomli==2.0.1 ; python_full_version >= "3.8.1" and python_full_version <= "3.11.0a6" +typing-extensions==4.10.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +virtualenv==20.25.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +waitress==3.0.0 ; python_full_version >= "3.8.1" and python_version < "4" webob==1.8.7 ; python_full_version >= "3.8.1" and python_version < "4" webtest==3.0.0 ; python_full_version >= "3.8.1" and python_version < "4" -werkzeug==2.2.3 ; python_full_version >= "3.8.1" and python_version < "4.0" -zipp==3.16.2 ; python_full_version >= "3.8.1" and python_version < "3.10" +werkzeug==3.0.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +wsgidav==4.3.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +wtforms==3.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +zipp==3.18.1 ; python_full_version >= "3.8.1" and python_version < "3.10" diff --git a/web/requirements.doc.txt b/web/requirements.doc.txt new file mode 100644 index 00000000..f1838552 --- /dev/null +++ b/web/requirements.doc.txt @@ -0,0 +1,94 @@ +alabaster==0.7.13 ; python_full_version >= "3.8.1" and python_version < "4.0" +alembic==1.13.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +amqp==5.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +annotated-types==0.6.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +async-timeout==4.0.3 ; python_full_version >= "3.8.1" and python_full_version < "3.11.3" +autodoc-pydantic==2.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +babel==2.14.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +backports-zoneinfo==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9" +backports-zoneinfo[tzdata]==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9" +billiard==4.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +blinker==1.7.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +cachelib==0.9.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +celery==5.3.6 ; python_full_version >= "3.8.1" and python_version < "4.0" +certifi==2024.2.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +cffi==1.16.0 ; python_full_version >= "3.8.1" and python_version < "4.0" and platform_python_implementation != "PyPy" +charset-normalizer==3.3.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +click-didyoumean==0.3.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +click-plugins==1.1.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +click-repl==0.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +click==8.1.7 ; python_full_version >= "3.8.1" and python_version < "4.0" +colorama==0.4.6 ; python_full_version >= "3.8.1" and python_version < "4.0" and (sys_platform == "win32" or platform_system == "Windows") +cryptography==42.0.5 ; python_full_version >= "3.8.1" and python_version < "4.0" +defusedxml==0.7.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +docutils==0.20.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +filetype==1.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-babel==4.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-caching==2.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-migrate==4.0.7 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-pyoidc==3.14.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-sqlalchemy==3.0.5 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-uploads==0.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask-wtf==1.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +flask==3.0.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +future==1.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +greenlet==3.0.3 ; python_full_version >= "3.8.1" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0" +gunicorn==21.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +idna==3.6 ; python_full_version >= "3.8.1" and python_version < "4.0" +imagesize==1.4.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +importlib-metadata==7.1.0 ; python_full_version >= "3.8.1" and python_version < "3.10" +importlib-resources==6.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +itsdangerous==2.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +jinja2==3.1.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +kombu==5.3.6 ; python_full_version >= "3.8.1" and python_version < "4.0" +lxml==5.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +mako==1.3.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +markdown-it-py==3.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +markupsafe==2.1.5 ; python_full_version >= "3.8.1" and python_version < "4.0" +mdit-py-plugins==0.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +mdurl==0.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +myst-parser==2.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +netaddr==1.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +oic==1.6.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +packaging==24.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +prompt-toolkit==3.0.43 ; python_full_version >= "3.8.1" and python_version < "4.0" +psycopg2==2.9.9 ; python_full_version >= "3.8.1" and python_version < "4.0" +pycparser==2.22 ; python_full_version >= "3.8.1" and python_version < "4.0" and platform_python_implementation != "PyPy" +pycryptodomex==3.20.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pydantic-core==2.16.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +pydantic-settings==2.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +pydantic==2.6.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +pygments==2.17.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +pyjwkest==1.4.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +python-dateutil==2.9.0.post0 ; python_full_version >= "3.8.1" and python_version < "4.0" +python-dotenv==1.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +python-slugify==8.0.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +pytz==2024.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +pyyaml==6.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +redis==5.0.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +requests==2.31.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +six==1.16.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +snowballstemmer==2.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinx-issues==4.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinx-rtd-theme==2.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinx==7.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinxcontrib-applehelp==1.0.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinxcontrib-devhelp==1.0.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinxcontrib-htmlhelp==2.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinxcontrib-jquery==4.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinxcontrib-jsmath==1.0.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinxcontrib-qthelp==1.0.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +sphinxcontrib-serializinghtml==1.1.5 ; python_full_version >= "3.8.1" and python_version < "4.0" +sqlalchemy-json==0.7.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +sqlalchemy-utils==0.41.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +sqlalchemy==1.4.52 ; python_full_version >= "3.8.1" and python_version < "4.0" +text-unidecode==1.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +typing-extensions==4.10.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +tzdata==2024.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +urllib3==2.2.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +vine==5.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +wcwidth==0.2.13 ; python_full_version >= "3.8.1" and python_version < "4.0" +webdavclient3==3.14.6 ; python_full_version >= "3.8.1" and python_version < "4.0" +werkzeug==3.0.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +wtforms==3.1.2 ; python_full_version >= "3.8.1" and python_version < "4.0" +zipp==3.18.1 ; python_full_version >= "3.8.1" and python_version < "3.10" diff --git a/web/tests/conftest.py b/web/tests/conftest.py index 65bff33d..fa803826 100644 --- a/web/tests/conftest.py +++ b/web/tests/conftest.py @@ -1,59 +1,116 @@ -import functools +import threading import time +import uuid +import wsgiref +from pathlib import Path -import flaskr.utils +import portpicker import pytest from flask_migrate import Migrate from flask_webtest import TestApp -from flaskr import create_app +from wsgidav.fs_dav_provider import FilesystemProvider +from wsgidav.wsgidav_app import WsgiDAVApp +import b3desk.utils +from b3desk import create_app -flaskr.utils.secret_key = lambda: "AZERTY" +b3desk.utils.secret_key = lambda: "AZERTY" +from b3desk.models import db -from flaskr.models import Meeting, User, db - -class FakeAuth: - def token_auth(self, provider_name): - def token_decorator(view_func): - @functools.wraps(view_func) - def wrapper(*args, **kwargs): - return view_func(*args, **kwargs) - - return wrapper - - return token_decorator - - def oidc_auth(self, provider_name): - def token_decorator(view_func): - @functools.wraps(view_func) - def wrapper(*args, **kwargs): - return view_func(*args, **kwargs) - - return wrapper - - return token_decorator - - def oidc_logout(self, view_func): - @functools.wraps(view_func) - def wrapper(*args, **kwargs): - return view_func(*args, **kwargs) - - return wrapper +@pytest.fixture +def iam_user(iam_server): + iam_user = iam_server.random_user( + id="user_id", + emails=["alice@domain.tld"], + given_name="Alice", + user_name="Alice_user_name", + family_name="Cooper", + ) + iam_user.save() + + yield iam_user + iam_user.delete() + + +@pytest.fixture +def iam_client(iam_server): + iam_client = iam_server.models.Client( + client_id="client_id", + client_secret="client_secret", + redirect_uris=["http://localhost:5000/oidc_callback"], + token_endpoint_auth_method="client_secret_post", + post_logout_redirect_uris=["http://localhost:5000/logout"], + grant_types=["authorization_code"], + response_types=["code", "token", "id_token"], + scope=["openid", "profile", "email"], + preconsent=True, + ) + iam_client.audience = [iam_client] + iam_client.save() + yield iam_client + iam_client.delete() -@pytest.fixture() -def app(mocker): - mocker.patch("flask_pyoidc.OIDCAuthentication", return_value=FakeAuth()) - app = create_app( - test_config={ - "SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:", - "WTF_CSRF_ENABLED": False, - "TESTING": True, - "BIGBLUEBUTTON_ENDPOINT": "https://bbb.test", - "OIDC_ATTENDEE_ISSUER": "http://oidc-server.test", - } +@pytest.fixture +def iam_token(iam_server, iam_client, iam_user): + iam_token = iam_server.random_token( + client=iam_client, + subject=iam_user, ) + yield iam_token + iam_token.delete() + + +@pytest.fixture +def configuration(tmp_path, iam_server, iam_client, smtpd): + smtpd.config.use_starttls = True + return { + "SECRET_KEY": "test-secret-key", + "SERVER_NAME": "localhost:5000", + "PREFERRED_URL_SCHEME": "http", + "SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:", + "WTF_CSRF_ENABLED": False, + "TESTING": True, + "BIGBLUEBUTTON_ENDPOINT": "https://bbb.test", + "OIDC_ISSUER": iam_server.url, + "OIDC_REDIRECT_URI": iam_client.redirect_uris[0], + "OIDC_CLIENT_ID": iam_client.client_id, + "OIDC_CLIENT_SECRET": iam_client.client_secret, + "OIDC_CLIENT_AUTH_METHOD": iam_client.token_endpoint_auth_method, + "OIDC_SCOPES": iam_client.scope, + "OIDC_USERINFO_HTTP_METHOD": "GET", + "UPLOAD_DIR": str(tmp_path), + "TMP_DOWNLOAD_DIR": str(tmp_path), + "RECORDING": True, + "BIGBLUEBUTTON_ANALYTICS_CALLBACK_URL": "https://bbb-analytics-staging.osc-fr1.scalingo.io/v1/post_events", + "MEETING_KEY_WORDING": "seminaire", + "QUICK_MEETING_LOGOUT_URL": "http://education.gouv.fr/", + "FORCE_HTTPS_ON_EXTERNAL_URLS": False, + "NC_LOGIN_API_URL": "http://tokenmock:80/index.php", + "NC_LOGIN_API_KEY": "MY-TOTALLY-COOL-API-KEY", + "FILE_SHARING": True, + # Overwrite the web.env values for tests running in docker + "STATS_URL": None, + "CACHE_TYPE": "SimpleCache", + # Disable cache in unit tests + "CACHE_DEFAULT_TIMEOUT": 0, + "BIGBLUEBUTTON_API_CACHE_DURATION": 0, + "MEETING_LOGOUT_URL": "https://example.org/logout", + "MAIL_MEETING": True, + "SMTP_FROM": "from@example.org", + "SMTP_HOST": smtpd.hostname, + "SMTP_PORT": smtpd.port, + "SMTP_SSL": smtpd.config.use_ssl, + "SMTP_STARTTLS": smtpd.config.use_starttls, + "SMTP_USERNAME": smtpd.config.login_username, + "SMTP_PASSWORD": smtpd.config.login_password, + } + + +@pytest.fixture +def app(configuration): + app = create_app(configuration) with app.app_context(): Migrate(app, db, compare_type=True) db.create_all() @@ -61,31 +118,47 @@ def app(mocker): return app -@pytest.fixture() +@pytest.fixture def client_app(app): - return TestApp(app) + with app.test_request_context(): + yield TestApp(app) + +@pytest.fixture +def meeting(client_app, user): + from b3desk.models.meetings import Meeting -@pytest.fixture() -def meeting(app, user): - meeting = Meeting(user=user) + meeting = Meeting( + user=user, + name="meeting", + maxParticipants=99, + duration=999, + moderatorPW="moderator", + attendeePW="attendee", + ) meeting.save() yield meeting -@pytest.fixture() -def user(app): - user = User(email="alice@domain.tld", given_name="Alice", family_name="Cooper") +@pytest.fixture +def user(client_app, iam_user): + from b3desk.models.users import User + + user = User( + email=iam_user.emails[0], + given_name=iam_user.given_name, + family_name=iam_user.family_name, + ) user.save() yield user -@pytest.fixture() -def authenticated_user(client_app, user): +@pytest.fixture +def authenticated_user(client_app, user, iam_token, iam_server, iam_user): with client_app.session_transaction() as session: - session["access_token"] = "" + session["access_token"] = iam_token.access_token session["access_token_expires_at"] = "" session["current_provider"] = "default" session["id_token"] = "" @@ -100,10 +173,13 @@ def authenticated_user(client_app, user): } session["refresh_token"] = "" + iam_server.login(iam_user) + iam_server.consent(iam_user) + yield user -@pytest.fixture() +@pytest.fixture def authenticated_attendee(client_app, user, mocker): with client_app.session_transaction() as session: session["access_token"] = "" @@ -123,10 +199,81 @@ def authenticated_attendee(client_app, user, mocker): yield user -@pytest.fixture() +@pytest.fixture def bbb_response(mocker): - class Resp: + class Response: content = """SUCCESStrue""" status_code = 200 - mocker.patch("requests.get", return_value=Resp) + yield mocker.patch("requests.Session.send", return_value=Response) + + +@pytest.fixture(scope="session") +def webdav_server(tmp_path_factory): + root_path = Path(tmp_path_factory.mktemp("webdav")) + (root_path / "remote.php" / "dav" / "files" / "alice").mkdir( + parents=True, exist_ok=True + ) + provider = FilesystemProvider(root_path, readonly=False, fs_opts={}) + + config = { + "host": "localhost", + "port": portpicker.pick_unused_port(), + "provider_mapping": {"/": provider}, + "http_authenticator": {"domain_controller": None}, + "simple_dc": {"user_mapping": {"*": True}}, + "verbose": 4, + "logging": { + "enable": True, + "enable_loggers": [], + }, + } + app = WsgiDAVApp(config) + + server = wsgiref.simple_server.make_server("localhost", config["port"], app) + + server_thread = threading.Thread(target=server.serve_forever) + server_thread.start() + try: + yield app + finally: + server.shutdown() + server_thread.join() + + +class CloudTokenResponse: + def __init__(self, nc_locator): + self.data = { + "nctoken": str(uuid.uuid4()), + "nclocator": nc_locator, + "nclogin": "alice", + } + + def json(self): + return self.data + + +@pytest.fixture(autouse=True) +def nextcloud_credentials(mocker, webdav_server): + response = CloudTokenResponse( + nc_locator=f"http://{webdav_server.config['host']}:{webdav_server.config['port']}", + ).data + mocker.patch( + "b3desk.models.users.make_nextcloud_credentials_request", return_value=response + ) + return response + + +@pytest.fixture +def cloud_service_response(mocker, webdav_server, request): + scheme = "http://" + if "secure" in request.keywords: + scheme = "https://" + elif "no_scheme" in request.keywords: + scheme = "" + return CloudTokenResponse(nc_locator=f"{scheme}cloud-auth-serv.ice") + + +@pytest.fixture +def jpg_file_content(): + return b"\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xff\xdb\x00C\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc2\x00\x0b\x08\x00\x01\x00\x01\x01\x01\x11\x00\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x01\x00\x01?\x10" diff --git a/web/tests/meeting/test_end.py b/web/tests/meeting/test_end.py deleted file mode 100644 index 41e3c923..00000000 --- a/web/tests/meeting/test_end.py +++ /dev/null @@ -1,11 +0,0 @@ -def test_end_bbb_meeting(app, client_app, authenticated_user, meeting, mocker): - mocked_end = mocker.patch("flaskr.models.BBB.end") - - response = client_app.post( - "/meeting/end", - {"meeting_id": meeting.id}, - status=302, - ) - - assert mocked_end.called - assert "welcome" in response.location diff --git a/web/tests/meeting/test_join.py b/web/tests/meeting/test_join.py index bbb209f2..cce52efa 100644 --- a/web/tests/meeting/test_join.py +++ b/web/tests/meeting/test_join.py @@ -4,9 +4,11 @@ from flask import url_for +from b3desk.models.roles import Role -def test_signin_meeting(client_app, app, meeting, user, bbb_response): - meeting_hash = meeting.get_hash("attendee") + +def test_signin_meeting(client_app, meeting, user, bbb_response): + meeting_hash = meeting.get_hash(Role.attendee) url = f"/meeting/signin/{meeting.id}/creator/{meeting.user.id}/hash/{meeting_hash}" response = client_app.get( @@ -29,11 +31,9 @@ def test_attendee_link_moderator_promotion_for_meeting_owner_already_authenticat authenticated_user, bbb_response, ): - """ - If the meeting owner are authenticated, they must be automatically - promoted moderator in the meeting when clicking on an attendee link. - """ - meeting_hash = meeting.get_hash("attendee") + """If the meeting owner are authenticated, they must be automatically + promoted moderator in the meeting when clicking on an attendee link.""" + meeting_hash = meeting.get_hash(Role.attendee) url = f"/meeting/signin/{meeting.id}/creator/{meeting.user.id}/hash/{meeting_hash}" response = client_app.get( @@ -45,8 +45,8 @@ def test_attendee_link_moderator_promotion_for_meeting_owner_already_authenticat assert url_role == ["moderator"] -def test_signin_meeting_with_authenticated_attendee(client_app, app, meeting): - meeting_hash = meeting.get_hash("authenticated") +def test_signin_meeting_with_authenticated_attendee(client_app, meeting): + meeting_hash = meeting.get_hash(Role.authenticated) url = f"/meeting/signin/{meeting.id}/creator/{meeting.user.id}/hash/{meeting_hash}" response = client_app.get( @@ -56,14 +56,14 @@ def test_signin_meeting_with_authenticated_attendee(client_app, app, meeting): assert response.location == "/meeting/join/1/authenticated" -def test_auth_attendee_disabled(client_app, app, meeting): - """ - If attendee authentication service is temporarily disabled, we should skip - the attendee authentication step. +def test_auth_attendee_disabled(client_app, meeting): + """If attendee authentication service is temporarily disabled, we should + skip the attendee authentication step. + https://github.com/numerique-gouv/b3desk/issues/9 """ - app.config["OIDC_ATTENDEE_ENABLED"] = False - meeting_hash = meeting.get_hash("authenticated") + client_app.app.config["OIDC_ATTENDEE_ENABLED"] = False + meeting_hash = meeting.get_hash(Role.authenticated) url = f"/meeting/signin/{meeting.id}/creator/{meeting.user.id}/hash/{meeting_hash}" response = client_app.get( @@ -73,7 +73,7 @@ def test_auth_attendee_disabled(client_app, app, meeting): def test_join_meeting_as_authenticated_attendee( - client_app, app, meeting, authenticated_attendee + client_app, meeting, authenticated_attendee ): url = f"/meeting/join/{meeting.id}/authenticated" response = client_app.get(url, status=302) @@ -81,156 +81,153 @@ def test_join_meeting_as_authenticated_attendee( assert "/meeting/wait/1/creator/1/hash/" in response.location assert "Bob%20Dylan" in response.location + response = response.follow() + + assert response.form["fullname"].value == "Bob Dylan" + + +def test_fix_authenticated_attendee_name_case(client_app, meeting, user): + """The user names coming from the identity provider might be uppercase. In + such cases b3desk should correct the display. + + https://github.com/numerique-gouv/b3desk/issues/47 + """ + + user.given_name = "JOHN" + user.family_name = "LENNON" + user.email = "john@lennon.com" + with client_app.session_transaction() as session: + session["current_provider"] = "attendee" + session["last_authenticated"] = "true" + session["userinfo"] = { + "given_name": user.given_name, + "family_name": user.family_name, + "email": user.email, + } + + url = f"/meeting/join/{meeting.id}/authenticated" + response = client_app.get(url, status=302) + + assert "/meeting/wait/1/creator/1/hash/" in response.location + assert "John%20Lennon" in response.location + + response = response.follow() + + assert response.form["fullname"].value == "John Lennon" + def test_join_meeting_as_authenticated_attendee_with_fullname_suffix( - client_app, app, meeting, authenticated_attendee, bbb_response + client_app, meeting, authenticated_attendee, bbb_response ): - meeting_hash = meeting.get_hash("authenticated") - - response = client_app.post( - "/meeting/join", - { - "fullname": "Bob Dylan", - "meeting_fake_id": meeting.id, - "user_id": meeting.user.id, - "h": meeting_hash, - "fullname_suffix": "Service", - }, - status=302, - ) + response = client_app.get(f"/meeting/join/{meeting.id}/authenticated").follow() + response.form["fullname_suffix"] = "Service" + response = response.form.submit(status=302) assert ( - f"{app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName=Bob+Dylan+-+Service&" + f"{client_app.app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName=Bob+Dylan+-+Service&" in response.location ) assert "guest" not in response.location def test_join_meeting_as_authenticated_attendee_with_modified_fullname( - client_app, app, meeting, authenticated_attendee, bbb_response + client_app, meeting, authenticated_attendee, bbb_response ): - meeting_hash = meeting.get_hash("authenticated") - - response = client_app.post( - "/meeting/join", - { - "fullname": "toto", - "meeting_fake_id": meeting.id, - "user_id": meeting.user.id, - "h": meeting_hash, - "fullname_suffix": "", - }, - ) + response = client_app.get(f"/meeting/join/{meeting.id}/authenticated").follow() + response.form["fullname"] = "toto" + response = response.form.submit() assert ( - f"{app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName=Bob+Dylan&" + f"{client_app.app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName=Bob+Dylan&" in response.location ) assert "guest" not in response.location -def test_join_meeting(client_app, app, meeting, bbb_response): - meeting_hash = meeting.get_hash("attendee") - fullname = "Bob" - - response = client_app.post( - "/meeting/join", - { - "fullname": fullname, - "meeting_fake_id": meeting.id, - "user_id": meeting.user.id, - "h": meeting_hash, - }, - status=302, +def test_join_meeting(client_app, meeting, bbb_response): + meeting_hash = meeting.get_hash(Role.attendee) + response = client_app.get( + f"/meeting/signin/{meeting.id}/creator/{meeting.user.id}/hash/{meeting_hash}" ) + response.form["fullname"] = "Bob" + response = response.form.submit() assert ( - f"{app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName={fullname}" + f"{client_app.app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName=Bob" in response.location ) assert "guest" in response.location -def test_join_mail_meeting(client_app, app, meeting, bbb_response): +def test_join_mail_meeting(client_app, meeting, bbb_response): expiration = int(time.time()) + 1000 meeting_hash = meeting.get_mail_signin_hash(meeting.id, expiration) - fullname = "Bob" - - response = client_app.post( - "/meeting/joinmail", - { - "fullname": fullname, - "meeting_fake_id": meeting.id, - "user_id": meeting.user.id, - "h": meeting_hash, - "expiration": expiration, - }, - status=302, + response = client_app.get( + f"/meeting/signinmail/{meeting.id}/expiration/{expiration}/hash/{meeting_hash}" ) + response.form["fullname"] = "Bob" + response.form["user_id"] = meeting.user.id + response = response.form.submit() assert ( - f"{app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName={fullname}" + f"{client_app.app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName=Bob" in response.location ) -def test_join_meeting_as_role( - client_app, app, authenticated_user, meeting, bbb_response -): +def test_join_meeting_as_role(client_app, authenticated_user, meeting, bbb_response): fullname = "Alice+Cooper" - response = client_app.get(f"/meeting/join/{meeting.id}/attendee", status=302) + response = client_app.get(f"/meeting/join/{meeting.id}/invite", status=302) assert ( - f"{app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName={fullname}" + f"{client_app.app.config['BIGBLUEBUTTON_ENDPOINT']}/join?fullName={fullname}" in response.location ) def test_join_meeting_as_role__meeting_not_found( - client_app, app, authenticated_user, bbb_response + client_app, authenticated_user, bbb_response ): client_app.get("/meeting/join/321/attendee", status=404) def test_join_meeting_as_role__not_attendee_or_moderator( - client_app, app, authenticated_user, meeting, bbb_response + client_app, authenticated_user, meeting, bbb_response ): client_app.get(f"/meeting/join/{meeting.id}/journalist", status=404) -def test_waiting_meeting_with_a_fullname_containing_a_slash(client_app, app, meeting): +def test_waiting_meeting_with_a_fullname_containing_a_slash(client_app, meeting): fullname_suffix = "Service EN" meeting_fake_id = meeting.fake_id - h = meeting.get_hash("attendee") + h = meeting.get_hash(Role.attendee) fullname = "Alice/Cooper" - with app.test_request_context(): - waiting_meeting_url = url_for( - "routes.waiting_meeting", - meeting_fake_id=meeting_fake_id, - user_id=meeting.user.id, - h=h, - fullname=fullname, - fullname_suffix=fullname_suffix, - ) + waiting_meeting_url = url_for( + "join.waiting_meeting", + meeting_fake_id=meeting_fake_id, + creator=meeting.user, + h=h, + fullname=fullname, + fullname_suffix=fullname_suffix, + ) response = client_app.get(waiting_meeting_url, status=200) response.mustcontain(fullname) -def test_waiting_meeting_with_empty_fullname_suffix(client_app, app, meeting): +def test_waiting_meeting_with_empty_fullname_suffix(client_app, meeting): meeting_fake_id = meeting.fake_id - h = meeting.get_hash("attendee") + h = meeting.get_hash(Role.attendee) fullname = "Alice/Cooper" - with app.test_request_context(): - waiting_meeting_url = url_for( - "routes.waiting_meeting", - meeting_fake_id=meeting_fake_id, - user_id=meeting.user.id, - h=h, - fullname=fullname, - fullname_suffix="", - ) + waiting_meeting_url = url_for( + "join.waiting_meeting", + meeting_fake_id=meeting_fake_id, + creator=meeting.user, + h=h, + fullname=fullname, + fullname_suffix="", + ) client_app.get(waiting_meeting_url, status=200) diff --git a/web/tests/meeting/test_meeting.py b/web/tests/meeting/test_meeting.py index 4a947913..f588f343 100644 --- a/web/tests/meeting/test_meeting.py +++ b/web/tests/meeting/test_meeting.py @@ -1,24 +1,36 @@ +import datetime +import hashlib +import os from unittest import mock +from urllib.parse import parse_qs +from urllib.parse import urlparse import pytest -from flaskr.models import Meeting -from flaskr.models import MODERATOR_ONLY_MESSAGE_MAXLENGTH + +from b3desk.models import db +from b3desk.models.meetings import MODERATOR_ONLY_MESSAGE_MAXLENGTH +from b3desk.models.meetings import Meeting +from b3desk.models.meetings import MeetingFiles +from b3desk.models.roles import Role + + +@pytest.fixture() +def mock_meeting_is_running(mocker): + mocker.patch("b3desk.models.meetings.Meeting.is_running", return_value=True) @pytest.fixture() -def mocked_is_meeting_running(mocker): - mocker.patch("flaskr.models.Meeting.is_meeting_running", return_value=False) +def mock_meeting_is_not_running(mocker): + mocker.patch("b3desk.models.meetings.Meeting.is_running", return_value=False) -def test_show_meeting(client_app, app, authenticated_user, meeting, bbb_response): +def test_show_meeting(client_app, authenticated_user, meeting, bbb_response): response = client_app.get(f"/meeting/show/{meeting.id}", status=200) assert "meeting/show.html" in response.contexts -def test_show_meeting_recording( - client_app, app, authenticated_user, meeting, bbb_response -): +def test_show_meeting_recording(client_app, authenticated_user, meeting, bbb_response): response = client_app.get(f"/meeting/recordings/{meeting.id}", status=200) assert "meeting/recordings.html" in response.contexts @@ -30,54 +42,48 @@ def test_new_meeting(client_app, authenticated_user): assert response.template == "meeting/wizard.html" -def test_new_meeting_when_recording_not_configured(client_app, app, authenticated_user): - app.config["RECORDING"] = False +def test_new_meeting_when_recording_not_configured(client_app, authenticated_user): + client_app.app.config["RECORDING"] = False response = client_app.get("/meeting/new") response.mustcontain(no="Enregistrement") -def test_edit_meeting(client_app, app, authenticated_user, meeting, bbb_response): +def test_edit_meeting(client_app, authenticated_user, meeting, bbb_response): response = client_app.get(f"/meeting/edit/{meeting.id}", status=200) assert response.template == "meeting/wizard.html" -MEETING_DATA = { - "name": "Mon meeting de test", - "welcome": "Bienvenue dans mon meeting de test", - "maxParticipants": 5, - "duration": 60, - "guestPolicy": "on", - "webcamsOnlyForModerator": "on", - "muteOnStart": "on", - "lockSettingsDisableCam": "on", - "lockSettingsDisableMic": "on", - "lockSettingsDisablePrivateChat": "on", - "lockSettingsDisablePublicChat": "on", - "lockSettingsDisableNote": "on", - "moderatorOnlyMessage": "Bienvenue aux modérateurs", - "logoutUrl": "https://log.out", - "moderatorPW": "Motdepasse1", - "attendeePW": "Motdepasse2", - "autoStartRecording": "on", - "allowStartStopRecording": "on", -} - - -def test_save_new_meeting( - app, client_app, authenticated_user, mocked_is_meeting_running -): - response = client_app.post( - "/meeting/save", - MEETING_DATA, - status=302, - ) - - assert "welcome" in response.location - - meeting = Meeting.query.get(1) +def test_save_new_meeting(client_app, authenticated_user, mock_meeting_is_not_running): + res = client_app.get("/meeting/new") + res.form["name"] = "Mon meeting de test" + res.form["welcome"] = "Bienvenue dans mon meeting de test" + res.form["maxParticipants"] = 5 + res.form["duration"] = 60 + res.form["guestPolicy"] = "on" + res.form["webcamsOnlyForModerator"] = "on" + res.form["muteOnStart"] = "on" + res.form["lockSettingsDisableCam"] = "on" + res.form["lockSettingsDisableMic"] = "on" + res.form["lockSettingsDisablePrivateChat"] = "on" + res.form["lockSettingsDisablePublicChat"] = "on" + res.form["lockSettingsDisableNote"] = "on" + res.form["moderatorOnlyMessage"] = "Bienvenue aux modérateurs" + res.form["logoutUrl"] = "https://log.out" + res.form["moderatorPW"] = "Motdepasse1" + res.form["attendeePW"] = "Motdepasse2" + res.form["autoStartRecording"] = "on" + res.form["allowStartStopRecording"] = "on" + + res = res.form.submit() + assert ( + "success", + "Mon meeting de test modifications prises en compte", + ) in res.flashes + + meeting = db.session.get(Meeting, 1) assert meeting.user_id == 1 assert meeting.name == "Mon meeting de test" @@ -101,28 +107,39 @@ def test_save_new_meeting( assert meeting.allowStartStopRecording is True -def test_save_existing_meeting( - app, client_app, authenticated_user, meeting, mocked_is_meeting_running +def test_save_existing_meeting_not_running( + client_app, authenticated_user, meeting, mock_meeting_is_not_running ): assert len(Meeting.query.all()) == 1 - data = MEETING_DATA.copy() - data["id"] = meeting.id - - response = client_app.post( - "/meeting/save", - data, - status=302, - ) - - assert "welcome" in response.location + res = client_app.get("/meeting/edit/1") + res.form["name"] = "Mon meeting de test" + res.form["welcome"] = "Bienvenue dans mon meeting de test" + res.form["maxParticipants"] = 5 + res.form["duration"] = 60 + res.form["guestPolicy"] = "on" + res.form["webcamsOnlyForModerator"] = "on" + res.form["muteOnStart"] = "on" + res.form["lockSettingsDisableCam"] = "on" + res.form["lockSettingsDisableMic"] = "on" + res.form["lockSettingsDisablePrivateChat"] = "on" + res.form["lockSettingsDisablePublicChat"] = "on" + res.form["lockSettingsDisableNote"] = "on" + res.form["moderatorOnlyMessage"] = "Bienvenue aux modérateurs" + res.form["logoutUrl"] = "https://log.out" + res.form["moderatorPW"] = "Motdepasse1" + res.form["attendeePW"] = "Motdepasse2" + res.form["autoStartRecording"] = "on" + res.form["allowStartStopRecording"] = "on" + + res = res.form.submit() + assert ("success", "meeting modifications prises en compte") in res.flashes assert len(Meeting.query.all()) == 1 - - meeting = Meeting.query.get(1) + meeting = db.session.get(Meeting, 1) assert meeting.user_id == 1 - assert not meeting.name # Name can not be edited + assert meeting.name == "meeting" # Name can not be edited assert meeting.welcome == "Bienvenue dans mon meeting de test" assert meeting.maxParticipants == 5 assert meeting.duration == 60 @@ -143,103 +160,138 @@ def test_save_existing_meeting( assert meeting.allowStartStopRecording is True +def test_save_existing_meeting_running( + mocker, client_app, authenticated_user, meeting, mock_meeting_is_running +): + mocker.patch("b3desk.models.meetings.Meeting.end_bbb", return_value=True) + assert len(Meeting.query.all()) == 1 + + res = client_app.get("/meeting/edit/1") + res.form["welcome"] = "Bienvenue dans mon meeting de test" + + res = res.form.submit() + assert res.template == "meeting/end.html" + assert ("success", "meeting modifications prises en compte") in res.flashes + + assert len(Meeting.query.all()) == 1 + meeting = db.session.get(Meeting, 1) + assert meeting.welcome == "Bienvenue dans mon meeting de test" + + res = res.form.submit() + assert ("success", "Séminaire « meeting » terminé(e)") in res.flashes + + def test_save_moderatorOnlyMessage_too_long( - app, client_app, authenticated_user, mocked_is_meeting_running + client_app, authenticated_user, mock_meeting_is_not_running ): - data = MEETING_DATA.copy() + res = client_app.get("/meeting/new") moderator_only_message = "a" * (MODERATOR_ONLY_MESSAGE_MAXLENGTH + 1) - data["moderatorOnlyMessage"] = moderator_only_message - - response = client_app.post( - "/meeting/save", - data, - status=200, - ) - assert response.template == "meeting/wizard.html" + res.form["moderatorOnlyMessage"] = moderator_only_message + res = res.form.submit() - response.mustcontain("Le formulaire contient des erreurs") - response.mustcontain(moderator_only_message) - response.mustcontain("Le message est trop long") + res.mustcontain("Le formulaire contient des erreurs") + res.mustcontain(moderator_only_message) + res.mustcontain("Le message est trop long") assert not Meeting.query.all() def test_save_no_recording_by_default( - app, client_app, authenticated_user, mocked_is_meeting_running + client_app, authenticated_user, mock_meeting_is_not_running ): - data = MEETING_DATA.copy() - del data["autoStartRecording"] - del data["allowStartStopRecording"] - - client_app.post("/meeting/save", data, status=302) - - meeting = Meeting.query.get(1) + res = client_app.get("/meeting/new") + res.form["name"] = "Mon meeting de test" + res.form["maxParticipants"] = 5 + res.form["duration"] = 60 + res.form["moderatorPW"] = "Motdepasse1" + res.form["attendeePW"] = "Motdepasse2" + + res = res.form.submit() + assert ( + "success", + "Mon meeting de test modifications prises en compte", + ) in res.flashes + + meeting = db.session.get(Meeting, 1) assert meeting.record is False assert meeting.autoStartRecording is False assert meeting.allowStartStopRecording is False def test_save_meeting_in_no_recording_environment( - app, client_app, authenticated_user, mocked_is_meeting_running + client_app, authenticated_user, mock_meeting_is_not_running ): - app.config["RECORDING"] = False + assert len(Meeting.query.all()) == 0 + client_app.app.config["RECORDING"] = False - response = client_app.post( - "/meeting/save", - MEETING_DATA, - status=302, - ) + res = client_app.get("/meeting/new") + res.form["name"] = "Mon meeting de test" + res.form["maxParticipants"] = 5 + res.form["duration"] = 60 + res.form["moderatorPW"] = "Motdepasse1" + res.form["attendeePW"] = "Motdepasse2" - assert "welcome" in response.location + assert "allowStartStopRecording" not in res.form.fields + assert "autoStartRecording" not in res.form.fields + + res = res.form.submit() + assert ( + "success", + "Mon meeting de test modifications prises en compte", + ) in res.flashes assert len(Meeting.query.all()) == 1 - meeting = Meeting.query.get(1) + meeting = db.session.get(Meeting, 1) assert meeting.record is False -def test_create(app, meeting, mocker): - app.config["FILE_SHARING"] = True +def test_create_no_file(client_app, meeting, mocker, bbb_response): + """Tests the BBB meeting creation request. - class Resp: - content = """SUCCESS""" + As there is no file attached to the meeting, no background upload + task should be called. + """ + client_app.app.config["FILE_SHARING"] = True - mocked_bbb_create_request = mocker.patch("requests.post", return_value=Resp) mocked_background_upload = mocker.patch( - "flaskr.tasks.background_upload.delay", return_value=True + "b3desk.tasks.background_upload.delay", return_value=True ) - with app.test_request_context(): - meeting.name = "My Meeting" - meeting.attendeePW = "Password1" - meeting.moderatorPW = "Password2" - meeting.welcome = "Welcome!" - meeting.maxParticipants = 25 - meeting.logoutUrl = "https://log.out" - meeting.record = True - meeting.duration = 60 - meeting.moderatorOnlyMessage = "Welcome moderators!" - meeting.autoStartRecording = False - meeting.allowStartStopRecording = True - meeting.webcamsOnlyForModerator = False - meeting.muteOnStart = True - meeting.lockSettingsDisableCam = False - meeting.lockSettingsDisableMic = False - meeting.allowModsToUnmuteUsers = False - meeting.lockSettingsDisablePrivateChat = False - meeting.lockSettingsDisablePublicChat = False - meeting.lockSettingsDisableNote = False - meeting.guestPolicy = True - - meeting.bbb.create() - - assert mocked_bbb_create_request.called - bbb_url = mocked_bbb_create_request.call_args.args[0] - assert bbb_url == f'{app.config["BIGBLUEBUTTON_ENDPOINT"]}/create' - bbb_params = mocked_bbb_create_request.call_args.kwargs["params"] + meeting.name = "My Meeting" + meeting.attendeePW = "Password1" + meeting.moderatorPW = "Password2" + meeting.welcome = "Welcome!" + meeting.maxParticipants = 25 + meeting.logoutUrl = "https://log.out" + meeting.record = True + meeting.duration = 60 + meeting.moderatorOnlyMessage = "Welcome moderators!" + meeting.autoStartRecording = False + meeting.allowStartStopRecording = True + meeting.webcamsOnlyForModerator = False + meeting.muteOnStart = True + meeting.lockSettingsDisableCam = False + meeting.lockSettingsDisableMic = False + meeting.allowModsToUnmuteUsers = False + meeting.lockSettingsDisablePrivateChat = False + meeting.lockSettingsDisablePublicChat = False + meeting.lockSettingsDisableNote = False + meeting.guestPolicy = True + meeting.bbb.create() + + assert bbb_response.called + bbb_url = bbb_response.call_args.args[0].url + assert bbb_url.startswith( + f'{client_app.app.config["BIGBLUEBUTTON_ENDPOINT"]}/create' + ) + bbb_params = { + key: value[0] for key, value in parse_qs(urlparse(bbb_url).query).items() + } assert bbb_params == { "meetingID": meeting.meetingID, "name": "My Meeting", "meetingKeepEvents": "true", "meta_analytics-callback-url": "https://bbb-analytics-staging.osc-fr1.scalingo.io/v1/post_events", + "meta_academy": "domain.tld", "attendeePW": "Password1", "moderatorPW": "Password2", "welcome": "Welcome!", @@ -247,7 +299,7 @@ class Resp: "logoutURL": "https://log.out", "record": "true", "duration": "60", - "moderatorOnlyMessage": "Welcome moderators!\n\n Lien Modérateur :\n\nhttp://localhost:5000/meeting/signin/1/creator/1/hash/74416cd20fdc0ce5f59ff198915c82515e1e375f\n\n Lien Participant :\n\nhttp://localhost:5000/meeting/signin/1/creator/1/hash/b3f8a558fb7cfc889405fd1b8c1c8d933db00334", + "moderatorOnlyMessage": f"Welcome moderators!\n\n Lien Modérateur :\n\nhttp://localhost:5000/meeting/signin/moderateur/1/creator/1/hash/{meeting.get_hash(Role.moderator)}\n\n Lien Participant :\n\nhttp://localhost:5000/meeting/signin/invite/1/creator/1/hash/{meeting.get_hash(Role.attendee)}", "autoStartRecording": "false", "allowStartStopRecording": "true", "webcamsOnlyForModerator": "false", @@ -260,48 +312,248 @@ class Resp: "lockSettingsDisableNote": "false", "guestPolicy": "ASK_MODERATOR", "checksum": mock.ANY, - "uploadExternalDescription": app.config["EXTERNAL_UPLOAD_DESCRIPTION"], - "uploadExternalUrl": f"{app.config['SERVER_FQDN']}/meeting/{str(meeting.id)}/externalUpload", + "uploadExternalDescription": client_app.app.config[ + "EXTERNAL_UPLOAD_DESCRIPTION" + ], + "uploadExternalUrl": f"http://localhost:5000/meeting/{str(meeting.id)}/externalUpload", } assert not mocked_background_upload.called -def test_create_without_logout_url_gets_default( - app, client_app, authenticated_user, mocked_is_meeting_running +def test_create_with_only_a_default_file( + client_app, meeting, mocker, bbb_response, jpg_file_content, tmp_path +): + """Tests the BBB meeting creation request. + + As there is a default file attached to the meeting, it should be + sent right away, and no background upload task should be called. + """ + client_app.app.config["FILE_SHARING"] = True + + file_path = os.path.join(tmp_path, "foobar.jpg") + with open(file_path, "wb") as fd: + fd.write(jpg_file_content) + + mocked_background_upload = mocker.patch( + "b3desk.tasks.background_upload.delay", return_value=True + ) + + meeting.name = "My Meeting" + meeting.attendeePW = "Password1" + meeting.moderatorPW = "Password2" + meeting.welcome = "Welcome!" + meeting.maxParticipants = 25 + meeting.logoutUrl = "https://log.out" + meeting.record = True + meeting.duration = 60 + meeting.moderatorOnlyMessage = "Welcome moderators!" + meeting.autoStartRecording = False + meeting.allowStartStopRecording = True + meeting.webcamsOnlyForModerator = False + meeting.muteOnStart = True + meeting.lockSettingsDisableCam = False + meeting.lockSettingsDisableMic = False + meeting.allowModsToUnmuteUsers = False + meeting.lockSettingsDisablePrivateChat = False + meeting.lockSettingsDisablePublicChat = False + meeting.lockSettingsDisableNote = False + meeting.guestPolicy = True + + meeting_file = MeetingFiles( + nc_path=file_path, + title="file_title", + created_at=datetime.date(2024, 3, 19), + meeting_id=meeting.id, + is_default=True, + ) + meeting.files = [meeting_file] + + meeting.bbb.create() + + assert bbb_response.called + bbb_url = bbb_response.call_args.args[0].url + assert bbb_url.startswith( + f'{client_app.app.config["BIGBLUEBUTTON_ENDPOINT"]}/create' + ) + bbb_params = { + key: value[0] for key, value in parse_qs(urlparse(bbb_url).query).items() + } + assert bbb_params == { + "meetingID": meeting.meetingID, + "name": "My Meeting", + "meetingKeepEvents": "true", + "meta_analytics-callback-url": "https://bbb-analytics-staging.osc-fr1.scalingo.io/v1/post_events", + "meta_academy": "domain.tld", + "attendeePW": "Password1", + "moderatorPW": "Password2", + "welcome": "Welcome!", + "maxParticipants": "25", + "logoutURL": "https://log.out", + "record": "true", + "duration": "60", + "moderatorOnlyMessage": f"Welcome moderators!\n\n Lien Modérateur :\n\nhttp://localhost:5000/meeting/signin/moderateur/1/creator/1/hash/{meeting.get_hash(Role.moderator)}\n\n Lien Participant :\n\nhttp://localhost:5000/meeting/signin/invite/1/creator/1/hash/{meeting.get_hash(Role.attendee)}", + "autoStartRecording": "false", + "allowStartStopRecording": "true", + "webcamsOnlyForModerator": "false", + "muteOnStart": "true", + "lockSettingsDisableCam": "false", + "lockSettingsDisableMic": "false", + "allowModsToUnmuteUsers": "false", + "lockSettingsDisablePrivateChat": "false", + "lockSettingsDisablePublicChat": "false", + "lockSettingsDisableNote": "false", + "guestPolicy": "ASK_MODERATOR", + "checksum": mock.ANY, + "uploadExternalDescription": client_app.app.config[ + "EXTERNAL_UPLOAD_DESCRIPTION" + ], + "uploadExternalUrl": f"http://localhost:5000/meeting/{str(meeting.id)}/externalUpload", + } + + assert not mocked_background_upload.called + + +def test_create_with_files( + client_app, meeting, mocker, bbb_response, jpg_file_content, tmp_path ): - data = MEETING_DATA.copy() - del data["logoutUrl"] + """Tests the BBB meeting creation request. + + As there is a non default file attached to the meeting, the + background upload task should be called. + """ + client_app.app.config["FILE_SHARING"] = True + + file_path = os.path.join(tmp_path, "foobar.jpg") + with open(file_path, "wb") as fd: + fd.write(jpg_file_content) + + mocked_background_upload = mocker.patch( + "b3desk.tasks.background_upload.delay", return_value=True + ) + + meeting.name = "My Meeting" + meeting.attendeePW = "Password1" + meeting.moderatorPW = "Password2" + meeting.welcome = "Welcome!" + meeting.maxParticipants = 25 + meeting.logoutUrl = "https://log.out" + meeting.record = True + meeting.duration = 60 + meeting.moderatorOnlyMessage = "Welcome moderators!" + meeting.autoStartRecording = False + meeting.allowStartStopRecording = True + meeting.webcamsOnlyForModerator = False + meeting.muteOnStart = True + meeting.lockSettingsDisableCam = False + meeting.lockSettingsDisableMic = False + meeting.allowModsToUnmuteUsers = False + meeting.lockSettingsDisablePrivateChat = False + meeting.lockSettingsDisablePublicChat = False + meeting.lockSettingsDisableNote = False + meeting.guestPolicy = True + + meeting_file = MeetingFiles( + nc_path=file_path, + title="file_title", + created_at=datetime.date(2024, 3, 19), + meeting_id=meeting.id, + is_default=False, + ) + meeting.files = [meeting_file] + + meeting.bbb.create() + + assert bbb_response.called + bbb_url = bbb_response.call_args.args[0].url + assert bbb_url.startswith( + f'{client_app.app.config["BIGBLUEBUTTON_ENDPOINT"]}/create' + ) + bbb_params = { + key: value[0] for key, value in parse_qs(urlparse(bbb_url).query).items() + } + assert bbb_params == { + "meetingID": meeting.meetingID, + "name": "My Meeting", + "meetingKeepEvents": "true", + "meta_analytics-callback-url": "https://bbb-analytics-staging.osc-fr1.scalingo.io/v1/post_events", + "meta_academy": "domain.tld", + "attendeePW": "Password1", + "moderatorPW": "Password2", + "welcome": "Welcome!", + "maxParticipants": "25", + "logoutURL": "https://log.out", + "record": "true", + "duration": "60", + "moderatorOnlyMessage": f"Welcome moderators!\n\n Lien Modérateur :\n\nhttp://localhost:5000/meeting/signin/moderateur/1/creator/1/hash/{meeting.get_hash(Role.moderator)}\n\n Lien Participant :\n\nhttp://localhost:5000/meeting/signin/invite/1/creator/1/hash/{meeting.get_hash(Role.attendee)}", + "autoStartRecording": "false", + "allowStartStopRecording": "true", + "webcamsOnlyForModerator": "false", + "muteOnStart": "true", + "lockSettingsDisableCam": "false", + "lockSettingsDisableMic": "false", + "allowModsToUnmuteUsers": "false", + "lockSettingsDisablePrivateChat": "false", + "lockSettingsDisablePublicChat": "false", + "lockSettingsDisableNote": "false", + "guestPolicy": "ASK_MODERATOR", + "checksum": mock.ANY, + "uploadExternalDescription": client_app.app.config[ + "EXTERNAL_UPLOAD_DESCRIPTION" + ], + "uploadExternalUrl": f"http://localhost:5000/meeting/{str(meeting.id)}/externalUpload", + } - client_app.post( - "/meeting/save", - data, - status=302, + assert mocked_background_upload.called + assert mocked_background_upload.call_args.args[0].startswith( + f'{client_app.app.config["BIGBLUEBUTTON_ENDPOINT"]}/insertDocument' ) - meeting = Meeting.query.get(1) + secret_key = client_app.app.config["SECRET_KEY"] + filehash = hashlib.sha1( + f"{secret_key}-0-{meeting_file.id}-{secret_key}".encode() + ).hexdigest() + + assert ( + mocked_background_upload.call_args.args[1] + == " " + + " " + + " " + + f" " + + "" + + "" + ) + + +def test_create_without_logout_url_gets_default( + app, client_app, authenticated_user, mock_meeting_is_not_running +): + res = client_app.get("/meeting/new") + res = res.form.submit() + assert ("success", "Mon Séminaire modifications prises en compte") in res.flashes + + meeting = db.session.get(Meeting, 1) assert meeting assert meeting.logoutUrl == app.config["MEETING_LOGOUT_URL"] -def test_create_quick_meeting(app, monkeypatch, user, mocker): - from flaskr.routes import get_quick_meeting_from_user_and_random_string +def test_create_quick_meeting(client_app, monkeypatch, user, mocker, bbb_response): + from b3desk.endpoints.meetings import get_quick_meeting_from_user_and_random_string - class Resp: - content = """SUCCESS""" + mocker.patch("b3desk.tasks.background_upload.delay", return_value=True) + monkeypatch.setattr("b3desk.models.users.User.id", 1) + monkeypatch.setattr("b3desk.models.users.User.hash", "hash") + meeting = get_quick_meeting_from_user_and_random_string(user) + meeting.bbb.create() - mocked_bbb_create_request = mocker.patch("requests.post", return_value=Resp) - mocker.patch("flaskr.tasks.background_upload.delay", return_value=True) - with app.test_request_context(): - monkeypatch.setattr("flaskr.models.User.id", 1) - monkeypatch.setattr("flaskr.models.User.hash", "hash") - meeting = get_quick_meeting_from_user_and_random_string(user) - meeting.bbb.create() - - assert mocked_bbb_create_request.called - bbb_url = mocked_bbb_create_request.call_args.args[0] - assert bbb_url == f'{app.config["BIGBLUEBUTTON_ENDPOINT"]}/create' - bbb_params = mocked_bbb_create_request.call_args.kwargs["params"] + assert bbb_response.called + bbb_url = bbb_response.call_args.args[0].url + assert bbb_url.startswith( + f'{client_app.app.config["BIGBLUEBUTTON_ENDPOINT"]}/create' + ) + bbb_params = { + key: value[0] for key, value in parse_qs(urlparse(bbb_url).query).items() + } assert bbb_params == { "meetingID": meeting.meetingID, "name": "Séminaire improvisé", @@ -309,18 +561,19 @@ class Resp: "uploadExternalDescription": "Fichiers depuis votre Nextcloud", "attendeePW": meeting.attendeePW, "moderatorPW": meeting.moderatorPW, - "logoutURL": "http://education.gouv.fr", + "logoutURL": "http://education.gouv.fr/", "duration": "280", "meetingKeepEvents": "true", "meta_analytics-callback-url": "https://bbb-analytics-staging.osc-fr1.scalingo.io/v1/post_events", - "moderatorOnlyMessage": f"Bienvenue aux modérateurs. Pour inviter quelqu'un à ce séminaire, envoyez-lui l'un de ces liens :\n\n Lien Modérateur :\n\nhttp://localhost:5000/meeting/signin/{meeting.fake_id}/creator/1/hash/{meeting.get_hash('moderator')}\n\n Lien Participant :\n\nhttp://localhost:5000/meeting/signin/{meeting.fake_id}/creator/1/hash/{meeting.get_hash('attendee')}", + "meta_academy": "domain.tld", + "moderatorOnlyMessage": f"Bienvenue aux modérateurs. Pour inviter quelqu'un à ce séminaire, envoyez-lui l'un de ces liens :\n\n Lien Modérateur :\n\nhttp://localhost:5000/meeting/signin/moderateur/{meeting.fake_id}/creator/1/hash/{meeting.get_hash(Role.moderator)}\n\n Lien Participant :\n\nhttp://localhost:5000/meeting/signin/invite/{meeting.fake_id}/creator/1/hash/{meeting.get_hash(Role.attendee)}", "guestPolicy": "ALWAYS_ACCEPT", "checksum": mock.ANY, } -def test_edit_files_meeting(client_app, app, authenticated_user, meeting, bbb_response): - app.config["FILE_SHARING"] = True +def test_edit_files_meeting(client_app, authenticated_user, meeting, bbb_response): + client_app.app.config["FILE_SHARING"] = True response = client_app.get(f"/meeting/files/{meeting.id}", status=200) @@ -328,9 +581,9 @@ def test_edit_files_meeting(client_app, app, authenticated_user, meeting, bbb_re def test_deactivated_meeting_files_cannot_access_files( - client_app, app, authenticated_user, meeting, bbb_response + client_app, authenticated_user, meeting, bbb_response ): - app.config["FILE_SHARING"] = False + client_app.app.config["FILE_SHARING"] = False response = client_app.get("/welcome", status=200) @@ -338,10 +591,16 @@ def test_deactivated_meeting_files_cannot_access_files( def test_deactivated_meeting_files_cannot_edit( - client_app, app, authenticated_user, meeting, bbb_response + client_app, authenticated_user, meeting, bbb_response ): - app.config["FILE_SHARING"] = False + client_app.app.config["FILE_SHARING"] = False response = client_app.get(f"/meeting/files/{meeting.id}", status=302) assert "welcome" in response.location + + +def test_delete_meeting(client_app, authenticated_user, meeting, bbb_response): + res = client_app.post("/meeting/delete", {"id": meeting.id}) + assert ("success", "Élément supprimé") in res.flashes + assert len(Meeting.query.all()) == 0 diff --git a/web/tests/meeting/test_meeting_files.py b/web/tests/meeting/test_meeting_files.py new file mode 100644 index 00000000..06eeb662 --- /dev/null +++ b/web/tests/meeting/test_meeting_files.py @@ -0,0 +1,66 @@ +import os + +from flask import url_for +from webdav3.exceptions import WebDavException + + +def test_nextcloud_enabled(client_app, authenticated_user, meeting): + res = client_app.get( + url_for("meeting_files.edit_meeting_files", meeting=meeting), status=200 + ) + res.mustcontain("depuis le Nuage") + + +def test_nextcloud_authentication_issue( + client_app, authenticated_user, meeting, mocker +): + response = { + "nctoken": None, + "nclocator": None, + "nclogin": None, + } + mocker.patch( + "b3desk.models.users.make_nextcloud_credentials_request", return_value=response + ) + res = client_app.get( + url_for("meeting_files.edit_meeting_files", meeting=meeting), status=200 + ) + res.mustcontain(no="depuis le Nuage") + + +def test_nextcloud_webdav_issue(client_app, authenticated_user, meeting, mocker): + mocker.patch("webdav3.client.Client.list", side_effect=WebDavException) + res = client_app.get( + url_for("meeting_files.edit_meeting_files", meeting=meeting), + status=200, + expect_errors=True, + ) + res.mustcontain(no="depuis le Nuage") + + +def test_file_sharing_disabled(client_app, authenticated_user, meeting): + client_app.app.config["FILE_SHARING"] = False + res = client_app.get( + url_for("meeting_files.edit_meeting_files", meeting=meeting), status=302 + ) + assert ("warning", "Vous ne pouvez pas modifier cet élément") in res.flashes + + +def test_add_dropzone_file( + client_app, authenticated_user, meeting, jpg_file_content, tmp_path +): + res = client_app.post( + "/meeting/files/1/dropzone", + { + "dzchunkindex": 0, + "dzchunkbyteoffset": 0, + "dztotalchunkcount": 1, + "dztotalfilesize": 134, + }, + upload_files=[("dropzoneFiles", "file.jpg", jpg_file_content)], + ) + + assert res.text == "Chunk upload successful" + + with open(os.path.join(tmp_path, "dropzone", "1-1-file.jpg"), "rb") as fd: + assert jpg_file_content == fd.read() diff --git a/web/tests/meeting/test_quick_meeting.py b/web/tests/meeting/test_quick_meeting.py new file mode 100644 index 00000000..66ab23ff --- /dev/null +++ b/web/tests/meeting/test_quick_meeting.py @@ -0,0 +1,45 @@ +import pyquery + + +def test_no_unauthenticated_quick_meeting(client_app, bbb_response): + """No anonymous quick mail form should be displayed on the home page if it + is not allowed by the configuration.""" + client_app.app.config["MAIL_MEETING"] = False + res = client_app.get("/home") + assert not res.forms + + +def test_unauthenticated_quick_meeting_unauthorized_email(client_app, bbb_response): + """Only allowed email domains should be able to launch an anonymous quick + mail meeting.""" + client_app.app.config["MAIL_MEETING"] = True + res = client_app.get("/home") + res.form["mail"] = "email@example.org" + res = res.form.submit() + assert ( + "error_login", + "Ce courriel ne correspond pas à un service de l'État. Si vous appartenez à un service de l'État mais votre courriel n'est pas reconnu par Webinaire, contactez-nous pour que nous le rajoutions !", + ) in res.flashes + + +def test_unauthenticated_quick_meeting_authorized_email( + client_app, bbb_response, smtpd +): + assert len(smtpd.messages) == 0 + client_app.app.config["MAIL_MEETING"] = True + res = client_app.get("/home") + res.form["mail"] = "example@gouv.fr" + res = res.form.submit() + assert ( + "success_login", + "Vous avez reçu un courriel pour vous connecter", + ) in res.flashes + assert len(smtpd.messages) == 1 + + message = smtpd.messages[0].get_payload()[0].get_payload(decode=True).decode() + pq = pyquery.PyQuery(message) + link = pq("a")[0].attrib["href"] + assert "/meeting/signinmail/" in link + + res = client_app.get(link) + assert res.template == "meeting/joinmail.html" diff --git a/web/tests/meeting/test_recordings.py b/web/tests/meeting/test_recordings.py index 2392e243..9e5c60b8 100644 --- a/web/tests/meeting/test_recordings.py +++ b/web/tests/meeting/test_recordings.py @@ -1,13 +1,15 @@ from datetime import datetime from datetime import timezone +from urllib.parse import parse_qs +from urllib.parse import urlparse import pytest -@pytest.fixture() +@pytest.fixture def bbb_getRecordings_response(mocker): - class Resp: - """Example response inspired from https://docs.bigbluebutton.org/dev/api.html#getrecordings""" + class Response: + """https://docs.bigbluebutton.org/dev/api.html#getrecordings""" content = """ @@ -111,10 +113,10 @@ class Resp: """ - mocker.patch("requests.get", return_value=Resp) + yield mocker.patch("requests.Session.send", return_value=Response) -def test_get_recordings(app, meeting, bbb_getRecordings_response): +def test_get_recordings(meeting, bbb_getRecordings_response): recordings = meeting.bbb.get_recordings() assert len(recordings) == 2 @@ -149,22 +151,21 @@ def test_get_recordings(app, meeting, bbb_getRecordings_response): ) -def test_update_recording_name(client_app, app, authenticated_user, meeting, mocker): - class Resp: - content = """SUCCESStrue""" - - mocked_bbb_request = mocker.patch("requests.get", return_value=Resp) - +def test_update_recording_name(client_app, authenticated_user, meeting, bbb_response): response = client_app.post( f"/meeting/{meeting.id}/recordings/recording_id", {"name": "First recording"}, status=302, ) - bbb_url = mocked_bbb_request.call_args.args - assert f"{app.config['BIGBLUEBUTTON_ENDPOINT']}/updateRecordings" in bbb_url - bbb_params = mocked_bbb_request.call_args.kwargs["params"].items() - assert ("meta_name", "First recording") in bbb_params - assert ("recordID", "recording_id") in bbb_params + bbb_url = bbb_response.call_args.args[0].url + assert bbb_url.startswith( + f"{client_app.app.config['BIGBLUEBUTTON_ENDPOINT']}/updateRecordings" + ) + bbb_params = { + key: value[0] for key, value in parse_qs(urlparse(bbb_url).query).items() + } + assert bbb_params["meta_name"] == "First recording" + assert bbb_params["recordID"] == "recording_id" assert f"meeting/recordings/{meeting.id}" in response.location diff --git a/web/tests/test_api.py b/web/tests/test_api.py new file mode 100644 index 00000000..f9a898d9 --- /dev/null +++ b/web/tests/test_api.py @@ -0,0 +1,79 @@ +import datetime + + +def test_api_meetings_nominal(client_app, user, meeting, iam_token): + res = client_app.get( + "/api/meetings", headers={"Authorization": f"Bearer {iam_token.access_token}"} + ) + assert res.json["meetings"] + assert res.json["meetings"][0]["name"] == "meeting" + assert ( + f"/meeting/signin/moderateur/{meeting.id}/creator/{user.id}/hash/" + in res.json["meetings"][0]["moderator_url"] + ) + assert ( + f"/meeting/signin/invite/{meeting.id}/creator/{user.id}/hash/" + in res.json["meetings"][0]["attendee_url"] + ) + + +def test_api_meetings_no_token(client_app): + client_app.get("/api/meetings", status=401) + + +def test_api_meetings_invalid_token(client_app): + client_app.get( + "/api/meetings", headers={"Authorization": "Bearer invalid-token"}, status=403 + ) + + +def test_api_meetings_token_expired(client_app, iam_server, iam_client, iam_user, user): + iam_token = iam_server.random_token( + client=iam_client, + subject=iam_user, + issue_date=datetime.datetime(2000, 1, 1, tzinfo=datetime.timezone.utc), + ) + + client_app.get( + "/api/meetings", + headers={"Authorization": f"Bearer {iam_token.access_token}"}, + status=403, + ) + + iam_token.delete() + + +def test_api_meetings_client_id_missing_in_token_audience( + client_app, iam_server, iam_client, iam_user, user +): + iam_token = iam_server.models.Token( + client=iam_client, + subject=iam_user, + audience="some-other-audience", + ) + + client_app.get( + "/api/meetings", + headers={"Authorization": f"Bearer {iam_token.access_token}"}, + status=403, + ) + + iam_token.delete() + + +def test_api_meetings_missing_scope_in_token( + client_app, iam_server, iam_client, iam_user, user +): + iam_token = iam_server.models.Token( + client=iam_client, + subject=iam_user, + scope=["openid"], + ) + + client_app.get( + "/api/meetings", + headers={"Authorization": f"Bearer {iam_token.access_token}"}, + status=403, + ) + + iam_token.delete() diff --git a/web/tests/test_authentication.py b/web/tests/test_authentication.py new file mode 100644 index 00000000..0d03eecc --- /dev/null +++ b/web/tests/test_authentication.py @@ -0,0 +1,38 @@ +import requests + +from b3desk.models import db +from b3desk.models.users import User + + +def test_user_authentication(client_app, configuration, iam_server, iam_client): + iam_user = iam_server.random_user() + iam_server.login(iam_user) + iam_server.consent(iam_user) + + assert not User.query.all() + + res = client_app.get("/home") + res.mustcontain("S’identifier") + res.mustcontain(no="se déconnecter") + + # 1. attempt to access a protected page + res1 = client_app.get("/welcome", status=302) + + # 2. authorization code request + res2 = requests.get(res1.location, allow_redirects=False) + assert res2.status_code == 302 + + # 3. load your application authorization endpoint + # pyoidc produces a useless error message there + # https://github.com/CZ-NIC/pyoidc/issues/824 + res3 = client_app.get(res2.headers["Location"], status=302, expect_errors=True) + + # 4. redirect to the protected page + res4 = res3.follow(status=200) + res4.mustcontain(no="S’identifier") + res4.mustcontain("se déconnecter") + + user = db.session.get(User, 1) + assert user.email == iam_user.emails[0] + assert user.given_name == iam_user.given_name + assert user.family_name == iam_user.family_name diff --git a/web/tests/test_bbb_api_caching.py b/web/tests/test_bbb_api_caching.py new file mode 100644 index 00000000..0947ea78 --- /dev/null +++ b/web/tests/test_bbb_api_caching.py @@ -0,0 +1,198 @@ +import pytest + + +@pytest.fixture +def configuration(configuration): + configuration["BIGBLUEBUTTON_API_CACHE_DURATION"] = 5 + return configuration + + +IS_MEETING_RUNNING_SUCCESS_RESPONSE = """ + + SUCCESS + true + +""" + + +def test_is_meeting_running(meeting, mocker): + """Tests that the requests to the ismeetingrunning endpoint of the BBB API + are cached.""" + + class Response: + content = IS_MEETING_RUNNING_SUCCESS_RESPONSE + + send = mocker.patch("requests.Session.send", return_value=Response) + + assert send.call_count == 0 + + assert meeting.bbb.is_meeting_running() + assert send.call_count == 1 + + assert meeting.bbb.is_meeting_running() + assert send.call_count == 1 + + +GET_RECORDINGS_RESPONSE = """ + + SUCCESS + + + ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124 + c637ba21adcd0191f48f5c4bf23fab0f96ed5c18 + ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124 + Fred's Room + false + true + published + 1530718721124 + 1530718810456 + 3 + 951067 + + https://bbb-analytics.url + false + c637ba21adcd0191f48f5c4bf23fab0f96ed5c18 + Fred's Room + + + unknown + 0 + false + + 1104836 + + + presentation + https://demo.bigbluebutton.org/playback/presentation/2.0/playback.html?meetingId=ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124 + 7177 + 0 + 1104836 + + + Welcome tohttps://demo.bigbluebutton.org/presentation/ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124/presentation/d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1530718721134/thumbnails/thumb-1.png + (this slide left blank for use as a whiteboard)https://demo.bigbluebutton.org/presentation/ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124/presentation/d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1530718721134/thumbnails/thumb-2.png + (this slide left blank for use as a whiteboard)https://demo.bigbluebutton.org/presentation/ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124/presentation/d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1530718721134/thumbnails/thumb-3.png + + + + + video + https://demo.bigbluebutton.org/podcast/ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124/meeting.mp4 + 0 + 0 + 1104836 + + + + + ffbfc4cc24428694e8b53a4e144f414052431693-1530278898111 + c637ba21adcd0191f48f5c4bf23fab0f96ed5c18 + ffbfc4cc24428694e8b53a4e144f414052431693-1530278898111 + Fred's Room + false + true + published + 1530278898111 + 1530281194326 + 7 + 381530 + + Recording title hand written + Fred's Room + c637ba21adcd0191f48f5c4bf23fab0f96ed5c18 + https://bbb-analytics.url + false + + + unknown + 0 + false + + + + podcast + https://demo.bigbluebutton.org/podcast/ffbfc4cc24428694e8b53a4e144f414052431693-1530278898111/audio.ogg + 0 + 33 + + + presentation + https://demo.bigbluebutton.org/playback/presentation/2.0/playback.html?meetingId=ffbfc4cc24428694e8b53a4e144f414052431693-1530278898111 + 139458 + 33 + + + Welcome tohttps://demo.bigbluebutton.org/presentation/ffbfc4cc24428694e8b53a4e144f414052431693-1530278898111/presentation/d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1530278898120/thumbnails/thumb-1.png + (this slide left blank for use as a whiteboard)https://demo.bigbluebutton.org/presentation/ffbfc4cc24428694e8b53a4e144f414052431693-1530278898111/presentation/d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1530278898120/thumbnails/thumb-2.png + (this slide left blank for use as a whiteboard)https://demo.bigbluebutton.org/presentation/ffbfc4cc24428694e8b53a4e144f414052431693-1530278898111/presentation/d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1530278898120/thumbnails/thumb-3.png + + + + + + + +""" + + +def test_get_recordings(meeting, mocker): + """Tests that the requests to the getrecordings endpoint of the BBB API are + cached.""" + + class Response: + content = GET_RECORDINGS_RESPONSE + + send = mocker.patch("requests.Session.send", return_value=Response) + + assert send.call_count == 0 + + recordings = meeting.bbb.get_recordings() + assert len(recordings) == 2 + assert send.call_count == 1 + + recordings = meeting.bbb.get_recordings() + assert len(recordings) == 2 + assert send.call_count == 1 + + +CREATE_RESPONSE = """ + + SUCCESS + Test + 640ab2bae07bedc4c163f679a746f7ab7fb5d1fa-1531155809613 + bbb-none + ap + mp + 1531155809613 + 70757 + 613-555-1234 + Mon Jul 09 17:03:29 UTC 2018 + false + 0 + false + duplicateWarning + This conference was already in existence and may currently be in progress. + +""" + + +def test_create(meeting, mocker): + """Tests that the requests to the create endpoint of the BBB API are NOT + cached.""" + + class Response: + content = CREATE_RESPONSE + + send = mocker.patch("requests.Session.send", return_value=Response) + mocker.patch("requests.post") + + assert send.call_count == 0 + + data = meeting.bbb.create() + assert data["returncode"] == "SUCCESS" + assert send.call_count == 1 + + data = meeting.bbb.create() + assert data["returncode"] == "SUCCESS" + assert send.call_count == 2 diff --git a/web/tests/test_default.py b/web/tests/test_default.py index 04c42ce0..7c178881 100644 --- a/web/tests/test_default.py +++ b/web/tests/test_default.py @@ -1,5 +1,6 @@ from flask import abort from flask import url_for +from flask_webtest import TestApp def test_custom_400(client_app): @@ -52,7 +53,7 @@ def test_home__anonymous_user(client_app, mocker): "participantCount": 123, "runningCount": 33, } - mocker.patch("flaskr.routes.get_meetings_stats", return_value=STATS) + mocker.patch("b3desk.endpoints.public.get_meetings_stats", return_value=STATS) response = client_app.get( "/home", extra_environ={"REMOTE_ADDR": "127.0.0.1"}, status=200 @@ -66,27 +67,25 @@ def test_home__authenticated_user(client_app, mocker, authenticated_user): "participantCount": 123, "runningCount": 33, } - mocker.patch("flaskr.routes.get_meetings_stats", return_value=STATS) + mocker.patch("b3desk.endpoints.public.get_meetings_stats", return_value=STATS) response = client_app.get( "/home", extra_environ={"REMOTE_ADDR": "127.0.0.1"}, status=302 ) - assert response.location == url_for("routes.welcome") + assert response.location == url_for("public.welcome") -def test_change_language(client_app): - client_app.get("/faq?lang=fr", status=200) - with client_app.session_transaction() as session: - assert session["lang"] == "fr" +def test_change_language(app): + client_app = TestApp(app) + res = client_app.get("/faq?lang=fr", status=200) + assert res.session["lang"] == "fr" - client_app.get("/faq?lang=uk", status=200) - with client_app.session_transaction() as session: - assert session["lang"] == "uk" + res = client_app.get("/faq?lang=uk", status=200) + assert res.session["lang"] == "uk" - client_app.get("/faq", status=200) - with client_app.session_transaction() as session: - assert session["lang"] == "uk" + res = client_app.get("/faq", status=200) + assert res.session["lang"] == "uk" def test_faq__anonymous_user(client_app): @@ -101,28 +100,30 @@ def test_faq__authenticated_user(client_app, authenticated_user): response.mustcontain("Alice Cooper") -def test_documentation__anonymous_user(app, client_app, mocker): - app.config["DOCUMENTATION_LINK"]["url"] = "/documentation" - app.config["DOCUMENTATION_LINK"]["is_external"] = False +def test_documentation__anonymous_user(client_app, mocker): + client_app.app.config["DOCUMENTATION_LINK"]["url"] = "/documentation" + client_app.app.config["DOCUMENTATION_LINK"]["is_external"] = False response = client_app.get("/documentation", status=200) response.mustcontain(no="Alice Cooper") -def test_documentation__authenticated_user(app, client_app, authenticated_user): - app.config["DOCUMENTATION_LINK"]["url"] = "/documentation" - app.config["DOCUMENTATION_LINK"]["is_external"] = False +def test_documentation__authenticated_user(client_app, authenticated_user): + client_app.app.config["DOCUMENTATION_LINK"]["url"] = "/documentation" + client_app.app.config["DOCUMENTATION_LINK"]["is_external"] = False response = client_app.get("/documentation", status=200) response.mustcontain("Alice Cooper") -def test_documentation_with_redirection(app, client_app): - app.config["DOCUMENTATION_LINK"]["url"] = "https://documentation_redirect.ion" - app.config["DOCUMENTATION_LINK"]["is_external"] = True +def test_documentation_with_redirection(client_app): + client_app.app.config["DOCUMENTATION_LINK"]["url"] = ( + "https://documentation_redirect.ion" + ) + client_app.app.config["DOCUMENTATION_LINK"]["is_external"] = True response = client_app.get("/documentation", status=302) - response.mustcontain(app.config["DOCUMENTATION_LINK"]["url"]) + response.mustcontain(client_app.app.config["DOCUMENTATION_LINK"]["url"]) def test_accessibilite__anonymous_user(client_app): diff --git a/web/tests/test_user.py b/web/tests/test_user.py index d1610efc..944f7aca 100644 --- a/web/tests/test_user.py +++ b/web/tests/test_user.py @@ -1,9 +1,13 @@ from datetime import date -from flaskr.models import get_or_create_user -from flaskr.models import User +import pytest from freezegun import freeze_time +from b3desk.models import db +from b3desk.models.users import User +from b3desk.models.users import get_or_create_user +from b3desk.models.users import make_nextcloud_credentials_request + def test_get_or_create_user(client_app): user_info = { @@ -14,7 +18,7 @@ def test_get_or_create_user(client_app): } get_or_create_user(user_info) - user = User.query.get(1) + user = db.session.get(User, 1) assert user.given_name == "Alice" assert user.family_name == "Cooper" assert user.email == "alice@mydomain.test" @@ -32,9 +36,75 @@ def test_update_last_connection_if_more_than_24h(client_app): get_or_create_user(user_info) with freeze_time("2021-08-11"): - user = User.query.get(1) + user = db.session.get(User, 1) assert user.last_connection_utc_datetime.date() == date(2021, 8, 10) get_or_create_user(user_info) assert user.last_connection_utc_datetime.date() == date(2021, 8, 11) + + +def test_make_nextcloud_credentials_request_with_scheme_response( + client_app, app, cloud_service_response, mocker +): + assert cloud_service_response.data["nclocator"].startswith("http://") + mocker.patch( + "b3desk.models.users.requests.post", return_value=cloud_service_response + ) + app.config["FORCE_HTTPS_ON_EXTERNAL_URLS"] = False + credentials = make_nextcloud_credentials_request( + url=app.config["NC_LOGIN_API_URL"], + payload={"username": "Alice"}, + headers={"X-API-KEY": app.config["NC_LOGIN_API_KEY"]}, + ) + assert credentials["nclocator"].startswith("http://") + + +@pytest.mark.secure +def test_make_nextcloud_credentials_request_with_secure_response( + client_app, app, cloud_service_response, mocker +): + assert cloud_service_response.data["nclocator"].startswith("https://") + mocker.patch( + "b3desk.models.users.requests.post", return_value=cloud_service_response + ) + app.config["FORCE_HTTPS_ON_EXTERNAL_URLS"] = False + credentials = make_nextcloud_credentials_request( + url=app.config["NC_LOGIN_API_URL"], + payload={"username": "Alice"}, + headers={"X-API-KEY": app.config["NC_LOGIN_API_KEY"]}, + ) + assert credentials["nclocator"].startswith("https://") + + +def test_make_nextcloud_credentials_request_force_secure_for_unsecure( + client_app, app, cloud_service_response, mocker +): + assert cloud_service_response.data["nclocator"].startswith("http://") + mocker.patch( + "b3desk.models.users.requests.post", return_value=cloud_service_response + ) + app.config["FORCE_HTTPS_ON_EXTERNAL_URLS"] = True + credentials = make_nextcloud_credentials_request( + url=app.config["NC_LOGIN_API_URL"], + payload={"username": "Alice"}, + headers={"X-API-KEY": app.config["NC_LOGIN_API_KEY"]}, + ) + assert credentials["nclocator"].startswith("https://") + + +@pytest.mark.no_scheme +def test_make_nextcloud_credentials_request_force_secure_for_missing_scheme( + client_app, app, cloud_service_response, mocker +): + assert not cloud_service_response.data["nclocator"].startswith("http") + mocker.patch( + "b3desk.models.users.requests.post", return_value=cloud_service_response + ) + app.config["FORCE_HTTPS_ON_EXTERNAL_URLS"] = True + credentials = make_nextcloud_credentials_request( + url=app.config["NC_LOGIN_API_URL"], + payload={"username": "Alice"}, + headers={"X-API-KEY": app.config["NC_LOGIN_API_KEY"]}, + ) + assert credentials["nclocator"].startswith("https://") diff --git a/web/translations/en/LC_MESSAGES/messages.po b/web/translations/en/LC_MESSAGES/messages.po index 00754fe1..c7469027 100644 --- a/web/translations/en/LC_MESSAGES/messages.po +++ b/web/translations/en/LC_MESSAGES/messages.po @@ -18,60 +18,60 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.8.0\n" -#: web/flaskr/forms.py:56 +#: web/b3desk/forms.py:56 #, python-format msgid "Titre %(of_the_meeting)s" msgstr "Title of the meeting" -#: web/flaskr/forms.py:60 +#: web/b3desk/forms.py:60 #, python-format msgid "Créer %(a_meeting)s dont le titre est :" msgstr "Create a meeting with the title:" -#: web/flaskr/forms.py:66 +#: web/b3desk/forms.py:66 #, python-format msgid "%(my_meeting)s" msgstr "" -#: web/flaskr/forms.py:71 +#: web/b3desk/forms.py:71 msgid "Texte de bienvenue" msgstr "Welcome message" -#: web/flaskr/forms.py:72 +#: web/b3desk/forms.py:72 msgid "Ce texte apparait comme message de bienvenue sur le tchat public" msgstr "This text is displayed as a welcome message on the public chat" -#: web/flaskr/forms.py:75 +#: web/b3desk/forms.py:75 #, python-format msgid "Bienvenue dans %(this_meeting)s %(meeting_name)s." msgstr "Welcome in this meeting %(meeting_name)s." -#: web/flaskr/forms.py:81 +#: web/b3desk/forms.py:81 msgid "Le texte est trop long" msgstr "The text is too long" -#: web/flaskr/forms.py:85 +#: web/b3desk/forms.py:85 msgid "Nombre maximal de participants" msgstr "Maximal number of participants" -#: web/flaskr/forms.py:86 +#: web/b3desk/forms.py:86 msgid "Limitez vos salons à 250 personnes pour plus de confort" msgstr "Limit your rooms to 250 people for more comfort" -#: web/flaskr/forms.py:92 +#: web/b3desk/forms.py:92 msgid "Durée maximale en minutes" msgstr "Maximal duration, in minutes" -#: web/flaskr/forms.py:93 +#: web/b3desk/forms.py:93 #, python-format msgid "Après laquelle %(the_meeting)s stoppe automatiquement" msgstr "After which the meeting automatically stops" -#: web/flaskr/forms.py:101 +#: web/b3desk/forms.py:101 msgid "Salle d'attente" msgstr "Waiting room" -#: web/flaskr/forms.py:102 +#: web/b3desk/forms.py:102 #, python-format msgid "" "Placer les participants dans une salle d'attente lorsqu'ils rejoignent " @@ -81,118 +81,118 @@ msgstr "" "Place participants in a waiting room when they join the meeting. The " "organiser or moderator will have to accept them individually." -#: web/flaskr/forms.py:109 +#: web/b3desk/forms.py:109 msgid "Seul les modérateurs peuvent voir les webcams des autres participants" msgstr "Only moderators can see the webcams of other participants" -#: web/flaskr/forms.py:112 +#: web/b3desk/forms.py:112 msgid "Les participants ne verront pas la diffusion de la caméra des autres" msgstr "Participants will not see each other's camera broadcast" -#: web/flaskr/forms.py:118 +#: web/b3desk/forms.py:118 msgid "Micros fermés au démarrage" msgstr "Closed microphones at start-up" -#: web/flaskr/forms.py:119 +#: web/b3desk/forms.py:119 msgid "Les micros sont clos à la connexion des utilisateurs" msgstr "The microphones are closed when users log on" -#: web/flaskr/forms.py:125 +#: web/b3desk/forms.py:125 msgid "Verrouillage caméra" msgstr "Camera lock" -#: web/flaskr/forms.py:126 +#: web/b3desk/forms.py:126 msgid "Les participants ne pourront pas activer leur caméra" msgstr "Participants will not be able to activate their camera" -#: web/flaskr/forms.py:132 +#: web/b3desk/forms.py:132 msgid "Verrouillage micro" msgstr "Microphone lock" -#: web/flaskr/forms.py:133 +#: web/b3desk/forms.py:133 msgid "Les participants ne pourront pas activer leur micro" msgstr "Participants will not be able to activate their microphone" -#: web/flaskr/forms.py:137 +#: web/b3desk/forms.py:137 msgid "Désactivation de la discussion privée" msgstr "Deactivation of the private discussion" -#: web/flaskr/forms.py:138 +#: web/b3desk/forms.py:138 msgid "Interdit les échanges textes directs entre participants" msgstr "Prohibits direct text exchanges between participants" -#: web/flaskr/forms.py:144 +#: web/b3desk/forms.py:144 msgid "Désactivation de la discussion publique" msgstr "Deactivation of the public discussion" -#: web/flaskr/forms.py:145 +#: web/b3desk/forms.py:145 msgid "Pas de tchat" msgstr "No chat" -#: web/flaskr/forms.py:149 +#: web/b3desk/forms.py:149 msgid "Désactivation de la prise de notes" msgstr "Disabling note-taking" -#: web/flaskr/forms.py:150 +#: web/b3desk/forms.py:150 msgid "Pas de prise de notes collaborative" msgstr "No collaborative note-taking" -#: web/flaskr/forms.py:154 +#: web/b3desk/forms.py:154 msgid "Message à l'attention des modérateurs" msgstr "Message for the attention of the moderators" -#: web/flaskr/forms.py:155 +#: web/b3desk/forms.py:155 msgid "150 caractères max" msgstr "150 characters max" -#: web/flaskr/forms.py:156 +#: web/b3desk/forms.py:156 msgid "Bienvenue aux modérateurs" msgstr "Welcome to the moderators" -#: web/flaskr/forms.py:158 +#: web/b3desk/forms.py:158 msgid "Le message est trop long" msgstr "The message is too long" -#: web/flaskr/forms.py:163 +#: web/b3desk/forms.py:163 #, python-format msgid "Url de redirection après %(the_meeting)s" msgstr "Redirection url after the meeting" -#: web/flaskr/forms.py:170 +#: web/b3desk/forms.py:170 msgid "Renouveler le lien modérateur" msgstr "Renew the moderator link" -#: web/flaskr/forms.py:171 web/flaskr/forms.py:180 +#: web/b3desk/forms.py:171 web/b3desk/forms.py:180 msgid "Ce code vous permet si vous le changez de bloquer les anciens liens" msgstr "This code allows you, if you change it, to block the old links" -#: web/flaskr/forms.py:179 +#: web/b3desk/forms.py:179 msgid "Renouveler le lien participants" msgstr "Renewing the link between participants" -#: web/flaskr/forms.py:191 +#: web/b3desk/forms.py:191 msgid "Enregistrement manuel" msgstr "" -#: web/flaskr/forms.py:192 +#: web/b3desk/forms.py:192 msgid "Autoriser le démarrage et l'arrêt de l'enregistrement par le modérateur" msgstr "Allow moderator to start and stop recording" -#: web/flaskr/forms.py:198 +#: web/b3desk/forms.py:198 msgid "Enregistrement automatique" msgstr "Automatic recording" -#: web/flaskr/forms.py:199 +#: web/b3desk/forms.py:199 msgid "Démarrage automatique" msgstr "Automatic start-up" -#: web/flaskr/routes.py:548 +#: web/b3desk/routes.py:548 msgid "" "Courriel invalide. Avez vous bien tapé votre email ? Vous pouvez " "réessayer." msgstr "Invalid email. Did you type your email correctly? You can try again." -#: web/flaskr/routes.py:556 +#: web/b3desk/routes.py:556 msgid "" "Ce courriel ne correspond pas à un service de l'État. Si vous appartenez " "à un service de l'État mais votre courriel n'est pas reconnu par " @@ -202,85 +202,85 @@ msgstr "" "to to a government department but your email is not recognised by " "Webinar, contact us so we can add it!" -#: web/flaskr/routes.py:568 +#: web/b3desk/routes.py:568 msgid "Vous avez reçu un courriel pour vous connecter" msgstr "You have received an email to log in" -#: web/flaskr/routes.py:623 web/flaskr/routes.py:653 +#: web/b3desk/routes.py:623 web/b3desk/routes.py:653 msgid "Vous ne pouvez pas voir cet élément (identifiant incorrect)" msgstr "You cannot see this item (incorrect ID)" -#: web/flaskr/routes.py:643 web/flaskr/routes.py:676 +#: web/b3desk/routes.py:643 web/b3desk/routes.py:676 msgid "Vous ne pouvez pas consulter cet élément" msgstr "You cannot view this item" -#: web/flaskr/routes.py:805 +#: web/b3desk/routes.py:805 msgid "Vous ne pouvez pas modifier cet élément" msgstr "You cannot change this item" -#: web/flaskr/routes.py:1264 +#: web/b3desk/routes.py:1264 #, python-format msgid "%(meeting_name)s modifications prises en compte" msgstr "%(meeting_name)s changes taken into account" -#: web/flaskr/routes.py:1427 web/flaskr/routes.py:1474 +#: web/b3desk/routes.py:1427 web/b3desk/routes.py:1474 #, python-format msgid "Aucune %(meeting_label)s ne correspond à ces paramètres" msgstr "No meeting corresponds to these parameters" -#: web/flaskr/routes.py:1437 web/flaskr/routes.py:1589 +#: web/b3desk/routes.py:1437 web/b3desk/routes.py:1589 msgid "Lien invalide" msgstr "Invalid link" -#: web/flaskr/routes.py:1442 web/flaskr/routes.py:1594 +#: web/b3desk/routes.py:1442 web/b3desk/routes.py:1594 msgid "Lien expiré" msgstr "Expired link" -#: web/flaskr/routes.py:1581 +#: web/b3desk/routes.py:1581 #, python-format msgid "%(meeting_label)s inexistante" msgstr "meeting non-existent" -#: web/flaskr/routes.py:1638 +#: web/b3desk/routes.py:1638 msgid "Accès non autorisé" msgstr "Unauthorised access" -#: web/flaskr/routes.py:1669 +#: web/b3desk/routes.py:1669 msgid "Élément supprimé" msgstr "Deleted item" -#: web/flaskr/routes.py:1671 +#: web/b3desk/routes.py:1671 msgid "Vous ne pouvez pas supprimer cet élément" msgstr "You cannot delete this item" -#: web/flaskr/routes.py:1687 +#: web/b3desk/routes.py:1687 msgid "Vidéo supprimée" msgstr "Deleted video" -#: web/flaskr/routes.py:1691 +#: web/b3desk/routes.py:1691 #, python-format msgid "Nous n'avons pas pu supprimer cette vidéo : %(code)s, %(message)s" msgstr "We were unable to remove this video : %(code)s, %(message)s" -#: web/flaskr/routes.py:1700 +#: web/b3desk/routes.py:1700 msgid "Vous ne pouvez pas supprimer cette enregistrement" msgstr "You cannot delete this record" -#: web/flaskr/templates/brand.html:19 +#: web/b3desk/templates/brand.html:19 #, python-format msgid "%(service_title)s" msgstr "" -#: web/flaskr/templates/brand.html:26 +#: web/b3desk/templates/brand.html:26 #, python-format msgid "%(service_tagline)s" msgstr "" -#: web/flaskr/templates/content.py:6 +#: web/b3desk/templates/content.py:6 msgid "Quelles sont les conditions d’accès pour accéder aux services ?" msgstr "What are the conditions of access to the services?" -#: web/flaskr/templates/content.py:9 +#: web/b3desk/templates/content.py:9 msgid "" "Cette plateforme offre une solution complète et puissante, adaptée à de " "nombreux types d’événements en ligne, jusqu’à 350 participants " @@ -347,11 +347,11 @@ msgstr "" "- On IOS, the Safari browser is recommended for iphone and ipad (IOS 12.2+)\n" "- On Android, use Chrome or Firefox browser (Android 6.0+)\n" -#: web/flaskr/templates/content.py:33 +#: web/b3desk/templates/content.py:33 msgid "Quel est le matériel nécessaire ?" msgstr "What equipment is needed?" -#: web/flaskr/templates/content.py:34 +#: web/b3desk/templates/content.py:34 msgid "" "Pour utiliser l’outil Webinaire de l’État, il vous suffit de disposer du " "matériel suivant :\n" @@ -390,11 +390,11 @@ msgstr "" "the camera and microphone can be activated depending on the " "contextcontext of intervention." -#: web/flaskr/templates/content.py:46 +#: web/b3desk/templates/content.py:46 msgid "Puis-je utiliser mon smartphone ou ma tablette pour me connecter ?" msgstr "Can I use my smartphone or tablet to connect?" -#: web/flaskr/templates/content.py:49 +#: web/b3desk/templates/content.py:49 msgid "" "Le Webinaire de l’Etat fonctionne également sur les appareils mobiles par" " un simple lien (sans application) sur le portail ou dans le séminaire. " @@ -406,11 +406,11 @@ msgstr "" "browser is recommended. On Android, use the latest version of a modern " "web browser (Firefox, Chrome...). (Android 6.0+)\n" -#: web/flaskr/templates/content.py:55 +#: web/b3desk/templates/content.py:55 msgid "Comment créer un séminaire ?" msgstr "How to create a webinar ?" -#: web/flaskr/templates/content.py:56 +#: web/b3desk/templates/content.py:56 msgid "" "Si vous êtes un agent de l’état, vous pouvez :\n" "- Créer des séminaires immédiatement en renseignant votre courriel " @@ -437,11 +437,11 @@ msgstr "" "If your domain name is not recognised, and you think you are eligible for" " the service, send an email to contact@webinaire.numerique.gouv.fr\n" -#: web/flaskr/templates/content.py:67 +#: web/b3desk/templates/content.py:67 msgid "Comment créer un compte ?" msgstr "How to create an account?" -#: web/flaskr/templates/content.py:68 +#: web/b3desk/templates/content.py:68 msgid "" "En tant qu’agent de l’État, si vous organisez régulièrement des " "séminaires vous pouvez créer un compte pour organiser et conserver " @@ -463,11 +463,11 @@ msgstr "" " table, General Assembly, Collaborative or ideation workshops, Committees" " in large numbers, ... etc.)." -#: web/flaskr/templates/content.py:75 +#: web/b3desk/templates/content.py:75 msgid "Comment inviter les participants/ modérateurs" msgstr "How to invite participants/moderators" -#: web/flaskr/templates/content.py:76 +#: web/b3desk/templates/content.py:76 msgid "" "L’organisateur qui a créé le séminaire peut partager le lien :\n" "« Participants » qu’ils soient de l’administration ou de l’extérieur " @@ -475,11 +475,11 @@ msgid "" "« Organisateurs/modérateurs » qui géreront avec vous le séminaire." msgstr "" -#: web/flaskr/templates/content.py:83 +#: web/b3desk/templates/content.py:83 msgid "Rejoindre un Webinaire en appel téléphonique ?" msgstr "Join a Webinar on a phone call?" -#: web/flaskr/templates/content.py:84 +#: web/b3desk/templates/content.py:84 msgid "" "Une fois dans le séminaire, il est possible d’utiliser aussi son " "téléphone fixe ou mobile pour suivre le séminaire.\n" @@ -505,11 +505,11 @@ msgstr "" "Once in the conference, press the \"0\" key on your phone to turn your " "microphone on or off." -#: web/flaskr/templates/content.py:95 +#: web/b3desk/templates/content.py:95 msgid "J'ai des perturbations audio ou vidéo ?" msgstr "I have audio or video disturbances?" -#: web/flaskr/templates/content.py:96 +#: web/b3desk/templates/content.py:96 msgid "" "\n" "Pour l’audio, rapprochez-vous de votre borne wifi, ou/et coupez votre " @@ -542,19 +542,19 @@ msgstr "" "To use less bandwidth and enjoy the service in the best conditions, with " "many participants, we recommend to connect outside VPN.\n" -#: web/flaskr/templates/content.py:110 +#: web/b3desk/templates/content.py:110 msgid "Besoin de contacter l'équipe du Webinaire de l’Etat ?" msgstr "Need to contact the Webinar team?" -#: web/flaskr/templates/content.py:113 +#: web/b3desk/templates/content.py:113 msgid "contact@webinaire.numerique.gouv.fr" msgstr "" -#: web/flaskr/templates/content.py:116 +#: web/b3desk/templates/content.py:116 msgid "Besoin de contacter l'équipe du ministére de l'Éducation nationale ?" msgstr "Need to contact the ministry of Education's team?" -#: web/flaskr/templates/content.py:119 +#: web/b3desk/templates/content.py:119 msgid "" "Rendez-vous sur votre portail d'assistance académique " "https://www.education.gouv.fr/la-messagerie-professionnelle-3446 ou sur " @@ -563,15 +563,15 @@ msgstr "" "Go to your academic support portal https://www.education.gouv.fr/la-" "messagerie-professionnelle-3446 or on https://apps.education.fr" -#: web/flaskr/templates/empty.html:2 +#: web/b3desk/templates/empty.html:2 msgid "Vous devez vous identifier pour consulter la liste des visioconférences." msgstr "You must be logged in to view the list of videoconferences." -#: web/flaskr/templates/faq.html:8 +#: web/b3desk/templates/faq.html:8 msgid "FAQ - Modalités d'accès" msgstr "FAQ - How to access" -#: web/flaskr/templates/footer.html:12 +#: web/b3desk/templates/footer.html:12 msgid "" "Service proposé par la Direction interministérielle du numérique et la " "Direction du numérique pour l'éducation" @@ -579,68 +579,68 @@ msgstr "" "Service offered by the Direction interministérielle du numérique and the " "Direction du numérique pour l'éducation" -#: web/flaskr/templates/footer.html:15 +#: web/b3desk/templates/footer.html:15 msgid "Le code source est ouvert et les contributions sont bienvenues." msgstr "The source code is open and contributions are welcome." -#: web/flaskr/templates/footer.html:16 +#: web/b3desk/templates/footer.html:16 msgid "Voir le code source - nouvelle fenêtre" msgstr "View source code - new window" -#: web/flaskr/templates/footer.html:16 +#: web/b3desk/templates/footer.html:16 msgid "Voir le code source" msgstr "View source code" -#: web/flaskr/templates/footer.html:37 +#: web/b3desk/templates/footer.html:37 msgid "Accessibilité : non conforme" msgstr "Accessibility: not compliant" -#: web/flaskr/templates/footer.html:40 -#: web/flaskr/templates/footer/mentions_legales.html:10 +#: web/b3desk/templates/footer.html:40 +#: web/b3desk/templates/footer/mentions_legales.html:10 msgid "Mentions légales" msgstr "Legal Notice" -#: web/flaskr/templates/footer.html:43 +#: web/b3desk/templates/footer.html:43 msgid "Données personnelles et cookies" msgstr "Personal data and cookies" -#: web/flaskr/templates/footer.html:46 web/flaskr/templates/footer/cgu.html:10 +#: web/b3desk/templates/footer.html:46 web/b3desk/templates/footer/cgu.html:10 msgid "Conditions générales d’utilisation" msgstr "Terms and Conditions" -#: web/flaskr/templates/jumbotron.html:8 +#: web/b3desk/templates/jumbotron.html:8 #, python-format msgid "Lancer %(a_meeting)s" msgstr "Start a meeting" -#: web/flaskr/templates/jumbotron.html:9 +#: web/b3desk/templates/jumbotron.html:9 #, python-format msgid "Lancer %(the_meeting)s - nouvelle fenêtre" msgstr "Start the meeting - new window" -#: web/flaskr/templates/jumbotron.html:9 +#: web/b3desk/templates/jumbotron.html:9 #, python-format -msgid "Démarrer %(a_meeting)s immédiatement" -msgstr "Start a meeting immediately" +msgid "Ouvrir %(a_meeting)s temporaire" +msgstr "Start a temporary meeting" -#: web/flaskr/templates/jumbotron.html:19 -#: web/flaskr/templates/jumbotron.html:49 +#: web/b3desk/templates/jumbotron.html:19 +#: web/b3desk/templates/jumbotron.html:49 #, python-format msgid "Actuellement, il y a %(count)s webinaire" msgid_plural "Actuellement, il y a %(count)s webinaires" msgstr[0] "Currently, there is %(count)s webinar" msgstr[1] "Currently, there is %(count)s webinars" -#: web/flaskr/templates/jumbotron.html:24 -#: web/flaskr/templates/jumbotron.html:54 +#: web/b3desk/templates/jumbotron.html:24 +#: web/b3desk/templates/jumbotron.html:54 #, python-format msgid "et %(count)s participant" msgid_plural "et %(count)s participants" msgstr[0] "and %(count)s participant" msgstr[1] "and %(count)s participants" -#: web/flaskr/templates/jumbotron.html:29 -#: web/flaskr/templates/jumbotron.html:59 +#: web/b3desk/templates/jumbotron.html:29 +#: web/b3desk/templates/jumbotron.html:59 #, python-format msgid "" " sur une capacité moyenne pour la plateforme de %(max_participants)s " @@ -649,12 +649,12 @@ msgstr "" "on an average capacity for the platform of %(max_participants)s " "participants." -#: web/flaskr/templates/jumbotron.html:42 +#: web/b3desk/templates/jumbotron.html:42 #, python-format msgid "Vous organisez régulièrement des %(some_meetings)s" msgstr "You regularly organize meetings" -#: web/flaskr/templates/jumbotron.html:43 +#: web/b3desk/templates/jumbotron.html:43 #, python-format msgid "" "Vous êtes agent de l’État, créez un compte pour organiser et conserver " @@ -663,16 +663,16 @@ msgstr "" "You are a state employee, create an account to organize and keep your " "meetings." -#: web/flaskr/templates/jumbotron.html:44 +#: web/b3desk/templates/jumbotron.html:44 msgid "Se connecter ou créer un compte" msgstr "Connect or create an account" -#: web/flaskr/templates/jumbotron.html:73 +#: web/b3desk/templates/jumbotron.html:73 #, python-format msgid "Démarrer %(a_meeting)s en ligne immédiatement" msgstr "Start a meeting online immediately" -#: web/flaskr/templates/jumbotron.html:83 +#: web/b3desk/templates/jumbotron.html:83 #, python-format msgid "" "Recevez par courriel un lien organisateur %(of_the_meeting)s, actif une " @@ -681,21 +681,21 @@ msgstr "" "Receive an email with an organizer link to the meeting, active one week, " "to send to attendees." -#: web/flaskr/templates/jumbotron.html:88 +#: web/b3desk/templates/jumbotron.html:88 msgid "Votre courriel professionnel" msgstr "Your professional email" -#: web/flaskr/templates/jumbotron.html:92 +#: web/b3desk/templates/jumbotron.html:92 #, python-format msgid "Créer %(my_meeting)s" msgstr "Create my meeting" -#: web/flaskr/templates/jumbotron.html:108 +#: web/b3desk/templates/jumbotron.html:108 #, python-format msgid "Vous essayez de rejoindre %(a_meeting)s" msgstr "You try to join a meeting" -#: web/flaskr/templates/jumbotron.html:109 +#: web/b3desk/templates/jumbotron.html:109 #, python-format msgid "" "Pour rejoindre %(a_meeting_to_which)s vous êtes invité, cliquez sur le " @@ -704,75 +704,75 @@ msgstr "" "To join a meeting to which you are invited, click on the link sent to you" " by the organizer/moderator." -#: web/flaskr/templates/redirections.html:4 +#: web/b3desk/templates/redirections.html:4 msgid "Connectez-vous ou créez un compte" msgstr "Connect or create an account" -#: web/flaskr/templates/redirections.html:10 +#: web/b3desk/templates/redirections.html:10 msgid "Autres profils" msgstr "Other profiles" -#: web/flaskr/templates/rie.html:3 +#: web/b3desk/templates/rie.html:3 msgid "Service accessible suivant les politiques de sécurité de votre ministère." msgstr "" -#: web/flaskr/templates/rie.html:4 +#: web/b3desk/templates/rie.html:4 msgid "" "Si l'audio ou la vidéo ne fonctionne pas, vous devez utiliser un autre " "appareil (ordinateur, smartphone)." msgstr "" -#: web/flaskr/templates/rie.html:5 +#: web/b3desk/templates/rie.html:5 msgid "en savoir plus" msgstr "" -#: web/flaskr/templates/tools.html:13 +#: web/b3desk/templates/tools.html:13 msgid "Modalités d'accès" msgstr "" -#: web/flaskr/templates/tools.html:32 +#: web/b3desk/templates/tools.html:32 msgid "se déconnecter" msgstr "" -#: web/flaskr/templates/tools.html:40 +#: web/b3desk/templates/tools.html:40 msgid "S’identifier" msgstr "" -#: web/flaskr/templates/errors/403.html:11 +#: web/b3desk/templates/errors/403.html:11 msgid "Erreur 403" msgstr "" -#: web/flaskr/templates/errors/403.html:12 +#: web/b3desk/templates/errors/403.html:12 msgid "" "Vous n’êtes pas autorisé à accéder cette page. Vous pouvez retourner à l’accueil." msgstr "" -#: web/flaskr/templates/errors/404.html:11 +#: web/b3desk/templates/errors/404.html:11 msgid "Erreur 404" msgstr "" -#: web/flaskr/templates/errors/404.html:12 +#: web/b3desk/templates/errors/404.html:12 msgid "" "Cette page n'existe pas. Vous pouvez retourner à " "l’accueil." msgstr "" -#: web/flaskr/templates/errors/500.html:11 +#: web/b3desk/templates/errors/500.html:11 msgid "Erreur 500" msgstr "" -#: web/flaskr/templates/errors/500.html:12 +#: web/b3desk/templates/errors/500.html:12 msgid "" "Le serveur a rencontré une erreur interne, veuillez réessayer " "ultérieurement." msgstr "" -#: web/flaskr/templates/footer/accessibilite.html:9 +#: web/b3desk/templates/footer/accessibilite.html:9 msgid "Accessibilité" msgstr "" -#: web/flaskr/templates/footer/accessibilite.html:10 +#: web/b3desk/templates/footer/accessibilite.html:10 msgid "" "Le site webinaire.numerique.gouv.fr est développé selon les " "recommendations du annuaire de l'administration" msgstr "" -#: web/flaskr/templates/footer/cgu.html:11 +#: web/b3desk/templates/footer/cgu.html:11 msgid "" "Le webinaire, Visio-ecoles/colleges/lycees/agents de l’État permet " "d’accéder à la page d’accueil du sous-domaine internet utilisé par l’Etat" @@ -853,7 +853,7 @@ msgid "" "les partenaires du service public." msgstr "" -#: web/flaskr/templates/footer/cgu.html:12 +#: web/b3desk/templates/footer/cgu.html:12 msgid "" "Le sous-domaine « https://visio-" @@ -875,25 +875,25 @@ msgid "" "Nationale, de la Jeunesse et des Sports." msgstr "" -#: web/flaskr/templates/footer/cgu.html:14 +#: web/b3desk/templates/footer/cgu.html:14 msgid "" "Le service est maintenu en conditions opérationnelles et ses évolutions " "sont assurées par le Ministère de l’Éducation Nationale, de la Jeunesse " "et des Sports, ci-après dénommé « l’éditeur »." msgstr "" -#: web/flaskr/templates/footer/cgu.html:15 +#: web/b3desk/templates/footer/cgu.html:15 msgid "" "Toute utilisation des ressources de domaine de publication est " "subordonnée au respect des présentes conditions générales d’utilisation " "(CGU)." msgstr "" -#: web/flaskr/templates/footer/cgu.html:17 +#: web/b3desk/templates/footer/cgu.html:17 msgid "Objet" msgstr "" -#: web/flaskr/templates/footer/cgu.html:18 +#: web/b3desk/templates/footer/cgu.html:18 msgid "" "Le sous-domaine permet de publier sur internet l’offre de service " "interministérielle de webconférence.

    " msgstr "" -#: web/flaskr/templates/footer/cgu.html:19 +#: web/b3desk/templates/footer/cgu.html:19 msgid "Code de conduite et responsabilités des Utilisateurs" msgstr "" -#: web/flaskr/templates/footer/cgu.html:20 +#: web/b3desk/templates/footer/cgu.html:20 msgid "" "L’utilisation de ce service interministériel est libre et gratuite pour " "les utilisateurs des services de l’Etat, et sur invitation, pour les " @@ -917,14 +917,14 @@ msgid "" "et responsabilités de l’éditeur." msgstr "" -#: web/flaskr/templates/footer/cgu.html:21 +#: web/b3desk/templates/footer/cgu.html:21 msgid "" "Sitôt entré sur la page d’accueil, l’utilisateur peut en consulter les " "contenus ou accéder à un salon en saisissant le nom de ce salon ou, pour " "les agents de l’Etat, en créant ledit salon." msgstr "" -#: web/flaskr/templates/footer/cgu.html:22 +#: web/b3desk/templates/footer/cgu.html:22 msgid "" "À l’instant où l’utilisateur accède à un salon de webconférence, il " "devient seul responsable des données et des contenus qu’il échange sur le" @@ -932,17 +932,17 @@ msgid "" "netiquette." msgstr "" -#: web/flaskr/templates/footer/cgu.html:23 +#: web/b3desk/templates/footer/cgu.html:23 msgid "Usage professionnel" msgstr "" -#: web/flaskr/templates/footer/cgu.html:24 +#: web/b3desk/templates/footer/cgu.html:24 msgid "" "Le service de Webinaire, Visio-ecoles/colleges/lycees/agents mis à " "disposition est à usage professionnel." msgstr "" -#: web/flaskr/templates/footer/cgu.html:25 +#: web/b3desk/templates/footer/cgu.html:25 msgid "" "Seule l’utilisation à usage professionnel de cette ressource mise à " "disposition est tolérée, l’utilisateur est attentif à ce que ces usages " @@ -950,11 +950,11 @@ msgid "" "service auquel il accède." msgstr "" -#: web/flaskr/templates/footer/cgu.html:26 +#: web/b3desk/templates/footer/cgu.html:26 msgid "Engagements et responsabilités de l’éditeur" msgstr "" -#: web/flaskr/templates/footer/cgu.html:27 +#: web/b3desk/templates/footer/cgu.html:27 msgid "" "L’éditeur donne accès au service interministériel de webconférence aux " "adresses suivantes : (\n" "56 rue de Varenne
    \n" "75007 Paris" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:95 +#: web/b3desk/templates/footer/donnees_personnelles.html:95 msgid "" "Si vous estimez, après nous avoir contactés, que vos droits Informatiques" " et Libertés ne sont pas respectés vous pouvez adresser une réclamation à" " la CNIL :" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:96 +#: web/b3desk/templates/footer/donnees_personnelles.html:96 msgid "" "Commission nationale informatique et libertés
    \n" "3 place de Fontenoy – TSA 80715 –
    \n" "75334 PARIS CEDEX 07" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:100 +#: web/b3desk/templates/footer/donnees_personnelles.html:100 msgid "" "Les modalités de réclamation sont précisées sur le site de la CNIL : " "www.cnil.fr." msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:102 +#: web/b3desk/templates/footer/donnees_personnelles.html:102 msgid "" "Contactez le Délégué à la protection des données pour les services " "Écoles/Colléges/Lycées/Agents" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:103 +#: web/b3desk/templates/footer/donnees_personnelles.html:103 msgid "" "Pour ce faire, envoyez un courriel à " "dpd[chez]education.gouv.fr" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:11 +#: web/b3desk/templates/footer/mentions_legales.html:11 msgid "Éditeur" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:12 +#: web/b3desk/templates/footer/mentions_legales.html:12 msgid "" "Ministère de l’Éducation nationale et de la jeunesse Direction du " "numérique pour l’éducation 110 rue Grenelle, 75007 Paris" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:12 +#: web/b3desk/templates/footer/mentions_legales.html:12 msgid "Directeur de publication" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:13 +#: web/b3desk/templates/footer/mentions_legales.html:13 msgid "Directeur de la publication" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:14 +#: web/b3desk/templates/footer/mentions_legales.html:14 msgid "M. Audran Le Baron, Directeur du numérique pour l’éducation" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:15 +#: web/b3desk/templates/footer/mentions_legales.html:15 msgid "Gestionnaire des statistiques" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:16 +#: web/b3desk/templates/footer/mentions_legales.html:16 msgid "Il n’y a pas d’outil de mesure d’audience pour ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:17 +#: web/b3desk/templates/footer/mentions_legales.html:17 msgid "Conception et gestion du site" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:18 +#: web/b3desk/templates/footer/mentions_legales.html:18 msgid "" "Le suivi éditorial, graphique et technique du site est assuré au " "quotidien par les équipes de la DINUM et du Pôle de compétence Identité " "du MENJS." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:19 +#: web/b3desk/templates/footer/mentions_legales.html:19 msgid "Droits de reproduction" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:20 +#: web/b3desk/templates/footer/mentions_legales.html:20 msgid "" "Conformément au droit public de la propriété intellectuelle et notamment " "selon l’article L122-5 du Code de la propriété intellectuelle, les " "’’documents officiels’’ sont librement réutilisables." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:21 +#: web/b3desk/templates/footer/mentions_legales.html:21 msgid "" "Cependant, le bon usage veut que la reprise de ces contenus de façon " "partielle ou intégrale mentionne clairement la source, et le cas échéant " "avec un lien vers le document original en ligne sur ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:22 +#: web/b3desk/templates/footer/mentions_legales.html:22 msgid "" "Toutes les infographies et vidéos réalisées par le service de " "communication de l’éditeur se trouvent sous « Licence Ouverte V2.0 » et " "sont librement réutilisables sous les conditions suivantes :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:23 +#: web/b3desk/templates/footer/mentions_legales.html:23 msgid "" "Attribution : vous devez attribuer l’œuvre de la manière indiquée par " "l’auteur de l’œuvre ou le titulaire des droits (mais pas d’une manière " @@ -1468,32 +1468,32 @@ msgid "" "l’œuvre)." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:24 +#: web/b3desk/templates/footer/mentions_legales.html:24 msgid "Liens hypertextes pointant vers ce site :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:25 +#: web/b3desk/templates/footer/mentions_legales.html:25 msgid "" "Tout site public ou privé est autorisé à établir, sans autorisation " "préalable, un lien (y compris profond) vers les informations diffusées " "par ce site de webinaire, Visio-ecoles/colleges/lycees/agents." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:26 +#: web/b3desk/templates/footer/mentions_legales.html:26 msgid "" "Pour les sites Internet, la reproduction, après autorisation, d’un " "contenu doit mentionner très clairement l’origine du document sous forme " "d’une adresse internet :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:27 +#: web/b3desk/templates/footer/mentions_legales.html:27 msgid "" "La mise en place de “liens profonds” pointant directement sur le document" " souhaité devra être privilégiée par rapport à la reproduction de " "contenus." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:28 +#: web/b3desk/templates/footer/mentions_legales.html:28 msgid "" "En effet, dans ce cas, la mise en place de liens vers ce site de " "Webinaire/Visio-ecoles/colleges/lycees/agents n’est conditionnée à aucun " @@ -1501,20 +1501,20 @@ msgid "" "du lien est recommandée." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:29 +#: web/b3desk/templates/footer/mentions_legales.html:29 msgid "" "Les sites qui font le choix de pointer vers ce site de Webinaire, Visio-" "ecoles/colleges/lycees/agents engagent leur responsabilité dès lors " "qu’ils porteraient atteinte à l’image du site public." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:30 +#: web/b3desk/templates/footer/mentions_legales.html:30 msgid "" "Liens hypertextes proposés par ce site de Webinaire, Visio-" "ecoles/colleges/lycees/agents :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:31 +#: web/b3desk/templates/footer/mentions_legales.html:31 msgid "" "Les liens vers chaque service interministériel référencé dans le " "catalogue que proposé par de ce site. Leur présence engage l’éditeur et " @@ -1524,43 +1524,43 @@ msgid "" "disposition au plan interministériel." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:32 +#: web/b3desk/templates/footer/mentions_legales.html:32 msgid "Clause de responsabilité" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:33 +#: web/b3desk/templates/footer/mentions_legales.html:33 msgid "" "Les informations proposées sur ce site le sont à titre de service rendu " "aux agents du service public, notamment aux agents des services de " "l’État." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:34 +#: web/b3desk/templates/footer/mentions_legales.html:34 msgid "" "Les informations et/ou documents disponibles sur ce site sont " "susceptibles d’être modifiés à tout moment, et peuvent faire l’objet de " "mises à jour pour faciliter l’accès aux ressources numériques." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:35 +#: web/b3desk/templates/footer/mentions_legales.html:35 msgid "" "Les informations et/ou documents accédés à partir de ce site relèvent de " "la responsabilité des porteurs de chaque service interministériel ainsi " "mis à disposition." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:36 +#: web/b3desk/templates/footer/mentions_legales.html:36 msgid "" "L’éditeur ne pourra en aucun cas être tenue responsable de tout dommage " "de quelque nature qu’il soit résultant de la mauvaise utilisation des " "ressources accessibles à partir de ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:37 +#: web/b3desk/templates/footer/mentions_legales.html:37 msgid "Droit à la compensation" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:38 +#: web/b3desk/templates/footer/mentions_legales.html:38 msgid "" "Dans l’attente d’une mise en conformité totale d’un de ces services, vous" " pouvez obtenir une version accessible des documents ou des informations " @@ -1570,69 +1570,69 @@ msgid "" "demandées vous seront transmises dans les plus brefs délais." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:40 +#: web/b3desk/templates/footer/mentions_legales.html:40 msgid "" "Vous pouvez nous aider à améliorer l’accessibilité du site en nous " "signalant les problèmes éventuels que vous rencontrez. Pour ce faire, " "envoyez-nous un courriel à apps[chez]education.gouv.fr" msgstr "" -#: web/flaskr/templates/meeting/form.html:36 +#: web/b3desk/templates/meeting/form.html:36 msgid "Modifier" msgstr "" -#: web/flaskr/templates/meeting/form.html:38 -#: web/flaskr/templates/meeting/submit.html:5 +#: web/b3desk/templates/meeting/form.html:38 +#: web/b3desk/templates/meeting/submit.html:5 msgid "Créer" msgstr "" -#: web/flaskr/templates/meeting/form.html:43 +#: web/b3desk/templates/meeting/form.html:43 msgid "Enregistrement impossible car certains champs sont mal renseignés." msgstr "" -#: web/flaskr/templates/meeting/form.html:51 +#: web/b3desk/templates/meeting/form.html:51 msgid "Configuration" msgstr "" -#: web/flaskr/templates/meeting/form.html:67 +#: web/b3desk/templates/meeting/form.html:67 msgid "" "Gestion des permissions, elles peuvent être ajustées une fois dans le " "salon" msgstr "" -#: web/flaskr/templates/meeting/form.html:84 +#: web/b3desk/templates/meeting/form.html:84 msgid "Personnalisation" msgstr "" -#: web/flaskr/templates/meeting/form.html:99 +#: web/b3desk/templates/meeting/form.html:99 msgid "Enregistrement" msgstr "Recording" -#: web/flaskr/templates/meeting/jumbotron.html:3 +#: web/b3desk/templates/meeting/jumbotron.html:3 msgid "Webinaire" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:5 +#: web/b3desk/templates/meeting/jumbotron.html:5 msgid "Nouveau webinaire" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:8 +#: web/b3desk/templates/meeting/jumbotron.html:8 msgid "Retour au tableau de bord" msgstr "" -#: web/flaskr/templates/meeting/list.html:2 +#: web/b3desk/templates/meeting/list.html:2 #, python-format msgid "Mes salles de %(some_meetings)s" msgstr "" -#: web/flaskr/templates/meeting/list.html:4 +#: web/b3desk/templates/meeting/list.html:4 #, python-format msgid "" "Créer une salle de %(meeting_label)s
    vous permet de conserver les " "réglages et le lien de la salle." msgstr "" -#: web/flaskr/templates/meeting/list.html:9 +#: web/b3desk/templates/meeting/list.html:9 #, python-format msgid "" "Vous avez atteint la limite des %(max_meetings_per_user)s " @@ -1640,22 +1640,22 @@ msgid "" "des %(meeting_label)ss inactives." msgstr "" -#: web/flaskr/templates/meeting/modals.html:75 +#: web/b3desk/templates/meeting/modals.html:75 #, python-format msgid "" "%(the_meeting)s est toujours en cours. Si un enregistrement est en cours," " il ne sera encodé qu'après la fin %(of_the_meeting)s." msgstr "" -#: web/flaskr/templates/meeting/modals.html:77 -#: web/flaskr/templates/meeting/recordings.html:22 +#: web/b3desk/templates/meeting/modals.html:77 +#: web/b3desk/templates/meeting/recordings.html:22 #, python-format msgid "" "Après la fin d'%(a_meeting)s, l'encodage de l'enregistrement peut prendre" " autant de temps que la durée %(of_the_meeting)s." msgstr "" -#: web/flaskr/templates/meeting/modals.html:78 +#: web/b3desk/templates/meeting/modals.html:78 #, python-format msgid "" "Si aucun modérateur ne met fin %(to_the_meeting)s, un délai " @@ -1663,54 +1663,54 @@ msgid "" "utilisateurs l'aient quitté." msgstr "" -#: web/flaskr/templates/meeting/modals.html:84 +#: web/b3desk/templates/meeting/modals.html:84 msgid "Images" msgstr "" -#: web/flaskr/templates/meeting/modals.html:85 +#: web/b3desk/templates/meeting/modals.html:85 msgid "Lien" msgstr "" -#: web/flaskr/templates/meeting/modals.html:105 -#: web/flaskr/templates/meeting/modals.html:106 -#: web/flaskr/templates/meeting/recordings.html:71 -#: web/flaskr/templates/meeting/recordings.html:72 +#: web/b3desk/templates/meeting/modals.html:105 +#: web/b3desk/templates/meeting/modals.html:106 +#: web/b3desk/templates/meeting/recordings.html:71 +#: web/b3desk/templates/meeting/recordings.html:72 #, python-format msgid "Supprimer video de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/modals.html:108 -#: web/flaskr/templates/meeting/recordings.html:74 +#: web/b3desk/templates/meeting/modals.html:108 +#: web/b3desk/templates/meeting/recordings.html:74 msgid "Suppression d'enregistrement" msgstr "" -#: web/flaskr/templates/meeting/modals.html:111 +#: web/b3desk/templates/meeting/modals.html:111 msgid "Copier le lien de l'enregistrement dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:11 +#: web/b3desk/templates/meeting/recordings.html:11 #, python-format msgid "Enregistrements de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:13 +#: web/b3desk/templates/meeting/recordings.html:13 #, python-format msgid "Retour à mes %(meeting_label)ss" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:18 +#: web/b3desk/templates/meeting/recordings.html:18 #, python-format msgid "%(this_meeting)s est toujours en cours" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:19 +#: web/b3desk/templates/meeting/recordings.html:19 #, python-format msgid "" "Si un enregistrement est en cours, il ne sera encodé qu'après la fin " "%(of_the_meeting)s" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:23 +#: web/b3desk/templates/meeting/recordings.html:23 #, python-format msgid "" "Si aucun modérateur ne met fin %(of_the_meeting)s, un délai " @@ -1718,199 +1718,199 @@ msgid "" "utilisateurs l'aient quitté." msgstr "" -#: web/flaskr/templates/meeting/recordings.html:42 +#: web/b3desk/templates/meeting/recordings.html:42 msgid "Visuels" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:43 +#: web/b3desk/templates/meeting/recordings.html:43 msgid "Actions" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:76 -#: web/flaskr/templates/meeting/row.html:29 -#: web/flaskr/templates/meeting/row.html:40 -#: web/flaskr/templates/meeting/row.html:59 +#: web/b3desk/templates/meeting/recordings.html:76 +#: web/b3desk/templates/meeting/row.html:29 +#: web/b3desk/templates/meeting/row.html:40 +#: web/b3desk/templates/meeting/row.html:59 msgid "Fermer la fenêtre modale" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:91 +#: web/b3desk/templates/meeting/recordings.html:91 msgid "Supprimer" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:92 -#: web/flaskr/templates/meeting/submit.html:7 +#: web/b3desk/templates/meeting/recordings.html:92 +#: web/b3desk/templates/meeting/submit.html:7 msgid "Annuler" msgstr "" -#: web/flaskr/templates/meeting/row.html:5 -#: web/flaskr/templates/meeting/row.html:33 +#: web/b3desk/templates/meeting/row.html:5 +#: web/b3desk/templates/meeting/row.html:33 #, python-format msgid "Lancer %(meeting_name)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/meeting/row.html:7 +#: web/b3desk/templates/meeting/row.html:7 msgid "Envoyer un courriel aux modérateurs" msgstr "" -#: web/flaskr/templates/meeting/row.html:9 +#: web/b3desk/templates/meeting/row.html:9 msgid "Copier le lien Modérateur dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/row.html:13 +#: web/b3desk/templates/meeting/row.html:13 #, python-format msgid "Participer à %(meeting_name)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/meeting/row.html:15 +#: web/b3desk/templates/meeting/row.html:15 msgid "Envoyer un courriel aux participants" msgstr "" -#: web/flaskr/templates/meeting/row.html:17 +#: web/b3desk/templates/meeting/row.html:17 msgid "Copier le lien Participant dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/row.html:20 -#: web/flaskr/templates/meeting/row.html:50 +#: web/b3desk/templates/meeting/row.html:20 +#: web/b3desk/templates/meeting/row.html:50 #, python-format msgid "Modifier %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:24 -#: web/flaskr/templates/meeting/row.html:25 -#: web/flaskr/templates/meeting/row.html:27 -#: web/flaskr/templates/meeting/row.html:54 -#: web/flaskr/templates/meeting/row.html:55 -#: web/flaskr/templates/meeting/row.html:57 +#: web/b3desk/templates/meeting/row.html:24 +#: web/b3desk/templates/meeting/row.html:25 +#: web/b3desk/templates/meeting/row.html:27 +#: web/b3desk/templates/meeting/row.html:54 +#: web/b3desk/templates/meeting/row.html:55 +#: web/b3desk/templates/meeting/row.html:57 #, python-format msgid "Supprimer %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:33 +#: web/b3desk/templates/meeting/row.html:33 msgid "Lancer" msgstr "" -#: web/flaskr/templates/meeting/row.html:36 -#: web/flaskr/templates/meeting/row.html:38 +#: web/b3desk/templates/meeting/row.html:36 +#: web/b3desk/templates/meeting/row.html:38 #, python-format msgid "Inviter à %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:41 +#: web/b3desk/templates/meeting/row.html:41 msgid "Inviter" msgstr "" -#: web/flaskr/templates/meeting/row.html:46 +#: web/b3desk/templates/meeting/row.html:46 #, python-format msgid "Voir les enregistrements de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:1 -#: web/flaskr/templates/meeting/signinmail.html:1 +#: web/b3desk/templates/meeting/signin.html:1 +#: web/b3desk/templates/meeting/signinmail.html:1 #, python-format msgid "Rejoindre %(the_meeting)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:16 +#: web/b3desk/templates/meeting/signin.html:16 #, python-format msgid "%(meeting_attente)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:24 -#: web/flaskr/templates/meeting/signinmail.html:16 +#: web/b3desk/templates/meeting/signin.html:24 +#: web/b3desk/templates/meeting/signinmail.html:16 msgid "Votre nom" msgstr "" -#: web/flaskr/templates/meeting/signin.html:25 -#: web/flaskr/templates/meeting/signinmail.html:17 +#: web/b3desk/templates/meeting/signin.html:25 +#: web/b3desk/templates/meeting/signinmail.html:17 msgid "Vous pouvez également préciser votre service ou votre fonction." msgstr "" -#: web/flaskr/templates/meeting/signin.html:44 -#: web/flaskr/templates/meeting/signinmail.html:23 +#: web/b3desk/templates/meeting/signin.html:44 +#: web/b3desk/templates/meeting/signinmail.html:23 msgid "Rejoindre" msgstr "" -#: web/flaskr/templates/meeting/signinmail.html:10 +#: web/b3desk/templates/meeting/signinmail.html:10 #, python-format msgid "Votre %(meeting_label)s n'a pas encore été activée par un modérateur" msgstr "" -#: web/flaskr/templates/meeting/submit.html:3 +#: web/b3desk/templates/meeting/submit.html:3 msgid "Enregistrer" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:4 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:4 msgid "Modérateur" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:6 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:6 msgid "Participant" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:9 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:9 #, python-format msgid "À %(the_meeting)s suivante :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:13 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:13 msgid "Le lien pour s'y inscrire est le suivant :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:21 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:21 #, python-format msgid "Le mot de passe de %(this_meeting)s est :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:29 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:29 msgid "Vous devez rentrer votre nom complet et le mot de passe pour y accéder." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:2 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:2 msgid "Bonjour," msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:5 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:5 #, python-format msgid "" "Vous avez demandé l’organisation d’%(a_quick_meeting)s au travers du " "webinaire de l’Etat." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:8 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:8 msgid "" "Le lien du webinaire que vous trouvez ci-dessous reste actif et " "accessible pendant une semaine depuis un navigateur internet sur un " "ordinateur ou un smartphone :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:11 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:11 #, python-format msgid "" "%(moderator_mail_signin_url)s" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:14 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:14 msgid "" "Vous pouvez dès à présent transmettre ce lien de connexion aux " "participants que vous souhaitez inviter." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:17 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:17 msgid "" "Une fois sur la page d’accueil, vous êtes invité à rentrer votre nom " "complet pour accéder au webinaire." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:20 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:20 msgid "Vous y êtes !" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:23 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:23 msgid "L’équipe du webinaire de l’Etat vous souhaite un excellent séminaire." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:26 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:26 #, python-format msgid "" "Si vous organisez régulièrement des %(meeting_label)ss, nous vous " @@ -1919,7 +1919,7 @@ msgid "" "mesure." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_subject.txt:1 +#: web/b3desk/templates/meeting/mailto/mail_subject.txt:1 msgid "Invitation" msgstr "" @@ -1961,21 +1961,27 @@ msgstr "" #: web/instance/config.py:185 msgid "" -"Créez un cours immédiatement avec des réglages standards. Ce cours ne " -"sera pas enregistré dans votre liste de salons." +"Créez en un clic un cours aux réglages standards. " +"Il ne sera pas enregistré dans votre liste de salles." msgstr "" +"Create a meeting with standard settings in just one " +"click. It will not be saved in your room list." #: web/instance/config.py:188 msgid "" -"Créez une réunion immédiatement avec des réglages standards. Cette " -"réunion ne sera pas enregistrée dans votre liste de salons." +"Créez en un clic une réunion aux réglages standards. " +"Elle ne sera pas enregistrée dans votre liste de salles." msgstr "" +"Create a course with standard settings in just one " +"click. It will not be saved in your room list." #: web/instance/config.py:191 msgid "" -"Créez un séminaire immédiatement avec des réglages standards. Ce " -"séminaire ne sera pas enregistré dans votre liste de salons." +"Créez en un clic un séminaire aux réglages standards. " +"Il ne sera pas enregistré dans votre liste de salles." msgstr "" +"Create a seminar with standard settings in just one " +"click. It will not be saved in your room list." #: web/instance/config.py:196 msgid "Invitation à un cours en ligne immédiat du Webinaire de l’Etat" diff --git a/web/translations/fr/LC_MESSAGES/messages.po b/web/translations/fr/LC_MESSAGES/messages.po index 3e63b734..5d0c0f26 100644 --- a/web/translations/fr/LC_MESSAGES/messages.po +++ b/web/translations/fr/LC_MESSAGES/messages.po @@ -18,60 +18,60 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.8.0\n" -#: web/flaskr/forms.py:56 +#: web/b3desk/forms.py:56 #, python-format msgid "Titre %(of_the_meeting)s" msgstr "" -#: web/flaskr/forms.py:60 +#: web/b3desk/forms.py:60 #, python-format msgid "Créer %(a_meeting)s dont le titre est :" msgstr "" -#: web/flaskr/forms.py:66 +#: web/b3desk/forms.py:66 #, python-format msgid "%(my_meeting)s" msgstr "" -#: web/flaskr/forms.py:71 +#: web/b3desk/forms.py:71 msgid "Texte de bienvenue" msgstr "" -#: web/flaskr/forms.py:72 +#: web/b3desk/forms.py:72 msgid "Ce texte apparait comme message de bienvenue sur le tchat public" msgstr "" -#: web/flaskr/forms.py:75 +#: web/b3desk/forms.py:75 #, python-format msgid "Bienvenue dans %(this_meeting)s %(meeting_name)s." msgstr "" -#: web/flaskr/forms.py:81 +#: web/b3desk/forms.py:81 msgid "Le texte est trop long" msgstr "" -#: web/flaskr/forms.py:85 +#: web/b3desk/forms.py:85 msgid "Nombre maximal de participants" msgstr "" -#: web/flaskr/forms.py:86 +#: web/b3desk/forms.py:86 msgid "Limitez vos salons à 250 personnes pour plus de confort" msgstr "" -#: web/flaskr/forms.py:92 +#: web/b3desk/forms.py:92 msgid "Durée maximale en minutes" msgstr "" -#: web/flaskr/forms.py:93 +#: web/b3desk/forms.py:93 #, python-format msgid "Après laquelle %(the_meeting)s stoppe automatiquement" msgstr "" -#: web/flaskr/forms.py:101 +#: web/b3desk/forms.py:101 msgid "Salle d'attente" msgstr "" -#: web/flaskr/forms.py:102 +#: web/b3desk/forms.py:102 #, python-format msgid "" "Placer les participants dans une salle d'attente lorsqu'ils rejoignent " @@ -79,203 +79,203 @@ msgid "" "individuellement." msgstr "" -#: web/flaskr/forms.py:109 +#: web/b3desk/forms.py:109 msgid "Seul les modérateurs peuvent voir les webcams des autres participants" msgstr "" -#: web/flaskr/forms.py:112 +#: web/b3desk/forms.py:112 msgid "Les participants ne verront pas la diffusion de la caméra des autres" msgstr "" -#: web/flaskr/forms.py:118 +#: web/b3desk/forms.py:118 msgid "Micros fermés au démarrage" msgstr "" -#: web/flaskr/forms.py:119 +#: web/b3desk/forms.py:119 msgid "Les micros sont clos à la connexion des utilisateurs" msgstr "" -#: web/flaskr/forms.py:125 +#: web/b3desk/forms.py:125 msgid "Verrouillage caméra" msgstr "" -#: web/flaskr/forms.py:126 +#: web/b3desk/forms.py:126 msgid "Les participants ne pourront pas activer leur caméra" msgstr "" -#: web/flaskr/forms.py:132 +#: web/b3desk/forms.py:132 msgid "Verrouillage micro" msgstr "" -#: web/flaskr/forms.py:133 +#: web/b3desk/forms.py:133 msgid "Les participants ne pourront pas activer leur micro" msgstr "" -#: web/flaskr/forms.py:137 +#: web/b3desk/forms.py:137 msgid "Désactivation de la discussion privée" msgstr "" -#: web/flaskr/forms.py:138 +#: web/b3desk/forms.py:138 msgid "Interdit les échanges textes directs entre participants" msgstr "" -#: web/flaskr/forms.py:144 +#: web/b3desk/forms.py:144 msgid "Désactivation de la discussion publique" msgstr "" -#: web/flaskr/forms.py:145 +#: web/b3desk/forms.py:145 msgid "Pas de tchat" msgstr "" -#: web/flaskr/forms.py:149 +#: web/b3desk/forms.py:149 msgid "Désactivation de la prise de notes" msgstr "" -#: web/flaskr/forms.py:150 +#: web/b3desk/forms.py:150 msgid "Pas de prise de notes collaborative" msgstr "" -#: web/flaskr/forms.py:154 +#: web/b3desk/forms.py:154 msgid "Message à l'attention des modérateurs" msgstr "" -#: web/flaskr/forms.py:155 +#: web/b3desk/forms.py:155 msgid "150 caractères max" msgstr "" -#: web/flaskr/forms.py:156 +#: web/b3desk/forms.py:156 msgid "Bienvenue aux modérateurs" msgstr "" -#: web/flaskr/forms.py:158 +#: web/b3desk/forms.py:158 msgid "Le message est trop long" msgstr "" -#: web/flaskr/forms.py:163 +#: web/b3desk/forms.py:163 #, python-format msgid "Url de redirection après %(the_meeting)s" msgstr "" -#: web/flaskr/forms.py:170 +#: web/b3desk/forms.py:170 msgid "Renouveler le lien modérateur" msgstr "" -#: web/flaskr/forms.py:171 web/flaskr/forms.py:180 +#: web/b3desk/forms.py:171 web/b3desk/forms.py:180 msgid "Ce code vous permet si vous le changez de bloquer les anciens liens" msgstr "" -#: web/flaskr/forms.py:179 +#: web/b3desk/forms.py:179 msgid "Renouveler le lien participants" msgstr "" -#: web/flaskr/forms.py:191 +#: web/b3desk/forms.py:191 msgid "Enregistrement manuel" msgstr "" -#: web/flaskr/forms.py:192 +#: web/b3desk/forms.py:192 msgid "Autoriser le démarrage et l'arrêt de l'enregistrement par le modérateur" msgstr "" -#: web/flaskr/forms.py:198 +#: web/b3desk/forms.py:198 msgid "Enregistrement automatique" msgstr "" -#: web/flaskr/forms.py:199 +#: web/b3desk/forms.py:199 msgid "Démarrage automatique" msgstr "" -#: web/flaskr/routes.py:548 +#: web/b3desk/routes.py:548 msgid "" "Courriel invalide. Avez vous bien tapé votre email ? Vous pouvez " "réessayer." msgstr "" -#: web/flaskr/routes.py:556 +#: web/b3desk/routes.py:556 msgid "" "Ce courriel ne correspond pas à un service de l'État. Si vous appartenez " "à un service de l'État mais votre courriel n'est pas reconnu par " "Webinaire, contactez-nous pour que nous le rajoutions!" msgstr "" -#: web/flaskr/routes.py:568 +#: web/b3desk/routes.py:568 msgid "Vous avez reçu un courriel pour vous connecter" msgstr "" -#: web/flaskr/routes.py:623 web/flaskr/routes.py:653 +#: web/b3desk/routes.py:623 web/b3desk/routes.py:653 msgid "Vous ne pouvez pas voir cet élément (identifiant incorrect)" msgstr "" -#: web/flaskr/routes.py:643 web/flaskr/routes.py:676 +#: web/b3desk/routes.py:643 web/b3desk/routes.py:676 msgid "Vous ne pouvez pas consulter cet élément" msgstr "" -#: web/flaskr/routes.py:805 +#: web/b3desk/routes.py:805 msgid "Vous ne pouvez pas modifier cet élément" msgstr "" -#: web/flaskr/routes.py:1264 +#: web/b3desk/routes.py:1264 #, python-format msgid "%(meeting_name)s modifications prises en compte" msgstr "" -#: web/flaskr/routes.py:1427 web/flaskr/routes.py:1474 +#: web/b3desk/routes.py:1427 web/b3desk/routes.py:1474 #, python-format msgid "Aucune %(meeting_label)s ne correspond à ces paramètres" msgstr "" -#: web/flaskr/routes.py:1437 web/flaskr/routes.py:1589 +#: web/b3desk/routes.py:1437 web/b3desk/routes.py:1589 msgid "Lien invalide" msgstr "" -#: web/flaskr/routes.py:1442 web/flaskr/routes.py:1594 +#: web/b3desk/routes.py:1442 web/b3desk/routes.py:1594 msgid "Lien expiré" msgstr "" -#: web/flaskr/routes.py:1581 +#: web/b3desk/routes.py:1581 #, python-format msgid "%(meeting_label)s inexistante" msgstr "" -#: web/flaskr/routes.py:1638 +#: web/b3desk/routes.py:1638 msgid "Accès non autorisé" msgstr "" -#: web/flaskr/routes.py:1669 +#: web/b3desk/routes.py:1669 msgid "Élément supprimé" msgstr "" -#: web/flaskr/routes.py:1671 +#: web/b3desk/routes.py:1671 msgid "Vous ne pouvez pas supprimer cet élément" msgstr "" -#: web/flaskr/routes.py:1687 +#: web/b3desk/routes.py:1687 msgid "Vidéo supprimée" msgstr "" -#: web/flaskr/routes.py:1691 +#: web/b3desk/routes.py:1691 #, python-format msgid "Nous n'avons pas pu supprimer cette vidéo : %(code)s, %(message)s" msgstr "" -#: web/flaskr/routes.py:1700 +#: web/b3desk/routes.py:1700 msgid "Vous ne pouvez pas supprimer cette enregistrement" msgstr "" -#: web/flaskr/templates/brand.html:19 +#: web/b3desk/templates/brand.html:19 #, python-format msgid "%(service_title)s" msgstr "" -#: web/flaskr/templates/brand.html:26 +#: web/b3desk/templates/brand.html:26 #, python-format msgid "%(service_tagline)s" msgstr "" -#: web/flaskr/templates/content.py:6 +#: web/b3desk/templates/content.py:6 msgid "Quelles sont les conditions d’accès pour accéder aux services ?" msgstr "" -#: web/flaskr/templates/content.py:9 +#: web/b3desk/templates/content.py:9 msgid "" "Cette plateforme offre une solution complète et puissante, adaptée à de " "nombreux types d’événements en ligne, jusqu’à 350 participants " @@ -312,11 +312,11 @@ msgid "" "- Sur Android, utiliser le navigateur Chrome par défaut (Android 6.0+)\n" msgstr "" -#: web/flaskr/templates/content.py:33 +#: web/b3desk/templates/content.py:33 msgid "Quel est le matériel nécessaire ?" msgstr "" -#: web/flaskr/templates/content.py:34 +#: web/b3desk/templates/content.py:34 msgid "" "Pour utiliser l’outil Webinaire de l’État, il vous suffit de disposer du " "matériel suivant :\n" @@ -338,11 +338,11 @@ msgid "" "contexte d’intervention." msgstr "" -#: web/flaskr/templates/content.py:46 +#: web/b3desk/templates/content.py:46 msgid "Puis-je utiliser mon smartphone ou ma tablette pour me connecter ?" msgstr "" -#: web/flaskr/templates/content.py:49 +#: web/b3desk/templates/content.py:49 msgid "" "Le Webinaire de l’Etat fonctionne également sur les appareils mobiles par" " un simple lien (sans application) sur le portail ou dans le séminaire. " @@ -350,11 +350,11 @@ msgid "" "Sur Android, utiliser le navigateur chrome par défaut (Android 6.0+).\n" msgstr "" -#: web/flaskr/templates/content.py:55 +#: web/b3desk/templates/content.py:55 msgid "Comment créer un séminaire ?" msgstr "" -#: web/flaskr/templates/content.py:56 +#: web/b3desk/templates/content.py:56 msgid "" "Si vous êtes un agent de l’état, vous pouvez :\n" "- Créer des séminaires immédiatement en renseignant votre courriel " @@ -370,11 +370,11 @@ msgid "" "contact@webinaire.numerique.gouv.fr \n" msgstr "" -#: web/flaskr/templates/content.py:67 +#: web/b3desk/templates/content.py:67 msgid "Comment créer un compte ?" msgstr "" -#: web/flaskr/templates/content.py:68 +#: web/b3desk/templates/content.py:68 msgid "" "En tant qu’agent de l’État, si vous organisez régulièrement des " "séminaires vous pouvez créer un compte pour organiser et conserver " @@ -387,11 +387,11 @@ msgid "" "en grand nombre, …etc.)." msgstr "" -#: web/flaskr/templates/content.py:75 +#: web/b3desk/templates/content.py:75 msgid "Comment inviter les participants/ modérateurs" msgstr "" -#: web/flaskr/templates/content.py:76 +#: web/b3desk/templates/content.py:76 msgid "" "L’organisateur qui a créé le séminaire peut partager le lien :\n" "« Participants » qu’ils soient de l’administration ou de l’extérieur " @@ -399,11 +399,11 @@ msgid "" "« Organisateurs/modérateurs » qui géreront avec vous le séminaire." msgstr "" -#: web/flaskr/templates/content.py:83 +#: web/b3desk/templates/content.py:83 msgid "Rejoindre un Webinaire en appel téléphonique ?" msgstr "" -#: web/flaskr/templates/content.py:84 +#: web/b3desk/templates/content.py:84 msgid "" "Une fois dans le séminaire, il est possible d’utiliser aussi son " "téléphone fixe ou mobile pour suivre le séminaire.\n" @@ -418,11 +418,11 @@ msgid "" "téléphone afin d’activer ou de désactiver votre microphone." msgstr "" -#: web/flaskr/templates/content.py:95 +#: web/b3desk/templates/content.py:95 msgid "J'ai des perturbations audio ou vidéo ?" msgstr "" -#: web/flaskr/templates/content.py:96 +#: web/b3desk/templates/content.py:96 msgid "" "\n" "Pour l’audio, rapprochez-vous de votre borne wifi, ou/et coupez votre " @@ -443,225 +443,225 @@ msgid "" "de vous connecter hors VPN.\n" msgstr "" -#: web/flaskr/templates/content.py:110 +#: web/b3desk/templates/content.py:110 msgid "Besoin de contacter l'équipe du Webinaire de l’Etat ?" msgstr "" -#: web/flaskr/templates/content.py:113 +#: web/b3desk/templates/content.py:113 msgid "contact@webinaire.numerique.gouv.fr" msgstr "" -#: web/flaskr/templates/content.py:116 +#: web/b3desk/templates/content.py:116 msgid "Besoin de contacter l'équipe du ministére de l'Éducation nationale ?" msgstr "" -#: web/flaskr/templates/content.py:119 +#: web/b3desk/templates/content.py:119 msgid "" "Rendez-vous sur votre portail d'assistance académique " "https://www.education.gouv.fr/la-messagerie-professionnelle-3446 ou sur " "Apps.education.fr" msgstr "" -#: web/flaskr/templates/empty.html:2 +#: web/b3desk/templates/empty.html:2 msgid "Vous devez vous identifier pour consulter la liste des visioconférences." msgstr "" -#: web/flaskr/templates/faq.html:8 +#: web/b3desk/templates/faq.html:8 msgid "FAQ - Modalités d'accès" msgstr "" -#: web/flaskr/templates/footer.html:12 +#: web/b3desk/templates/footer.html:12 msgid "" "Service proposé par la Direction interministérielle du numérique et la " "Direction du numérique pour l'éducation" msgstr "" -#: web/flaskr/templates/footer.html:15 +#: web/b3desk/templates/footer.html:15 msgid "Le code source est ouvert et les contributions sont bienvenues." msgstr "" -#: web/flaskr/templates/footer.html:16 +#: web/b3desk/templates/footer.html:16 msgid "Voir le code source - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/footer.html:16 +#: web/b3desk/templates/footer.html:16 msgid "Voir le code source" msgstr "" -#: web/flaskr/templates/footer.html:37 +#: web/b3desk/templates/footer.html:37 msgid "Accessibilité : non conforme" msgstr "" -#: web/flaskr/templates/footer.html:40 -#: web/flaskr/templates/footer/mentions_legales.html:10 +#: web/b3desk/templates/footer.html:40 +#: web/b3desk/templates/footer/mentions_legales.html:10 msgid "Mentions légales" msgstr "" -#: web/flaskr/templates/footer.html:43 +#: web/b3desk/templates/footer.html:43 msgid "Données personnelles et cookies" msgstr "" -#: web/flaskr/templates/footer.html:46 web/flaskr/templates/footer/cgu.html:10 +#: web/b3desk/templates/footer.html:46 web/b3desk/templates/footer/cgu.html:10 msgid "Conditions générales d’utilisation" msgstr "" -#: web/flaskr/templates/jumbotron.html:8 +#: web/b3desk/templates/jumbotron.html:8 #, python-format msgid "Lancer %(a_meeting)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:9 +#: web/b3desk/templates/jumbotron.html:9 #, python-format msgid "Lancer %(the_meeting)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/jumbotron.html:9 +#: web/b3desk/templates/jumbotron.html:9 #, python-format -msgid "Démarrer %(a_meeting)s immédiatement" +msgid "Ouvrir %(a_meeting)s temporaire" msgstr "" -#: web/flaskr/templates/jumbotron.html:19 -#: web/flaskr/templates/jumbotron.html:49 +#: web/b3desk/templates/jumbotron.html:19 +#: web/b3desk/templates/jumbotron.html:49 #, python-format msgid "Actuellement, il y a %(count)s webinaire" msgid_plural "Actuellement, il y a %(count)s webinaires" msgstr[0] "" msgstr[1] "" -#: web/flaskr/templates/jumbotron.html:24 -#: web/flaskr/templates/jumbotron.html:54 +#: web/b3desk/templates/jumbotron.html:24 +#: web/b3desk/templates/jumbotron.html:54 #, python-format msgid "et %(count)s participant" msgid_plural "et %(count)s participants" msgstr[0] "" msgstr[1] "" -#: web/flaskr/templates/jumbotron.html:29 -#: web/flaskr/templates/jumbotron.html:59 +#: web/b3desk/templates/jumbotron.html:29 +#: web/b3desk/templates/jumbotron.html:59 #, python-format msgid "" " sur une capacité moyenne pour la plateforme de %(max_participants)s " "participants." msgstr "" -#: web/flaskr/templates/jumbotron.html:42 +#: web/b3desk/templates/jumbotron.html:42 #, python-format msgid "Vous organisez régulièrement des %(some_meetings)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:43 +#: web/b3desk/templates/jumbotron.html:43 #, python-format msgid "" "Vous êtes agent de l’État, créez un compte pour organiser et conserver " "vos %(some_meetings)s." msgstr "" -#: web/flaskr/templates/jumbotron.html:44 +#: web/b3desk/templates/jumbotron.html:44 msgid "Se connecter ou créer un compte" msgstr "" -#: web/flaskr/templates/jumbotron.html:73 +#: web/b3desk/templates/jumbotron.html:73 #, python-format msgid "Démarrer %(a_meeting)s en ligne immédiatement" msgstr "" -#: web/flaskr/templates/jumbotron.html:83 +#: web/b3desk/templates/jumbotron.html:83 #, python-format msgid "" "Recevez par courriel un lien organisateur %(of_the_meeting)s, actif une " "semaine, à envoyer aux participants." msgstr "" -#: web/flaskr/templates/jumbotron.html:88 +#: web/b3desk/templates/jumbotron.html:88 msgid "Votre courriel professionnel" msgstr "" -#: web/flaskr/templates/jumbotron.html:92 +#: web/b3desk/templates/jumbotron.html:92 #, python-format msgid "Créer %(my_meeting)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:108 +#: web/b3desk/templates/jumbotron.html:108 #, python-format msgid "Vous essayez de rejoindre %(a_meeting)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:109 +#: web/b3desk/templates/jumbotron.html:109 #, python-format msgid "" "Pour rejoindre %(a_meeting_to_which)s vous êtes invité, cliquez sur le " "lien que vous a transmis l'organisateur/modérateur." msgstr "" -#: web/flaskr/templates/redirections.html:4 +#: web/b3desk/templates/redirections.html:4 msgid "Connectez-vous ou créez un compte" msgstr "" -#: web/flaskr/templates/redirections.html:10 +#: web/b3desk/templates/redirections.html:10 msgid "Autres profils" msgstr "" -#: web/flaskr/templates/rie.html:3 +#: web/b3desk/templates/rie.html:3 msgid "Service accessible suivant les politiques de sécurité de votre ministère." msgstr "" -#: web/flaskr/templates/rie.html:4 +#: web/b3desk/templates/rie.html:4 msgid "" "Si l'audio ou la vidéo ne fonctionne pas, vous devez utiliser un autre " "appareil (ordinateur, smartphone)." msgstr "" -#: web/flaskr/templates/rie.html:5 +#: web/b3desk/templates/rie.html:5 msgid "en savoir plus" msgstr "" -#: web/flaskr/templates/tools.html:13 +#: web/b3desk/templates/tools.html:13 msgid "Modalités d'accès" msgstr "" -#: web/flaskr/templates/tools.html:32 +#: web/b3desk/templates/tools.html:32 msgid "se déconnecter" msgstr "" -#: web/flaskr/templates/tools.html:40 +#: web/b3desk/templates/tools.html:40 msgid "S’identifier" msgstr "" -#: web/flaskr/templates/errors/403.html:11 +#: web/b3desk/templates/errors/403.html:11 msgid "Erreur 403" msgstr "" -#: web/flaskr/templates/errors/403.html:12 +#: web/b3desk/templates/errors/403.html:12 msgid "" "Vous n’êtes pas autorisé à accéder cette page. Vous pouvez retourner à l’accueil." msgstr "" -#: web/flaskr/templates/errors/404.html:11 +#: web/b3desk/templates/errors/404.html:11 msgid "Erreur 404" msgstr "" -#: web/flaskr/templates/errors/404.html:12 +#: web/b3desk/templates/errors/404.html:12 msgid "" "Cette page n'existe pas. Vous pouvez retourner à " "l’accueil." msgstr "" -#: web/flaskr/templates/errors/500.html:11 +#: web/b3desk/templates/errors/500.html:11 msgid "Erreur 500" msgstr "" -#: web/flaskr/templates/errors/500.html:12 +#: web/b3desk/templates/errors/500.html:12 msgid "" "Le serveur a rencontré une erreur interne, veuillez réessayer " "ultérieurement." msgstr "" -#: web/flaskr/templates/footer/accessibilite.html:9 +#: web/b3desk/templates/footer/accessibilite.html:9 msgid "Accessibilité" msgstr "" -#: web/flaskr/templates/footer/accessibilite.html:10 +#: web/b3desk/templates/footer/accessibilite.html:10 msgid "" "Le site webinaire.numerique.gouv.fr est développé selon les " "recommendations du annuaire de l'administration" msgstr "" -#: web/flaskr/templates/footer/cgu.html:11 +#: web/b3desk/templates/footer/cgu.html:11 msgid "" "Le webinaire, Visio-ecoles/colleges/lycees/agents de l’État permet " "d’accéder à la page d’accueil du sous-domaine internet utilisé par l’Etat" @@ -742,7 +742,7 @@ msgid "" "les partenaires du service public." msgstr "" -#: web/flaskr/templates/footer/cgu.html:12 +#: web/b3desk/templates/footer/cgu.html:12 msgid "" "Le sous-domaine « https://visio-" @@ -764,25 +764,25 @@ msgid "" "Nationale, de la Jeunesse et des Sports." msgstr "" -#: web/flaskr/templates/footer/cgu.html:14 +#: web/b3desk/templates/footer/cgu.html:14 msgid "" "Le service est maintenu en conditions opérationnelles et ses évolutions " "sont assurées par le Ministère de l’Éducation Nationale, de la Jeunesse " "et des Sports, ci-après dénommé « l’éditeur »." msgstr "" -#: web/flaskr/templates/footer/cgu.html:15 +#: web/b3desk/templates/footer/cgu.html:15 msgid "" "Toute utilisation des ressources de domaine de publication est " "subordonnée au respect des présentes conditions générales d’utilisation " "(CGU)." msgstr "" -#: web/flaskr/templates/footer/cgu.html:17 +#: web/b3desk/templates/footer/cgu.html:17 msgid "Objet" msgstr "" -#: web/flaskr/templates/footer/cgu.html:18 +#: web/b3desk/templates/footer/cgu.html:18 msgid "" "Le sous-domaine permet de publier sur internet l’offre de service " "interministérielle de webconférence.

    " msgstr "" -#: web/flaskr/templates/footer/cgu.html:19 +#: web/b3desk/templates/footer/cgu.html:19 msgid "Code de conduite et responsabilités des Utilisateurs" msgstr "" -#: web/flaskr/templates/footer/cgu.html:20 +#: web/b3desk/templates/footer/cgu.html:20 msgid "" "L’utilisation de ce service interministériel est libre et gratuite pour " "les utilisateurs des services de l’Etat, et sur invitation, pour les " @@ -806,14 +806,14 @@ msgid "" "et responsabilités de l’éditeur." msgstr "" -#: web/flaskr/templates/footer/cgu.html:21 +#: web/b3desk/templates/footer/cgu.html:21 msgid "" "Sitôt entré sur la page d’accueil, l’utilisateur peut en consulter les " "contenus ou accéder à un salon en saisissant le nom de ce salon ou, pour " "les agents de l’Etat, en créant ledit salon." msgstr "" -#: web/flaskr/templates/footer/cgu.html:22 +#: web/b3desk/templates/footer/cgu.html:22 msgid "" "À l’instant où l’utilisateur accède à un salon de webconférence, il " "devient seul responsable des données et des contenus qu’il échange sur le" @@ -821,17 +821,17 @@ msgid "" "netiquette." msgstr "" -#: web/flaskr/templates/footer/cgu.html:23 +#: web/b3desk/templates/footer/cgu.html:23 msgid "Usage professionnel" msgstr "" -#: web/flaskr/templates/footer/cgu.html:24 +#: web/b3desk/templates/footer/cgu.html:24 msgid "" "Le service de Webinaire, Visio-ecoles/colleges/lycees/agents mis à " "disposition est à usage professionnel." msgstr "" -#: web/flaskr/templates/footer/cgu.html:25 +#: web/b3desk/templates/footer/cgu.html:25 msgid "" "Seule l’utilisation à usage professionnel de cette ressource mise à " "disposition est tolérée, l’utilisateur est attentif à ce que ces usages " @@ -839,11 +839,11 @@ msgid "" "service auquel il accède." msgstr "" -#: web/flaskr/templates/footer/cgu.html:26 +#: web/b3desk/templates/footer/cgu.html:26 msgid "Engagements et responsabilités de l’éditeur" msgstr "" -#: web/flaskr/templates/footer/cgu.html:27 +#: web/b3desk/templates/footer/cgu.html:27 msgid "" "L’éditeur donne accès au service interministériel de webconférence aux " "adresses suivantes : (\n" "56 rue de Varenne
    \n" "75007 Paris" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:95 +#: web/b3desk/templates/footer/donnees_personnelles.html:95 msgid "" "Si vous estimez, après nous avoir contactés, que vos droits Informatiques" " et Libertés ne sont pas respectés vous pouvez adresser une réclamation à" " la CNIL :" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:96 +#: web/b3desk/templates/footer/donnees_personnelles.html:96 msgid "" "Commission nationale informatique et libertés
    \n" "3 place de Fontenoy – TSA 80715 –
    \n" "75334 PARIS CEDEX 07" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:100 +#: web/b3desk/templates/footer/donnees_personnelles.html:100 msgid "" "Les modalités de réclamation sont précisées sur le site de la CNIL : " "www.cnil.fr." msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:102 +#: web/b3desk/templates/footer/donnees_personnelles.html:102 msgid "" "Contactez le Délégué à la protection des données pour les services " "Écoles/Colléges/Lycées/Agents" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:103 +#: web/b3desk/templates/footer/donnees_personnelles.html:103 msgid "" "Pour ce faire, envoyez un courriel à " "dpd[chez]education.gouv.fr" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:11 +#: web/b3desk/templates/footer/mentions_legales.html:11 msgid "Éditeur" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:12 +#: web/b3desk/templates/footer/mentions_legales.html:12 msgid "" "Ministère de l’Éducation nationale et de la jeunesse Direction du " "numérique pour l’éducation 110 rue Grenelle, 75007 Paris" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:12 +#: web/b3desk/templates/footer/mentions_legales.html:12 msgid "Directeur de publication" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:13 +#: web/b3desk/templates/footer/mentions_legales.html:13 msgid "Directeur de la publication" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:14 +#: web/b3desk/templates/footer/mentions_legales.html:14 msgid "M. Audran Le Baron, Directeur du numérique pour l’éducation" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:15 +#: web/b3desk/templates/footer/mentions_legales.html:15 msgid "Gestionnaire des statistiques" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:16 +#: web/b3desk/templates/footer/mentions_legales.html:16 msgid "Il n’y a pas d’outil de mesure d’audience pour ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:17 +#: web/b3desk/templates/footer/mentions_legales.html:17 msgid "Conception et gestion du site" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:18 +#: web/b3desk/templates/footer/mentions_legales.html:18 msgid "" "Le suivi éditorial, graphique et technique du site est assuré au " "quotidien par les équipes de la DINUM et du Pôle de compétence Identité " "du MENJS." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:19 +#: web/b3desk/templates/footer/mentions_legales.html:19 msgid "Droits de reproduction" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:20 +#: web/b3desk/templates/footer/mentions_legales.html:20 msgid "" "Conformément au droit public de la propriété intellectuelle et notamment " "selon l’article L122-5 du Code de la propriété intellectuelle, les " "’’documents officiels’’ sont librement réutilisables." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:21 +#: web/b3desk/templates/footer/mentions_legales.html:21 msgid "" "Cependant, le bon usage veut que la reprise de ces contenus de façon " "partielle ou intégrale mentionne clairement la source, et le cas échéant " "avec un lien vers le document original en ligne sur ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:22 +#: web/b3desk/templates/footer/mentions_legales.html:22 msgid "" "Toutes les infographies et vidéos réalisées par le service de " "communication de l’éditeur se trouvent sous « Licence Ouverte V2.0 » et " "sont librement réutilisables sous les conditions suivantes :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:23 +#: web/b3desk/templates/footer/mentions_legales.html:23 msgid "" "Attribution : vous devez attribuer l’œuvre de la manière indiquée par " "l’auteur de l’œuvre ou le titulaire des droits (mais pas d’une manière " @@ -1357,32 +1357,32 @@ msgid "" "l’œuvre)." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:24 +#: web/b3desk/templates/footer/mentions_legales.html:24 msgid "Liens hypertextes pointant vers ce site :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:25 +#: web/b3desk/templates/footer/mentions_legales.html:25 msgid "" "Tout site public ou privé est autorisé à établir, sans autorisation " "préalable, un lien (y compris profond) vers les informations diffusées " "par ce site de webinaire, Visio-ecoles/colleges/lycees/agents." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:26 +#: web/b3desk/templates/footer/mentions_legales.html:26 msgid "" "Pour les sites Internet, la reproduction, après autorisation, d’un " "contenu doit mentionner très clairement l’origine du document sous forme " "d’une adresse internet :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:27 +#: web/b3desk/templates/footer/mentions_legales.html:27 msgid "" "La mise en place de “liens profonds” pointant directement sur le document" " souhaité devra être privilégiée par rapport à la reproduction de " "contenus." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:28 +#: web/b3desk/templates/footer/mentions_legales.html:28 msgid "" "En effet, dans ce cas, la mise en place de liens vers ce site de " "Webinaire/Visio-ecoles/colleges/lycees/agents n’est conditionnée à aucun " @@ -1390,20 +1390,20 @@ msgid "" "du lien est recommandée." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:29 +#: web/b3desk/templates/footer/mentions_legales.html:29 msgid "" "Les sites qui font le choix de pointer vers ce site de Webinaire, Visio-" "ecoles/colleges/lycees/agents engagent leur responsabilité dès lors " "qu’ils porteraient atteinte à l’image du site public." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:30 +#: web/b3desk/templates/footer/mentions_legales.html:30 msgid "" "Liens hypertextes proposés par ce site de Webinaire, Visio-" "ecoles/colleges/lycees/agents :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:31 +#: web/b3desk/templates/footer/mentions_legales.html:31 msgid "" "Les liens vers chaque service interministériel référencé dans le " "catalogue que proposé par de ce site. Leur présence engage l’éditeur et " @@ -1413,43 +1413,43 @@ msgid "" "disposition au plan interministériel." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:32 +#: web/b3desk/templates/footer/mentions_legales.html:32 msgid "Clause de responsabilité" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:33 +#: web/b3desk/templates/footer/mentions_legales.html:33 msgid "" "Les informations proposées sur ce site le sont à titre de service rendu " "aux agents du service public, notamment aux agents des services de " "l’État." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:34 +#: web/b3desk/templates/footer/mentions_legales.html:34 msgid "" "Les informations et/ou documents disponibles sur ce site sont " "susceptibles d’être modifiés à tout moment, et peuvent faire l’objet de " "mises à jour pour faciliter l’accès aux ressources numériques." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:35 +#: web/b3desk/templates/footer/mentions_legales.html:35 msgid "" "Les informations et/ou documents accédés à partir de ce site relèvent de " "la responsabilité des porteurs de chaque service interministériel ainsi " "mis à disposition." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:36 +#: web/b3desk/templates/footer/mentions_legales.html:36 msgid "" "L’éditeur ne pourra en aucun cas être tenue responsable de tout dommage " "de quelque nature qu’il soit résultant de la mauvaise utilisation des " "ressources accessibles à partir de ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:37 +#: web/b3desk/templates/footer/mentions_legales.html:37 msgid "Droit à la compensation" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:38 +#: web/b3desk/templates/footer/mentions_legales.html:38 msgid "" "Dans l’attente d’une mise en conformité totale d’un de ces services, vous" " pouvez obtenir une version accessible des documents ou des informations " @@ -1459,69 +1459,69 @@ msgid "" "demandées vous seront transmises dans les plus brefs délais." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:40 +#: web/b3desk/templates/footer/mentions_legales.html:40 msgid "" "Vous pouvez nous aider à améliorer l’accessibilité du site en nous " "signalant les problèmes éventuels que vous rencontrez. Pour ce faire, " "envoyez-nous un courriel à apps[chez]education.gouv.fr" msgstr "" -#: web/flaskr/templates/meeting/form.html:36 +#: web/b3desk/templates/meeting/form.html:36 msgid "Modifier" msgstr "" -#: web/flaskr/templates/meeting/form.html:38 -#: web/flaskr/templates/meeting/submit.html:5 +#: web/b3desk/templates/meeting/form.html:38 +#: web/b3desk/templates/meeting/submit.html:5 msgid "Créer" msgstr "" -#: web/flaskr/templates/meeting/form.html:43 +#: web/b3desk/templates/meeting/form.html:43 msgid "Enregistrement impossible car certains champs sont mal renseignés." msgstr "" -#: web/flaskr/templates/meeting/form.html:51 +#: web/b3desk/templates/meeting/form.html:51 msgid "Configuration" msgstr "" -#: web/flaskr/templates/meeting/form.html:67 +#: web/b3desk/templates/meeting/form.html:67 msgid "" "Gestion des permissions, elles peuvent être ajustées une fois dans le " "salon" msgstr "" -#: web/flaskr/templates/meeting/form.html:84 +#: web/b3desk/templates/meeting/form.html:84 msgid "Personnalisation" msgstr "" -#: web/flaskr/templates/meeting/form.html:99 +#: web/b3desk/templates/meeting/form.html:99 msgid "Enregistrement" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:3 +#: web/b3desk/templates/meeting/jumbotron.html:3 msgid "Webinaire" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:5 +#: web/b3desk/templates/meeting/jumbotron.html:5 msgid "Nouveau webinaire" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:8 +#: web/b3desk/templates/meeting/jumbotron.html:8 msgid "Retour au tableau de bord" msgstr "" -#: web/flaskr/templates/meeting/list.html:2 +#: web/b3desk/templates/meeting/list.html:2 #, python-format msgid "Mes salles de %(some_meetings)s" msgstr "" -#: web/flaskr/templates/meeting/list.html:4 +#: web/b3desk/templates/meeting/list.html:4 #, python-format msgid "" "Créer une salle de %(meeting_label)s
    vous permet de conserver les " "réglages et le lien de la salle." msgstr "" -#: web/flaskr/templates/meeting/list.html:9 +#: web/b3desk/templates/meeting/list.html:9 #, python-format msgid "" "Vous avez atteint la limite des %(max_meetings_per_user)s " @@ -1529,22 +1529,22 @@ msgid "" "des %(meeting_label)ss inactives." msgstr "" -#: web/flaskr/templates/meeting/modals.html:75 +#: web/b3desk/templates/meeting/modals.html:75 #, python-format msgid "" "%(the_meeting)s est toujours en cours. Si un enregistrement est en cours," " il ne sera encodé qu'après la fin %(of_the_meeting)s." msgstr "" -#: web/flaskr/templates/meeting/modals.html:77 -#: web/flaskr/templates/meeting/recordings.html:22 +#: web/b3desk/templates/meeting/modals.html:77 +#: web/b3desk/templates/meeting/recordings.html:22 #, python-format msgid "" "Après la fin d'%(a_meeting)s, l'encodage de l'enregistrement peut prendre" " autant de temps que la durée %(of_the_meeting)s." msgstr "" -#: web/flaskr/templates/meeting/modals.html:78 +#: web/b3desk/templates/meeting/modals.html:78 #, python-format msgid "" "Si aucun modérateur ne met fin %(to_the_meeting)s, un délai " @@ -1552,54 +1552,54 @@ msgid "" "utilisateurs l'aient quitté." msgstr "" -#: web/flaskr/templates/meeting/modals.html:84 +#: web/b3desk/templates/meeting/modals.html:84 msgid "Images" msgstr "" -#: web/flaskr/templates/meeting/modals.html:85 +#: web/b3desk/templates/meeting/modals.html:85 msgid "Lien" msgstr "" -#: web/flaskr/templates/meeting/modals.html:105 -#: web/flaskr/templates/meeting/modals.html:106 -#: web/flaskr/templates/meeting/recordings.html:71 -#: web/flaskr/templates/meeting/recordings.html:72 +#: web/b3desk/templates/meeting/modals.html:105 +#: web/b3desk/templates/meeting/modals.html:106 +#: web/b3desk/templates/meeting/recordings.html:71 +#: web/b3desk/templates/meeting/recordings.html:72 #, python-format msgid "Supprimer video de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/modals.html:108 -#: web/flaskr/templates/meeting/recordings.html:74 +#: web/b3desk/templates/meeting/modals.html:108 +#: web/b3desk/templates/meeting/recordings.html:74 msgid "Suppression d'enregistrement" msgstr "" -#: web/flaskr/templates/meeting/modals.html:111 +#: web/b3desk/templates/meeting/modals.html:111 msgid "Copier le lien de l'enregistrement dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:11 +#: web/b3desk/templates/meeting/recordings.html:11 #, python-format msgid "Enregistrements de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:13 +#: web/b3desk/templates/meeting/recordings.html:13 #, python-format msgid "Retour à mes %(meeting_label)ss" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:18 +#: web/b3desk/templates/meeting/recordings.html:18 #, python-format msgid "%(this_meeting)s est toujours en cours" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:19 +#: web/b3desk/templates/meeting/recordings.html:19 #, python-format msgid "" "Si un enregistrement est en cours, il ne sera encodé qu'après la fin " "%(of_the_meeting)s" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:23 +#: web/b3desk/templates/meeting/recordings.html:23 #, python-format msgid "" "Si aucun modérateur ne met fin %(of_the_meeting)s, un délai " @@ -1607,199 +1607,199 @@ msgid "" "utilisateurs l'aient quitté." msgstr "" -#: web/flaskr/templates/meeting/recordings.html:42 +#: web/b3desk/templates/meeting/recordings.html:42 msgid "Visuels" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:43 +#: web/b3desk/templates/meeting/recordings.html:43 msgid "Actions" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:76 -#: web/flaskr/templates/meeting/row.html:29 -#: web/flaskr/templates/meeting/row.html:40 -#: web/flaskr/templates/meeting/row.html:59 +#: web/b3desk/templates/meeting/recordings.html:76 +#: web/b3desk/templates/meeting/row.html:29 +#: web/b3desk/templates/meeting/row.html:40 +#: web/b3desk/templates/meeting/row.html:59 msgid "Fermer la fenêtre modale" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:91 +#: web/b3desk/templates/meeting/recordings.html:91 msgid "Supprimer" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:92 -#: web/flaskr/templates/meeting/submit.html:7 +#: web/b3desk/templates/meeting/recordings.html:92 +#: web/b3desk/templates/meeting/submit.html:7 msgid "Annuler" msgstr "" -#: web/flaskr/templates/meeting/row.html:5 -#: web/flaskr/templates/meeting/row.html:33 +#: web/b3desk/templates/meeting/row.html:5 +#: web/b3desk/templates/meeting/row.html:33 #, python-format msgid "Lancer %(meeting_name)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/meeting/row.html:7 +#: web/b3desk/templates/meeting/row.html:7 msgid "Envoyer un courriel aux modérateurs" msgstr "" -#: web/flaskr/templates/meeting/row.html:9 +#: web/b3desk/templates/meeting/row.html:9 msgid "Copier le lien Modérateur dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/row.html:13 +#: web/b3desk/templates/meeting/row.html:13 #, python-format msgid "Participer à %(meeting_name)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/meeting/row.html:15 +#: web/b3desk/templates/meeting/row.html:15 msgid "Envoyer un courriel aux participants" msgstr "" -#: web/flaskr/templates/meeting/row.html:17 +#: web/b3desk/templates/meeting/row.html:17 msgid "Copier le lien Participant dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/row.html:20 -#: web/flaskr/templates/meeting/row.html:50 +#: web/b3desk/templates/meeting/row.html:20 +#: web/b3desk/templates/meeting/row.html:50 #, python-format msgid "Modifier %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:24 -#: web/flaskr/templates/meeting/row.html:25 -#: web/flaskr/templates/meeting/row.html:27 -#: web/flaskr/templates/meeting/row.html:54 -#: web/flaskr/templates/meeting/row.html:55 -#: web/flaskr/templates/meeting/row.html:57 +#: web/b3desk/templates/meeting/row.html:24 +#: web/b3desk/templates/meeting/row.html:25 +#: web/b3desk/templates/meeting/row.html:27 +#: web/b3desk/templates/meeting/row.html:54 +#: web/b3desk/templates/meeting/row.html:55 +#: web/b3desk/templates/meeting/row.html:57 #, python-format msgid "Supprimer %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:33 +#: web/b3desk/templates/meeting/row.html:33 msgid "Lancer" msgstr "" -#: web/flaskr/templates/meeting/row.html:36 -#: web/flaskr/templates/meeting/row.html:38 +#: web/b3desk/templates/meeting/row.html:36 +#: web/b3desk/templates/meeting/row.html:38 #, python-format msgid "Inviter à %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:41 +#: web/b3desk/templates/meeting/row.html:41 msgid "Inviter" msgstr "" -#: web/flaskr/templates/meeting/row.html:46 +#: web/b3desk/templates/meeting/row.html:46 #, python-format msgid "Voir les enregistrements de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:1 -#: web/flaskr/templates/meeting/signinmail.html:1 +#: web/b3desk/templates/meeting/signin.html:1 +#: web/b3desk/templates/meeting/signinmail.html:1 #, python-format msgid "Rejoindre %(the_meeting)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:16 +#: web/b3desk/templates/meeting/signin.html:16 #, python-format msgid "%(meeting_attente)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:24 -#: web/flaskr/templates/meeting/signinmail.html:16 +#: web/b3desk/templates/meeting/signin.html:24 +#: web/b3desk/templates/meeting/signinmail.html:16 msgid "Votre nom" msgstr "" -#: web/flaskr/templates/meeting/signin.html:25 -#: web/flaskr/templates/meeting/signinmail.html:17 +#: web/b3desk/templates/meeting/signin.html:25 +#: web/b3desk/templates/meeting/signinmail.html:17 msgid "Vous pouvez également préciser votre service ou votre fonction." msgstr "" -#: web/flaskr/templates/meeting/signin.html:44 -#: web/flaskr/templates/meeting/signinmail.html:23 +#: web/b3desk/templates/meeting/signin.html:44 +#: web/b3desk/templates/meeting/signinmail.html:23 msgid "Rejoindre" msgstr "" -#: web/flaskr/templates/meeting/signinmail.html:10 +#: web/b3desk/templates/meeting/signinmail.html:10 #, python-format msgid "Votre %(meeting_label)s n'a pas encore été activée par un modérateur" msgstr "" -#: web/flaskr/templates/meeting/submit.html:3 +#: web/b3desk/templates/meeting/submit.html:3 msgid "Enregistrer" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:4 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:4 msgid "Modérateur" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:6 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:6 msgid "Participant" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:9 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:9 #, python-format msgid "À %(the_meeting)s suivante :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:13 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:13 msgid "Le lien pour s'y inscrire est le suivant :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:21 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:21 #, python-format msgid "Le mot de passe de %(this_meeting)s est :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:29 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:29 msgid "Vous devez rentrer votre nom complet et le mot de passe pour y accéder." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:2 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:2 msgid "Bonjour," msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:5 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:5 #, python-format msgid "" "Vous avez demandé l’organisation d’%(a_quick_meeting)s au travers du " "webinaire de l’Etat." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:8 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:8 msgid "" "Le lien du webinaire que vous trouvez ci-dessous reste actif et " "accessible pendant une semaine depuis un navigateur internet sur un " "ordinateur ou un smartphone :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:11 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:11 #, python-format msgid "" "%(moderator_mail_signin_url)s" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:14 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:14 msgid "" "Vous pouvez dès à présent transmettre ce lien de connexion aux " "participants que vous souhaitez inviter." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:17 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:17 msgid "" "Une fois sur la page d’accueil, vous êtes invité à rentrer votre nom " "complet pour accéder au webinaire." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:20 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:20 msgid "Vous y êtes !" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:23 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:23 msgid "L’équipe du webinaire de l’Etat vous souhaite un excellent séminaire." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:26 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:26 #, python-format msgid "" "Si vous organisez régulièrement des %(meeting_label)ss, nous vous " @@ -1808,7 +1808,7 @@ msgid "" "mesure." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_subject.txt:1 +#: web/b3desk/templates/meeting/mailto/mail_subject.txt:1 msgid "Invitation" msgstr "" @@ -1850,20 +1850,20 @@ msgstr "" #: web/instance/config.py:185 msgid "" -"Créez un cours immédiatement avec des réglages standards. Ce cours ne " -"sera pas enregistré dans votre liste de salons." +"Créez en un clic un cours aux réglages standards. " +"Il ne sera pas enregistré dans votre liste de salles." msgstr "" #: web/instance/config.py:188 msgid "" -"Créez une réunion immédiatement avec des réglages standards. Cette " -"réunion ne sera pas enregistrée dans votre liste de salons." +"Créez en un clic une réunion aux réglages standards. " +"Elle ne sera pas enregistrée dans votre liste de salles." msgstr "" #: web/instance/config.py:191 msgid "" -"Créez un séminaire immédiatement avec des réglages standards. Ce " -"séminaire ne sera pas enregistré dans votre liste de salons." +"Créez en un clic un séminaire aux réglages standards. " +"Il ne sera pas enregistré dans votre liste de salles." msgstr "" #: web/instance/config.py:196 @@ -2333,4 +2333,3 @@ msgstr "" #~ " \n" #~ "« Organisateurs/modérateurs » qui géreront avec vous le séminaire." #~ msgstr "" - diff --git a/web/translations/messages.pot b/web/translations/messages.pot index 54fa5658..38f2d03d 100644 --- a/web/translations/messages.pot +++ b/web/translations/messages.pot @@ -17,60 +17,60 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.8.0\n" -#: web/flaskr/forms.py:56 +#: web/b3desk/forms.py:56 #, python-format msgid "Titre %(of_the_meeting)s" msgstr "" -#: web/flaskr/forms.py:60 +#: web/b3desk/forms.py:60 #, python-format msgid "Créer %(a_meeting)s dont le titre est :" msgstr "" -#: web/flaskr/forms.py:66 +#: web/b3desk/forms.py:66 #, python-format msgid "%(my_meeting)s" msgstr "" -#: web/flaskr/forms.py:71 +#: web/b3desk/forms.py:71 msgid "Texte de bienvenue" msgstr "" -#: web/flaskr/forms.py:72 +#: web/b3desk/forms.py:72 msgid "Ce texte apparait comme message de bienvenue sur le tchat public" msgstr "" -#: web/flaskr/forms.py:75 +#: web/b3desk/forms.py:75 #, python-format msgid "Bienvenue dans %(this_meeting)s %(meeting_name)s." msgstr "" -#: web/flaskr/forms.py:81 +#: web/b3desk/forms.py:81 msgid "Le texte est trop long" msgstr "" -#: web/flaskr/forms.py:85 +#: web/b3desk/forms.py:85 msgid "Nombre maximal de participants" msgstr "" -#: web/flaskr/forms.py:86 +#: web/b3desk/forms.py:86 msgid "Limitez vos salons à 250 personnes pour plus de confort" msgstr "" -#: web/flaskr/forms.py:92 +#: web/b3desk/forms.py:92 msgid "Durée maximale en minutes" msgstr "" -#: web/flaskr/forms.py:93 +#: web/b3desk/forms.py:93 #, python-format msgid "Après laquelle %(the_meeting)s stoppe automatiquement" msgstr "" -#: web/flaskr/forms.py:101 +#: web/b3desk/forms.py:101 msgid "Salle d'attente" msgstr "" -#: web/flaskr/forms.py:102 +#: web/b3desk/forms.py:102 #, python-format msgid "" "Placer les participants dans une salle d'attente lorsqu'ils rejoignent " @@ -78,203 +78,203 @@ msgid "" "individuellement." msgstr "" -#: web/flaskr/forms.py:109 +#: web/b3desk/forms.py:109 msgid "Seul les modérateurs peuvent voir les webcams des autres participants" msgstr "" -#: web/flaskr/forms.py:112 +#: web/b3desk/forms.py:112 msgid "Les participants ne verront pas la diffusion de la caméra des autres" msgstr "" -#: web/flaskr/forms.py:118 +#: web/b3desk/forms.py:118 msgid "Micros fermés au démarrage" msgstr "" -#: web/flaskr/forms.py:119 +#: web/b3desk/forms.py:119 msgid "Les micros sont clos à la connexion des utilisateurs" msgstr "" -#: web/flaskr/forms.py:125 +#: web/b3desk/forms.py:125 msgid "Verrouillage caméra" msgstr "" -#: web/flaskr/forms.py:126 +#: web/b3desk/forms.py:126 msgid "Les participants ne pourront pas activer leur caméra" msgstr "" -#: web/flaskr/forms.py:132 +#: web/b3desk/forms.py:132 msgid "Verrouillage micro" msgstr "" -#: web/flaskr/forms.py:133 +#: web/b3desk/forms.py:133 msgid "Les participants ne pourront pas activer leur micro" msgstr "" -#: web/flaskr/forms.py:137 +#: web/b3desk/forms.py:137 msgid "Désactivation de la discussion privée" msgstr "" -#: web/flaskr/forms.py:138 +#: web/b3desk/forms.py:138 msgid "Interdit les échanges textes directs entre participants" msgstr "" -#: web/flaskr/forms.py:144 +#: web/b3desk/forms.py:144 msgid "Désactivation de la discussion publique" msgstr "" -#: web/flaskr/forms.py:145 +#: web/b3desk/forms.py:145 msgid "Pas de tchat" msgstr "" -#: web/flaskr/forms.py:149 +#: web/b3desk/forms.py:149 msgid "Désactivation de la prise de notes" msgstr "" -#: web/flaskr/forms.py:150 +#: web/b3desk/forms.py:150 msgid "Pas de prise de notes collaborative" msgstr "" -#: web/flaskr/forms.py:154 +#: web/b3desk/forms.py:154 msgid "Message à l'attention des modérateurs" msgstr "" -#: web/flaskr/forms.py:155 +#: web/b3desk/forms.py:155 msgid "150 caractères max" msgstr "" -#: web/flaskr/forms.py:156 +#: web/b3desk/forms.py:156 msgid "Bienvenue aux modérateurs" msgstr "" -#: web/flaskr/forms.py:158 +#: web/b3desk/forms.py:158 msgid "Le message est trop long" msgstr "" -#: web/flaskr/forms.py:163 +#: web/b3desk/forms.py:163 #, python-format msgid "Url de redirection après %(the_meeting)s" msgstr "" -#: web/flaskr/forms.py:170 +#: web/b3desk/forms.py:170 msgid "Renouveler le lien modérateur" msgstr "" -#: web/flaskr/forms.py:171 web/flaskr/forms.py:180 +#: web/b3desk/forms.py:171 web/b3desk/forms.py:180 msgid "Ce code vous permet si vous le changez de bloquer les anciens liens" msgstr "" -#: web/flaskr/forms.py:179 +#: web/b3desk/forms.py:179 msgid "Renouveler le lien participants" msgstr "" -#: web/flaskr/forms.py:191 +#: web/b3desk/forms.py:191 msgid "Enregistrement manuel" msgstr "" -#: web/flaskr/forms.py:192 +#: web/b3desk/forms.py:192 msgid "Autoriser le démarrage et l'arrêt de l'enregistrement par le modérateur" msgstr "" -#: web/flaskr/forms.py:198 +#: web/b3desk/forms.py:198 msgid "Enregistrement automatique" msgstr "" -#: web/flaskr/forms.py:199 +#: web/b3desk/forms.py:199 msgid "Démarrage automatique" msgstr "" -#: web/flaskr/routes.py:548 +#: web/b3desk/routes.py:548 msgid "" "Courriel invalide. Avez vous bien tapé votre email ? Vous pouvez " "réessayer." msgstr "" -#: web/flaskr/routes.py:556 +#: web/b3desk/routes.py:556 msgid "" "Ce courriel ne correspond pas à un service de l'État. Si vous appartenez " "à un service de l'État mais votre courriel n'est pas reconnu par " "Webinaire, contactez-nous pour que nous le rajoutions!" msgstr "" -#: web/flaskr/routes.py:568 +#: web/b3desk/routes.py:568 msgid "Vous avez reçu un courriel pour vous connecter" msgstr "" -#: web/flaskr/routes.py:623 web/flaskr/routes.py:653 +#: web/b3desk/routes.py:623 web/b3desk/routes.py:653 msgid "Vous ne pouvez pas voir cet élément (identifiant incorrect)" msgstr "" -#: web/flaskr/routes.py:643 web/flaskr/routes.py:676 +#: web/b3desk/routes.py:643 web/b3desk/routes.py:676 msgid "Vous ne pouvez pas consulter cet élément" msgstr "" -#: web/flaskr/routes.py:805 +#: web/b3desk/routes.py:805 msgid "Vous ne pouvez pas modifier cet élément" msgstr "" -#: web/flaskr/routes.py:1264 +#: web/b3desk/routes.py:1264 #, python-format msgid "%(meeting_name)s modifications prises en compte" msgstr "" -#: web/flaskr/routes.py:1427 web/flaskr/routes.py:1474 +#: web/b3desk/routes.py:1427 web/b3desk/routes.py:1474 #, python-format msgid "Aucune %(meeting_label)s ne correspond à ces paramètres" msgstr "" -#: web/flaskr/routes.py:1437 web/flaskr/routes.py:1589 +#: web/b3desk/routes.py:1437 web/b3desk/routes.py:1589 msgid "Lien invalide" msgstr "" -#: web/flaskr/routes.py:1442 web/flaskr/routes.py:1594 +#: web/b3desk/routes.py:1442 web/b3desk/routes.py:1594 msgid "Lien expiré" msgstr "" -#: web/flaskr/routes.py:1581 +#: web/b3desk/routes.py:1581 #, python-format msgid "%(meeting_label)s inexistante" msgstr "" -#: web/flaskr/routes.py:1638 +#: web/b3desk/routes.py:1638 msgid "Accès non autorisé" msgstr "" -#: web/flaskr/routes.py:1669 +#: web/b3desk/routes.py:1669 msgid "Élément supprimé" msgstr "" -#: web/flaskr/routes.py:1671 +#: web/b3desk/routes.py:1671 msgid "Vous ne pouvez pas supprimer cet élément" msgstr "" -#: web/flaskr/routes.py:1687 +#: web/b3desk/routes.py:1687 msgid "Vidéo supprimée" msgstr "" -#: web/flaskr/routes.py:1691 +#: web/b3desk/routes.py:1691 #, python-format msgid "Nous n'avons pas pu supprimer cette vidéo : %(code)s, %(message)s" msgstr "" -#: web/flaskr/routes.py:1700 +#: web/b3desk/routes.py:1700 msgid "Vous ne pouvez pas supprimer cette enregistrement" msgstr "" -#: web/flaskr/templates/brand.html:19 +#: web/b3desk/templates/brand.html:19 #, python-format msgid "%(service_title)s" msgstr "" -#: web/flaskr/templates/brand.html:26 +#: web/b3desk/templates/brand.html:26 #, python-format msgid "%(service_tagline)s" msgstr "" -#: web/flaskr/templates/content.py:6 +#: web/b3desk/templates/content.py:6 msgid "Quelles sont les conditions d’accès pour accéder aux services ?" msgstr "" -#: web/flaskr/templates/content.py:9 +#: web/b3desk/templates/content.py:9 msgid "" "Cette plateforme offre une solution complète et puissante, adaptée à de " "nombreux types d’événements en ligne, jusqu’à 350 participants " @@ -311,11 +311,11 @@ msgid "" "- Sur Android, utiliser le navigateur Chrome par défaut (Android 6.0+)\n" msgstr "" -#: web/flaskr/templates/content.py:33 +#: web/b3desk/templates/content.py:33 msgid "Quel est le matériel nécessaire ?" msgstr "" -#: web/flaskr/templates/content.py:34 +#: web/b3desk/templates/content.py:34 msgid "" "Pour utiliser l’outil Webinaire de l’État, il vous suffit de disposer du " "matériel suivant :\n" @@ -337,11 +337,11 @@ msgid "" "contexte d’intervention." msgstr "" -#: web/flaskr/templates/content.py:46 +#: web/b3desk/templates/content.py:46 msgid "Puis-je utiliser mon smartphone ou ma tablette pour me connecter ?" msgstr "" -#: web/flaskr/templates/content.py:49 +#: web/b3desk/templates/content.py:49 msgid "" "Le Webinaire de l’Etat fonctionne également sur les appareils mobiles par" " un simple lien (sans application) sur le portail ou dans le séminaire. " @@ -349,11 +349,11 @@ msgid "" "Sur Android, utiliser le navigateur chrome par défaut (Android 6.0+).\n" msgstr "" -#: web/flaskr/templates/content.py:55 +#: web/b3desk/templates/content.py:55 msgid "Comment créer un séminaire ?" msgstr "" -#: web/flaskr/templates/content.py:56 +#: web/b3desk/templates/content.py:56 msgid "" "Si vous êtes un agent de l’état, vous pouvez :\n" "- Créer des séminaires immédiatement en renseignant votre courriel " @@ -369,11 +369,11 @@ msgid "" "contact@webinaire.numerique.gouv.fr \n" msgstr "" -#: web/flaskr/templates/content.py:67 +#: web/b3desk/templates/content.py:67 msgid "Comment créer un compte ?" msgstr "" -#: web/flaskr/templates/content.py:68 +#: web/b3desk/templates/content.py:68 msgid "" "En tant qu’agent de l’État, si vous organisez régulièrement des " "séminaires vous pouvez créer un compte pour organiser et conserver " @@ -386,11 +386,11 @@ msgid "" "en grand nombre, …etc.)." msgstr "" -#: web/flaskr/templates/content.py:75 +#: web/b3desk/templates/content.py:75 msgid "Comment inviter les participants/ modérateurs" msgstr "" -#: web/flaskr/templates/content.py:76 +#: web/b3desk/templates/content.py:76 msgid "" "L’organisateur qui a créé le séminaire peut partager le lien :\n" "« Participants » qu’ils soient de l’administration ou de l’extérieur " @@ -398,11 +398,11 @@ msgid "" "« Organisateurs/modérateurs » qui géreront avec vous le séminaire." msgstr "" -#: web/flaskr/templates/content.py:83 +#: web/b3desk/templates/content.py:83 msgid "Rejoindre un Webinaire en appel téléphonique ?" msgstr "" -#: web/flaskr/templates/content.py:84 +#: web/b3desk/templates/content.py:84 msgid "" "Une fois dans le séminaire, il est possible d’utiliser aussi son " "téléphone fixe ou mobile pour suivre le séminaire.\n" @@ -417,11 +417,11 @@ msgid "" "téléphone afin d’activer ou de désactiver votre microphone." msgstr "" -#: web/flaskr/templates/content.py:95 +#: web/b3desk/templates/content.py:95 msgid "J'ai des perturbations audio ou vidéo ?" msgstr "" -#: web/flaskr/templates/content.py:96 +#: web/b3desk/templates/content.py:96 msgid "" "\n" "Pour l’audio, rapprochez-vous de votre borne wifi, ou/et coupez votre " @@ -442,225 +442,225 @@ msgid "" "de vous connecter hors VPN.\n" msgstr "" -#: web/flaskr/templates/content.py:110 +#: web/b3desk/templates/content.py:110 msgid "Besoin de contacter l'équipe du Webinaire de l’Etat ?" msgstr "" -#: web/flaskr/templates/content.py:113 +#: web/b3desk/templates/content.py:113 msgid "contact@webinaire.numerique.gouv.fr" msgstr "" -#: web/flaskr/templates/content.py:116 +#: web/b3desk/templates/content.py:116 msgid "Besoin de contacter l'équipe du ministére de l'Éducation nationale ?" msgstr "" -#: web/flaskr/templates/content.py:119 +#: web/b3desk/templates/content.py:119 msgid "" "Rendez-vous sur votre portail d'assistance académique " "https://www.education.gouv.fr/la-messagerie-professionnelle-3446 ou sur " "Apps.education.fr" msgstr "" -#: web/flaskr/templates/empty.html:2 +#: web/b3desk/templates/empty.html:2 msgid "Vous devez vous identifier pour consulter la liste des visioconférences." msgstr "" -#: web/flaskr/templates/faq.html:8 +#: web/b3desk/templates/faq.html:8 msgid "FAQ - Modalités d'accès" msgstr "" -#: web/flaskr/templates/footer.html:12 +#: web/b3desk/templates/footer.html:12 msgid "" "Service proposé par la Direction interministérielle du numérique et la " "Direction du numérique pour l'éducation" msgstr "" -#: web/flaskr/templates/footer.html:15 +#: web/b3desk/templates/footer.html:15 msgid "Le code source est ouvert et les contributions sont bienvenues." msgstr "" -#: web/flaskr/templates/footer.html:16 +#: web/b3desk/templates/footer.html:16 msgid "Voir le code source - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/footer.html:16 +#: web/b3desk/templates/footer.html:16 msgid "Voir le code source" msgstr "" -#: web/flaskr/templates/footer.html:37 +#: web/b3desk/templates/footer.html:37 msgid "Accessibilité : non conforme" msgstr "" -#: web/flaskr/templates/footer.html:40 -#: web/flaskr/templates/footer/mentions_legales.html:10 +#: web/b3desk/templates/footer.html:40 +#: web/b3desk/templates/footer/mentions_legales.html:10 msgid "Mentions légales" msgstr "" -#: web/flaskr/templates/footer.html:43 +#: web/b3desk/templates/footer.html:43 msgid "Données personnelles et cookies" msgstr "" -#: web/flaskr/templates/footer.html:46 web/flaskr/templates/footer/cgu.html:10 +#: web/b3desk/templates/footer.html:46 web/b3desk/templates/footer/cgu.html:10 msgid "Conditions générales d’utilisation" msgstr "" -#: web/flaskr/templates/jumbotron.html:8 +#: web/b3desk/templates/jumbotron.html:8 #, python-format msgid "Lancer %(a_meeting)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:9 +#: web/b3desk/templates/jumbotron.html:9 #, python-format msgid "Lancer %(the_meeting)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/jumbotron.html:9 +#: web/b3desk/templates/jumbotron.html:9 #, python-format -msgid "Démarrer %(a_meeting)s immédiatement" +msgid "Ouvrir %(a_meeting)s temporaire" msgstr "" -#: web/flaskr/templates/jumbotron.html:19 -#: web/flaskr/templates/jumbotron.html:49 +#: web/b3desk/templates/jumbotron.html:19 +#: web/b3desk/templates/jumbotron.html:49 #, python-format msgid "Actuellement, il y a %(count)s webinaire" msgid_plural "Actuellement, il y a %(count)s webinaires" msgstr[0] "" msgstr[1] "" -#: web/flaskr/templates/jumbotron.html:24 -#: web/flaskr/templates/jumbotron.html:54 +#: web/b3desk/templates/jumbotron.html:24 +#: web/b3desk/templates/jumbotron.html:54 #, python-format msgid "et %(count)s participant" msgid_plural "et %(count)s participants" msgstr[0] "" msgstr[1] "" -#: web/flaskr/templates/jumbotron.html:29 -#: web/flaskr/templates/jumbotron.html:59 +#: web/b3desk/templates/jumbotron.html:29 +#: web/b3desk/templates/jumbotron.html:59 #, python-format msgid "" " sur une capacité moyenne pour la plateforme de %(max_participants)s " "participants." msgstr "" -#: web/flaskr/templates/jumbotron.html:42 +#: web/b3desk/templates/jumbotron.html:42 #, python-format msgid "Vous organisez régulièrement des %(some_meetings)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:43 +#: web/b3desk/templates/jumbotron.html:43 #, python-format msgid "" "Vous êtes agent de l’État, créez un compte pour organiser et conserver " "vos %(some_meetings)s." msgstr "" -#: web/flaskr/templates/jumbotron.html:44 +#: web/b3desk/templates/jumbotron.html:44 msgid "Se connecter ou créer un compte" msgstr "" -#: web/flaskr/templates/jumbotron.html:73 +#: web/b3desk/templates/jumbotron.html:73 #, python-format msgid "Démarrer %(a_meeting)s en ligne immédiatement" msgstr "" -#: web/flaskr/templates/jumbotron.html:83 +#: web/b3desk/templates/jumbotron.html:83 #, python-format msgid "" "Recevez par courriel un lien organisateur %(of_the_meeting)s, actif une " "semaine, à envoyer aux participants." msgstr "" -#: web/flaskr/templates/jumbotron.html:88 +#: web/b3desk/templates/jumbotron.html:88 msgid "Votre courriel professionnel" msgstr "" -#: web/flaskr/templates/jumbotron.html:92 +#: web/b3desk/templates/jumbotron.html:92 #, python-format msgid "Créer %(my_meeting)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:108 +#: web/b3desk/templates/jumbotron.html:108 #, python-format msgid "Vous essayez de rejoindre %(a_meeting)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:109 +#: web/b3desk/templates/jumbotron.html:109 #, python-format msgid "" "Pour rejoindre %(a_meeting_to_which)s vous êtes invité, cliquez sur le " "lien que vous a transmis l'organisateur/modérateur." msgstr "" -#: web/flaskr/templates/redirections.html:4 +#: web/b3desk/templates/redirections.html:4 msgid "Connectez-vous ou créez un compte" msgstr "" -#: web/flaskr/templates/redirections.html:10 +#: web/b3desk/templates/redirections.html:10 msgid "Autres profils" msgstr "" -#: web/flaskr/templates/rie.html:3 +#: web/b3desk/templates/rie.html:3 msgid "Service accessible suivant les politiques de sécurité de votre ministère." msgstr "" -#: web/flaskr/templates/rie.html:4 +#: web/b3desk/templates/rie.html:4 msgid "" "Si l'audio ou la vidéo ne fonctionne pas, vous devez utiliser un autre " "appareil (ordinateur, smartphone)." msgstr "" -#: web/flaskr/templates/rie.html:5 +#: web/b3desk/templates/rie.html:5 msgid "en savoir plus" msgstr "" -#: web/flaskr/templates/tools.html:13 +#: web/b3desk/templates/tools.html:13 msgid "Modalités d'accès" msgstr "" -#: web/flaskr/templates/tools.html:32 +#: web/b3desk/templates/tools.html:32 msgid "se déconnecter" msgstr "" -#: web/flaskr/templates/tools.html:40 +#: web/b3desk/templates/tools.html:40 msgid "S’identifier" msgstr "" -#: web/flaskr/templates/errors/403.html:11 +#: web/b3desk/templates/errors/403.html:11 msgid "Erreur 403" msgstr "" -#: web/flaskr/templates/errors/403.html:12 +#: web/b3desk/templates/errors/403.html:12 msgid "" "Vous n’êtes pas autorisé à accéder cette page. Vous pouvez retourner à l’accueil." msgstr "" -#: web/flaskr/templates/errors/404.html:11 +#: web/b3desk/templates/errors/404.html:11 msgid "Erreur 404" msgstr "" -#: web/flaskr/templates/errors/404.html:12 +#: web/b3desk/templates/errors/404.html:12 msgid "" "Cette page n'existe pas. Vous pouvez retourner à " "l’accueil." msgstr "" -#: web/flaskr/templates/errors/500.html:11 +#: web/b3desk/templates/errors/500.html:11 msgid "Erreur 500" msgstr "" -#: web/flaskr/templates/errors/500.html:12 +#: web/b3desk/templates/errors/500.html:12 msgid "" "Le serveur a rencontré une erreur interne, veuillez réessayer " "ultérieurement." msgstr "" -#: web/flaskr/templates/footer/accessibilite.html:9 +#: web/b3desk/templates/footer/accessibilite.html:9 msgid "Accessibilité" msgstr "" -#: web/flaskr/templates/footer/accessibilite.html:10 +#: web/b3desk/templates/footer/accessibilite.html:10 msgid "" "Le site webinaire.numerique.gouv.fr est développé selon les " "recommendations du annuaire de l'administration" msgstr "" -#: web/flaskr/templates/footer/cgu.html:11 +#: web/b3desk/templates/footer/cgu.html:11 msgid "" "Le webinaire, Visio-ecoles/colleges/lycees/agents de l’État permet " "d’accéder à la page d’accueil du sous-domaine internet utilisé par l’Etat" @@ -741,7 +741,7 @@ msgid "" "les partenaires du service public." msgstr "" -#: web/flaskr/templates/footer/cgu.html:12 +#: web/b3desk/templates/footer/cgu.html:12 msgid "" "Le sous-domaine « https://visio-" @@ -763,25 +763,25 @@ msgid "" "Nationale, de la Jeunesse et des Sports." msgstr "" -#: web/flaskr/templates/footer/cgu.html:14 +#: web/b3desk/templates/footer/cgu.html:14 msgid "" "Le service est maintenu en conditions opérationnelles et ses évolutions " "sont assurées par le Ministère de l’Éducation Nationale, de la Jeunesse " "et des Sports, ci-après dénommé « l’éditeur »." msgstr "" -#: web/flaskr/templates/footer/cgu.html:15 +#: web/b3desk/templates/footer/cgu.html:15 msgid "" "Toute utilisation des ressources de domaine de publication est " "subordonnée au respect des présentes conditions générales d’utilisation " "(CGU)." msgstr "" -#: web/flaskr/templates/footer/cgu.html:17 +#: web/b3desk/templates/footer/cgu.html:17 msgid "Objet" msgstr "" -#: web/flaskr/templates/footer/cgu.html:18 +#: web/b3desk/templates/footer/cgu.html:18 msgid "" "Le sous-domaine permet de publier sur internet l’offre de service " "interministérielle de webconférence.

    " msgstr "" -#: web/flaskr/templates/footer/cgu.html:19 +#: web/b3desk/templates/footer/cgu.html:19 msgid "Code de conduite et responsabilités des Utilisateurs" msgstr "" -#: web/flaskr/templates/footer/cgu.html:20 +#: web/b3desk/templates/footer/cgu.html:20 msgid "" "L’utilisation de ce service interministériel est libre et gratuite pour " "les utilisateurs des services de l’Etat, et sur invitation, pour les " @@ -805,14 +805,14 @@ msgid "" "et responsabilités de l’éditeur." msgstr "" -#: web/flaskr/templates/footer/cgu.html:21 +#: web/b3desk/templates/footer/cgu.html:21 msgid "" "Sitôt entré sur la page d’accueil, l’utilisateur peut en consulter les " "contenus ou accéder à un salon en saisissant le nom de ce salon ou, pour " "les agents de l’Etat, en créant ledit salon." msgstr "" -#: web/flaskr/templates/footer/cgu.html:22 +#: web/b3desk/templates/footer/cgu.html:22 msgid "" "À l’instant où l’utilisateur accède à un salon de webconférence, il " "devient seul responsable des données et des contenus qu’il échange sur le" @@ -820,17 +820,17 @@ msgid "" "netiquette." msgstr "" -#: web/flaskr/templates/footer/cgu.html:23 +#: web/b3desk/templates/footer/cgu.html:23 msgid "Usage professionnel" msgstr "" -#: web/flaskr/templates/footer/cgu.html:24 +#: web/b3desk/templates/footer/cgu.html:24 msgid "" "Le service de Webinaire, Visio-ecoles/colleges/lycees/agents mis à " "disposition est à usage professionnel." msgstr "" -#: web/flaskr/templates/footer/cgu.html:25 +#: web/b3desk/templates/footer/cgu.html:25 msgid "" "Seule l’utilisation à usage professionnel de cette ressource mise à " "disposition est tolérée, l’utilisateur est attentif à ce que ces usages " @@ -838,11 +838,11 @@ msgid "" "service auquel il accède." msgstr "" -#: web/flaskr/templates/footer/cgu.html:26 +#: web/b3desk/templates/footer/cgu.html:26 msgid "Engagements et responsabilités de l’éditeur" msgstr "" -#: web/flaskr/templates/footer/cgu.html:27 +#: web/b3desk/templates/footer/cgu.html:27 msgid "" "L’éditeur donne accès au service interministériel de webconférence aux " "adresses suivantes : (\n" "56 rue de Varenne
    \n" "75007 Paris" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:95 +#: web/b3desk/templates/footer/donnees_personnelles.html:95 msgid "" "Si vous estimez, après nous avoir contactés, que vos droits Informatiques" " et Libertés ne sont pas respectés vous pouvez adresser une réclamation à" " la CNIL :" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:96 +#: web/b3desk/templates/footer/donnees_personnelles.html:96 msgid "" "Commission nationale informatique et libertés
    \n" "3 place de Fontenoy – TSA 80715 –
    \n" "75334 PARIS CEDEX 07" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:100 +#: web/b3desk/templates/footer/donnees_personnelles.html:100 msgid "" "Les modalités de réclamation sont précisées sur le site de la CNIL : " "www.cnil.fr." msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:102 +#: web/b3desk/templates/footer/donnees_personnelles.html:102 msgid "" "Contactez le Délégué à la protection des données pour les services " "Écoles/Colléges/Lycées/Agents" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:103 +#: web/b3desk/templates/footer/donnees_personnelles.html:103 msgid "" "Pour ce faire, envoyez un courriel à " "dpd[chez]education.gouv.fr" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:11 +#: web/b3desk/templates/footer/mentions_legales.html:11 msgid "Éditeur" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:12 +#: web/b3desk/templates/footer/mentions_legales.html:12 msgid "" "Ministère de l’Éducation nationale et de la jeunesse Direction du " "numérique pour l’éducation 110 rue Grenelle, 75007 Paris" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:12 +#: web/b3desk/templates/footer/mentions_legales.html:12 msgid "Directeur de publication" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:13 +#: web/b3desk/templates/footer/mentions_legales.html:13 msgid "Directeur de la publication" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:14 +#: web/b3desk/templates/footer/mentions_legales.html:14 msgid "M. Audran Le Baron, Directeur du numérique pour l’éducation" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:15 +#: web/b3desk/templates/footer/mentions_legales.html:15 msgid "Gestionnaire des statistiques" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:16 +#: web/b3desk/templates/footer/mentions_legales.html:16 msgid "Il n’y a pas d’outil de mesure d’audience pour ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:17 +#: web/b3desk/templates/footer/mentions_legales.html:17 msgid "Conception et gestion du site" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:18 +#: web/b3desk/templates/footer/mentions_legales.html:18 msgid "" "Le suivi éditorial, graphique et technique du site est assuré au " "quotidien par les équipes de la DINUM et du Pôle de compétence Identité " "du MENJS." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:19 +#: web/b3desk/templates/footer/mentions_legales.html:19 msgid "Droits de reproduction" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:20 +#: web/b3desk/templates/footer/mentions_legales.html:20 msgid "" "Conformément au droit public de la propriété intellectuelle et notamment " "selon l’article L122-5 du Code de la propriété intellectuelle, les " "’’documents officiels’’ sont librement réutilisables." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:21 +#: web/b3desk/templates/footer/mentions_legales.html:21 msgid "" "Cependant, le bon usage veut que la reprise de ces contenus de façon " "partielle ou intégrale mentionne clairement la source, et le cas échéant " "avec un lien vers le document original en ligne sur ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:22 +#: web/b3desk/templates/footer/mentions_legales.html:22 msgid "" "Toutes les infographies et vidéos réalisées par le service de " "communication de l’éditeur se trouvent sous « Licence Ouverte V2.0 » et " "sont librement réutilisables sous les conditions suivantes :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:23 +#: web/b3desk/templates/footer/mentions_legales.html:23 msgid "" "Attribution : vous devez attribuer l’œuvre de la manière indiquée par " "l’auteur de l’œuvre ou le titulaire des droits (mais pas d’une manière " @@ -1356,32 +1356,32 @@ msgid "" "l’œuvre)." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:24 +#: web/b3desk/templates/footer/mentions_legales.html:24 msgid "Liens hypertextes pointant vers ce site :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:25 +#: web/b3desk/templates/footer/mentions_legales.html:25 msgid "" "Tout site public ou privé est autorisé à établir, sans autorisation " "préalable, un lien (y compris profond) vers les informations diffusées " "par ce site de webinaire, Visio-ecoles/colleges/lycees/agents." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:26 +#: web/b3desk/templates/footer/mentions_legales.html:26 msgid "" "Pour les sites Internet, la reproduction, après autorisation, d’un " "contenu doit mentionner très clairement l’origine du document sous forme " "d’une adresse internet :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:27 +#: web/b3desk/templates/footer/mentions_legales.html:27 msgid "" "La mise en place de “liens profonds” pointant directement sur le document" " souhaité devra être privilégiée par rapport à la reproduction de " "contenus." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:28 +#: web/b3desk/templates/footer/mentions_legales.html:28 msgid "" "En effet, dans ce cas, la mise en place de liens vers ce site de " "Webinaire/Visio-ecoles/colleges/lycees/agents n’est conditionnée à aucun " @@ -1389,20 +1389,20 @@ msgid "" "du lien est recommandée." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:29 +#: web/b3desk/templates/footer/mentions_legales.html:29 msgid "" "Les sites qui font le choix de pointer vers ce site de Webinaire, Visio-" "ecoles/colleges/lycees/agents engagent leur responsabilité dès lors " "qu’ils porteraient atteinte à l’image du site public." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:30 +#: web/b3desk/templates/footer/mentions_legales.html:30 msgid "" "Liens hypertextes proposés par ce site de Webinaire, Visio-" "ecoles/colleges/lycees/agents :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:31 +#: web/b3desk/templates/footer/mentions_legales.html:31 msgid "" "Les liens vers chaque service interministériel référencé dans le " "catalogue que proposé par de ce site. Leur présence engage l’éditeur et " @@ -1412,43 +1412,43 @@ msgid "" "disposition au plan interministériel." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:32 +#: web/b3desk/templates/footer/mentions_legales.html:32 msgid "Clause de responsabilité" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:33 +#: web/b3desk/templates/footer/mentions_legales.html:33 msgid "" "Les informations proposées sur ce site le sont à titre de service rendu " "aux agents du service public, notamment aux agents des services de " "l’État." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:34 +#: web/b3desk/templates/footer/mentions_legales.html:34 msgid "" "Les informations et/ou documents disponibles sur ce site sont " "susceptibles d’être modifiés à tout moment, et peuvent faire l’objet de " "mises à jour pour faciliter l’accès aux ressources numériques." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:35 +#: web/b3desk/templates/footer/mentions_legales.html:35 msgid "" "Les informations et/ou documents accédés à partir de ce site relèvent de " "la responsabilité des porteurs de chaque service interministériel ainsi " "mis à disposition." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:36 +#: web/b3desk/templates/footer/mentions_legales.html:36 msgid "" "L’éditeur ne pourra en aucun cas être tenue responsable de tout dommage " "de quelque nature qu’il soit résultant de la mauvaise utilisation des " "ressources accessibles à partir de ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:37 +#: web/b3desk/templates/footer/mentions_legales.html:37 msgid "Droit à la compensation" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:38 +#: web/b3desk/templates/footer/mentions_legales.html:38 msgid "" "Dans l’attente d’une mise en conformité totale d’un de ces services, vous" " pouvez obtenir une version accessible des documents ou des informations " @@ -1458,69 +1458,69 @@ msgid "" "demandées vous seront transmises dans les plus brefs délais." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:40 +#: web/b3desk/templates/footer/mentions_legales.html:40 msgid "" "Vous pouvez nous aider à améliorer l’accessibilité du site en nous " "signalant les problèmes éventuels que vous rencontrez. Pour ce faire, " "envoyez-nous un courriel à apps[chez]education.gouv.fr" msgstr "" -#: web/flaskr/templates/meeting/form.html:36 +#: web/b3desk/templates/meeting/form.html:36 msgid "Modifier" msgstr "" -#: web/flaskr/templates/meeting/form.html:38 -#: web/flaskr/templates/meeting/submit.html:5 +#: web/b3desk/templates/meeting/form.html:38 +#: web/b3desk/templates/meeting/submit.html:5 msgid "Créer" msgstr "" -#: web/flaskr/templates/meeting/form.html:43 +#: web/b3desk/templates/meeting/form.html:43 msgid "Enregistrement impossible car certains champs sont mal renseignés." msgstr "" -#: web/flaskr/templates/meeting/form.html:51 +#: web/b3desk/templates/meeting/form.html:51 msgid "Configuration" msgstr "" -#: web/flaskr/templates/meeting/form.html:67 +#: web/b3desk/templates/meeting/form.html:67 msgid "" "Gestion des permissions, elles peuvent être ajustées une fois dans le " "salon" msgstr "" -#: web/flaskr/templates/meeting/form.html:84 +#: web/b3desk/templates/meeting/form.html:84 msgid "Personnalisation" msgstr "" -#: web/flaskr/templates/meeting/form.html:99 +#: web/b3desk/templates/meeting/form.html:99 msgid "Enregistrement" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:3 +#: web/b3desk/templates/meeting/jumbotron.html:3 msgid "Webinaire" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:5 +#: web/b3desk/templates/meeting/jumbotron.html:5 msgid "Nouveau webinaire" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:8 +#: web/b3desk/templates/meeting/jumbotron.html:8 msgid "Retour au tableau de bord" msgstr "" -#: web/flaskr/templates/meeting/list.html:2 +#: web/b3desk/templates/meeting/list.html:2 #, python-format msgid "Mes salles de %(some_meetings)s" msgstr "" -#: web/flaskr/templates/meeting/list.html:4 +#: web/b3desk/templates/meeting/list.html:4 #, python-format msgid "" "Créer une salle de %(meeting_label)s
    vous permet de conserver les " "réglages et le lien de la salle." msgstr "" -#: web/flaskr/templates/meeting/list.html:9 +#: web/b3desk/templates/meeting/list.html:9 #, python-format msgid "" "Vous avez atteint la limite des %(max_meetings_per_user)s " @@ -1528,22 +1528,22 @@ msgid "" "des %(meeting_label)ss inactives." msgstr "" -#: web/flaskr/templates/meeting/modals.html:75 +#: web/b3desk/templates/meeting/modals.html:75 #, python-format msgid "" "%(the_meeting)s est toujours en cours. Si un enregistrement est en cours," " il ne sera encodé qu'après la fin %(of_the_meeting)s." msgstr "" -#: web/flaskr/templates/meeting/modals.html:77 -#: web/flaskr/templates/meeting/recordings.html:22 +#: web/b3desk/templates/meeting/modals.html:77 +#: web/b3desk/templates/meeting/recordings.html:22 #, python-format msgid "" "Après la fin d'%(a_meeting)s, l'encodage de l'enregistrement peut prendre" " autant de temps que la durée %(of_the_meeting)s." msgstr "" -#: web/flaskr/templates/meeting/modals.html:78 +#: web/b3desk/templates/meeting/modals.html:78 #, python-format msgid "" "Si aucun modérateur ne met fin %(to_the_meeting)s, un délai " @@ -1551,54 +1551,54 @@ msgid "" "utilisateurs l'aient quitté." msgstr "" -#: web/flaskr/templates/meeting/modals.html:84 +#: web/b3desk/templates/meeting/modals.html:84 msgid "Images" msgstr "" -#: web/flaskr/templates/meeting/modals.html:85 +#: web/b3desk/templates/meeting/modals.html:85 msgid "Lien" msgstr "" -#: web/flaskr/templates/meeting/modals.html:105 -#: web/flaskr/templates/meeting/modals.html:106 -#: web/flaskr/templates/meeting/recordings.html:71 -#: web/flaskr/templates/meeting/recordings.html:72 +#: web/b3desk/templates/meeting/modals.html:105 +#: web/b3desk/templates/meeting/modals.html:106 +#: web/b3desk/templates/meeting/recordings.html:71 +#: web/b3desk/templates/meeting/recordings.html:72 #, python-format msgid "Supprimer video de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/modals.html:108 -#: web/flaskr/templates/meeting/recordings.html:74 +#: web/b3desk/templates/meeting/modals.html:108 +#: web/b3desk/templates/meeting/recordings.html:74 msgid "Suppression d'enregistrement" msgstr "" -#: web/flaskr/templates/meeting/modals.html:111 +#: web/b3desk/templates/meeting/modals.html:111 msgid "Copier le lien de l'enregistrement dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:11 +#: web/b3desk/templates/meeting/recordings.html:11 #, python-format msgid "Enregistrements de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:13 +#: web/b3desk/templates/meeting/recordings.html:13 #, python-format msgid "Retour à mes %(meeting_label)ss" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:18 +#: web/b3desk/templates/meeting/recordings.html:18 #, python-format msgid "%(this_meeting)s est toujours en cours" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:19 +#: web/b3desk/templates/meeting/recordings.html:19 #, python-format msgid "" "Si un enregistrement est en cours, il ne sera encodé qu'après la fin " "%(of_the_meeting)s" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:23 +#: web/b3desk/templates/meeting/recordings.html:23 #, python-format msgid "" "Si aucun modérateur ne met fin %(of_the_meeting)s, un délai " @@ -1606,199 +1606,199 @@ msgid "" "utilisateurs l'aient quitté." msgstr "" -#: web/flaskr/templates/meeting/recordings.html:42 +#: web/b3desk/templates/meeting/recordings.html:42 msgid "Visuels" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:43 +#: web/b3desk/templates/meeting/recordings.html:43 msgid "Actions" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:76 -#: web/flaskr/templates/meeting/row.html:29 -#: web/flaskr/templates/meeting/row.html:40 -#: web/flaskr/templates/meeting/row.html:59 +#: web/b3desk/templates/meeting/recordings.html:76 +#: web/b3desk/templates/meeting/row.html:29 +#: web/b3desk/templates/meeting/row.html:40 +#: web/b3desk/templates/meeting/row.html:59 msgid "Fermer la fenêtre modale" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:91 +#: web/b3desk/templates/meeting/recordings.html:91 msgid "Supprimer" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:92 -#: web/flaskr/templates/meeting/submit.html:7 +#: web/b3desk/templates/meeting/recordings.html:92 +#: web/b3desk/templates/meeting/submit.html:7 msgid "Annuler" msgstr "" -#: web/flaskr/templates/meeting/row.html:5 -#: web/flaskr/templates/meeting/row.html:33 +#: web/b3desk/templates/meeting/row.html:5 +#: web/b3desk/templates/meeting/row.html:33 #, python-format msgid "Lancer %(meeting_name)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/meeting/row.html:7 +#: web/b3desk/templates/meeting/row.html:7 msgid "Envoyer un courriel aux modérateurs" msgstr "" -#: web/flaskr/templates/meeting/row.html:9 +#: web/b3desk/templates/meeting/row.html:9 msgid "Copier le lien Modérateur dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/row.html:13 +#: web/b3desk/templates/meeting/row.html:13 #, python-format msgid "Participer à %(meeting_name)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/meeting/row.html:15 +#: web/b3desk/templates/meeting/row.html:15 msgid "Envoyer un courriel aux participants" msgstr "" -#: web/flaskr/templates/meeting/row.html:17 +#: web/b3desk/templates/meeting/row.html:17 msgid "Copier le lien Participant dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/row.html:20 -#: web/flaskr/templates/meeting/row.html:50 +#: web/b3desk/templates/meeting/row.html:20 +#: web/b3desk/templates/meeting/row.html:50 #, python-format msgid "Modifier %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:24 -#: web/flaskr/templates/meeting/row.html:25 -#: web/flaskr/templates/meeting/row.html:27 -#: web/flaskr/templates/meeting/row.html:54 -#: web/flaskr/templates/meeting/row.html:55 -#: web/flaskr/templates/meeting/row.html:57 +#: web/b3desk/templates/meeting/row.html:24 +#: web/b3desk/templates/meeting/row.html:25 +#: web/b3desk/templates/meeting/row.html:27 +#: web/b3desk/templates/meeting/row.html:54 +#: web/b3desk/templates/meeting/row.html:55 +#: web/b3desk/templates/meeting/row.html:57 #, python-format msgid "Supprimer %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:33 +#: web/b3desk/templates/meeting/row.html:33 msgid "Lancer" msgstr "" -#: web/flaskr/templates/meeting/row.html:36 -#: web/flaskr/templates/meeting/row.html:38 +#: web/b3desk/templates/meeting/row.html:36 +#: web/b3desk/templates/meeting/row.html:38 #, python-format msgid "Inviter à %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:41 +#: web/b3desk/templates/meeting/row.html:41 msgid "Inviter" msgstr "" -#: web/flaskr/templates/meeting/row.html:46 +#: web/b3desk/templates/meeting/row.html:46 #, python-format msgid "Voir les enregistrements de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:1 -#: web/flaskr/templates/meeting/signinmail.html:1 +#: web/b3desk/templates/meeting/signin.html:1 +#: web/b3desk/templates/meeting/signinmail.html:1 #, python-format msgid "Rejoindre %(the_meeting)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:16 +#: web/b3desk/templates/meeting/signin.html:16 #, python-format msgid "%(meeting_attente)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:24 -#: web/flaskr/templates/meeting/signinmail.html:16 +#: web/b3desk/templates/meeting/signin.html:24 +#: web/b3desk/templates/meeting/signinmail.html:16 msgid "Votre nom" msgstr "" -#: web/flaskr/templates/meeting/signin.html:25 -#: web/flaskr/templates/meeting/signinmail.html:17 +#: web/b3desk/templates/meeting/signin.html:25 +#: web/b3desk/templates/meeting/signinmail.html:17 msgid "Vous pouvez également préciser votre service ou votre fonction." msgstr "" -#: web/flaskr/templates/meeting/signin.html:44 -#: web/flaskr/templates/meeting/signinmail.html:23 +#: web/b3desk/templates/meeting/signin.html:44 +#: web/b3desk/templates/meeting/signinmail.html:23 msgid "Rejoindre" msgstr "" -#: web/flaskr/templates/meeting/signinmail.html:10 +#: web/b3desk/templates/meeting/signinmail.html:10 #, python-format msgid "Votre %(meeting_label)s n'a pas encore été activée par un modérateur" msgstr "" -#: web/flaskr/templates/meeting/submit.html:3 +#: web/b3desk/templates/meeting/submit.html:3 msgid "Enregistrer" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:4 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:4 msgid "Modérateur" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:6 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:6 msgid "Participant" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:9 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:9 #, python-format msgid "À %(the_meeting)s suivante :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:13 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:13 msgid "Le lien pour s'y inscrire est le suivant :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:21 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:21 #, python-format msgid "Le mot de passe de %(this_meeting)s est :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:29 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:29 msgid "Vous devez rentrer votre nom complet et le mot de passe pour y accéder." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:2 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:2 msgid "Bonjour," msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:5 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:5 #, python-format msgid "" "Vous avez demandé l’organisation d’%(a_quick_meeting)s au travers du " "webinaire de l’Etat." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:8 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:8 msgid "" "Le lien du webinaire que vous trouvez ci-dessous reste actif et " "accessible pendant une semaine depuis un navigateur internet sur un " "ordinateur ou un smartphone :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:11 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:11 #, python-format msgid "" "%(moderator_mail_signin_url)s" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:14 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:14 msgid "" "Vous pouvez dès à présent transmettre ce lien de connexion aux " "participants que vous souhaitez inviter." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:17 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:17 msgid "" "Une fois sur la page d’accueil, vous êtes invité à rentrer votre nom " "complet pour accéder au webinaire." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:20 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:20 msgid "Vous y êtes !" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:23 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:23 msgid "L’équipe du webinaire de l’Etat vous souhaite un excellent séminaire." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:26 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:26 #, python-format msgid "" "Si vous organisez régulièrement des %(meeting_label)ss, nous vous " @@ -1807,7 +1807,7 @@ msgid "" "mesure." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_subject.txt:1 +#: web/b3desk/templates/meeting/mailto/mail_subject.txt:1 msgid "Invitation" msgstr "" @@ -1849,20 +1849,20 @@ msgstr "" #: web/instance/config.py:185 msgid "" -"Créez un cours immédiatement avec des réglages standards. Ce cours ne " -"sera pas enregistré dans votre liste de salons." +"Créez en un clic un cours aux réglages standards. " +"Il ne sera pas enregistré dans votre liste de salles." msgstr "" #: web/instance/config.py:188 msgid "" -"Créez une réunion immédiatement avec des réglages standards. Cette " -"réunion ne sera pas enregistrée dans votre liste de salons." +"Créez en un clic une réunion aux réglages standards. " +"Elle ne sera pas enregistrée dans votre liste de salles." msgstr "" #: web/instance/config.py:191 msgid "" -"Créez un séminaire immédiatement avec des réglages standards. Ce " -"séminaire ne sera pas enregistré dans votre liste de salons." +"Créez en un clic un séminaire aux réglages standards. " +"Il ne sera pas enregistré dans votre liste de salles." msgstr "" #: web/instance/config.py:196 @@ -1898,4 +1898,3 @@ msgid "" "Bienvenue. Pour inviter quelqu'un à %(this_meeting)s, envoyez-lui l'un de" " ces liens :" msgstr "" - diff --git a/web/translations/uk/LC_MESSAGES/messages.po b/web/translations/uk/LC_MESSAGES/messages.po index 5d5d7a21..9887aef1 100644 --- a/web/translations/uk/LC_MESSAGES/messages.po +++ b/web/translations/uk/LC_MESSAGES/messages.po @@ -19,60 +19,60 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.8.0\n" -#: web/flaskr/forms.py:56 +#: web/b3desk/forms.py:56 #, python-format msgid "Titre %(of_the_meeting)s" msgstr "Ukrainian translation" -#: web/flaskr/forms.py:60 +#: web/b3desk/forms.py:60 #, python-format msgid "Créer %(a_meeting)s dont le titre est :" msgstr "" -#: web/flaskr/forms.py:66 +#: web/b3desk/forms.py:66 #, python-format msgid "%(my_meeting)s" msgstr "" -#: web/flaskr/forms.py:71 +#: web/b3desk/forms.py:71 msgid "Texte de bienvenue" msgstr "" -#: web/flaskr/forms.py:72 +#: web/b3desk/forms.py:72 msgid "Ce texte apparait comme message de bienvenue sur le tchat public" msgstr "" -#: web/flaskr/forms.py:75 +#: web/b3desk/forms.py:75 #, python-format msgid "Bienvenue dans %(this_meeting)s %(meeting_name)s." msgstr "" -#: web/flaskr/forms.py:81 +#: web/b3desk/forms.py:81 msgid "Le texte est trop long" msgstr "" -#: web/flaskr/forms.py:85 +#: web/b3desk/forms.py:85 msgid "Nombre maximal de participants" msgstr "" -#: web/flaskr/forms.py:86 +#: web/b3desk/forms.py:86 msgid "Limitez vos salons à 250 personnes pour plus de confort" msgstr "" -#: web/flaskr/forms.py:92 +#: web/b3desk/forms.py:92 msgid "Durée maximale en minutes" msgstr "" -#: web/flaskr/forms.py:93 +#: web/b3desk/forms.py:93 #, python-format msgid "Après laquelle %(the_meeting)s stoppe automatiquement" msgstr "" -#: web/flaskr/forms.py:101 +#: web/b3desk/forms.py:101 msgid "Salle d'attente" msgstr "" -#: web/flaskr/forms.py:102 +#: web/b3desk/forms.py:102 #, python-format msgid "" "Placer les participants dans une salle d'attente lorsqu'ils rejoignent " @@ -80,203 +80,203 @@ msgid "" "individuellement." msgstr "" -#: web/flaskr/forms.py:109 +#: web/b3desk/forms.py:109 msgid "Seul les modérateurs peuvent voir les webcams des autres participants" msgstr "" -#: web/flaskr/forms.py:112 +#: web/b3desk/forms.py:112 msgid "Les participants ne verront pas la diffusion de la caméra des autres" msgstr "" -#: web/flaskr/forms.py:118 +#: web/b3desk/forms.py:118 msgid "Micros fermés au démarrage" msgstr "" -#: web/flaskr/forms.py:119 +#: web/b3desk/forms.py:119 msgid "Les micros sont clos à la connexion des utilisateurs" msgstr "" -#: web/flaskr/forms.py:125 +#: web/b3desk/forms.py:125 msgid "Verrouillage caméra" msgstr "" -#: web/flaskr/forms.py:126 +#: web/b3desk/forms.py:126 msgid "Les participants ne pourront pas activer leur caméra" msgstr "" -#: web/flaskr/forms.py:132 +#: web/b3desk/forms.py:132 msgid "Verrouillage micro" msgstr "" -#: web/flaskr/forms.py:133 +#: web/b3desk/forms.py:133 msgid "Les participants ne pourront pas activer leur micro" msgstr "" -#: web/flaskr/forms.py:137 +#: web/b3desk/forms.py:137 msgid "Désactivation de la discussion privée" msgstr "" -#: web/flaskr/forms.py:138 +#: web/b3desk/forms.py:138 msgid "Interdit les échanges textes directs entre participants" msgstr "" -#: web/flaskr/forms.py:144 +#: web/b3desk/forms.py:144 msgid "Désactivation de la discussion publique" msgstr "" -#: web/flaskr/forms.py:145 +#: web/b3desk/forms.py:145 msgid "Pas de tchat" msgstr "" -#: web/flaskr/forms.py:149 +#: web/b3desk/forms.py:149 msgid "Désactivation de la prise de notes" msgstr "" -#: web/flaskr/forms.py:150 +#: web/b3desk/forms.py:150 msgid "Pas de prise de notes collaborative" msgstr "" -#: web/flaskr/forms.py:154 +#: web/b3desk/forms.py:154 msgid "Message à l'attention des modérateurs" msgstr "" -#: web/flaskr/forms.py:155 +#: web/b3desk/forms.py:155 msgid "150 caractères max" msgstr "" -#: web/flaskr/forms.py:156 +#: web/b3desk/forms.py:156 msgid "Bienvenue aux modérateurs" msgstr "" -#: web/flaskr/forms.py:158 +#: web/b3desk/forms.py:158 msgid "Le message est trop long" msgstr "" -#: web/flaskr/forms.py:163 +#: web/b3desk/forms.py:163 #, python-format msgid "Url de redirection après %(the_meeting)s" msgstr "" -#: web/flaskr/forms.py:170 +#: web/b3desk/forms.py:170 msgid "Renouveler le lien modérateur" msgstr "" -#: web/flaskr/forms.py:171 web/flaskr/forms.py:180 +#: web/b3desk/forms.py:171 web/b3desk/forms.py:180 msgid "Ce code vous permet si vous le changez de bloquer les anciens liens" msgstr "" -#: web/flaskr/forms.py:179 +#: web/b3desk/forms.py:179 msgid "Renouveler le lien participants" msgstr "" -#: web/flaskr/forms.py:191 +#: web/b3desk/forms.py:191 msgid "Enregistrement manuel" msgstr "" -#: web/flaskr/forms.py:192 +#: web/b3desk/forms.py:192 msgid "Autoriser le démarrage et l'arrêt de l'enregistrement par le modérateur" msgstr "" -#: web/flaskr/forms.py:198 +#: web/b3desk/forms.py:198 msgid "Enregistrement automatique" msgstr "" -#: web/flaskr/forms.py:199 +#: web/b3desk/forms.py:199 msgid "Démarrage automatique" msgstr "" -#: web/flaskr/routes.py:548 +#: web/b3desk/routes.py:548 msgid "" "Courriel invalide. Avez vous bien tapé votre email ? Vous pouvez " "réessayer." msgstr "" -#: web/flaskr/routes.py:556 +#: web/b3desk/routes.py:556 msgid "" "Ce courriel ne correspond pas à un service de l'État. Si vous appartenez " "à un service de l'État mais votre courriel n'est pas reconnu par " "Webinaire, contactez-nous pour que nous le rajoutions!" msgstr "" -#: web/flaskr/routes.py:568 +#: web/b3desk/routes.py:568 msgid "Vous avez reçu un courriel pour vous connecter" msgstr "" -#: web/flaskr/routes.py:623 web/flaskr/routes.py:653 +#: web/b3desk/routes.py:623 web/b3desk/routes.py:653 msgid "Vous ne pouvez pas voir cet élément (identifiant incorrect)" msgstr "" -#: web/flaskr/routes.py:643 web/flaskr/routes.py:676 +#: web/b3desk/routes.py:643 web/b3desk/routes.py:676 msgid "Vous ne pouvez pas consulter cet élément" msgstr "" -#: web/flaskr/routes.py:805 +#: web/b3desk/routes.py:805 msgid "Vous ne pouvez pas modifier cet élément" msgstr "" -#: web/flaskr/routes.py:1264 +#: web/b3desk/routes.py:1264 #, python-format msgid "%(meeting_name)s modifications prises en compte" msgstr "" -#: web/flaskr/routes.py:1427 web/flaskr/routes.py:1474 +#: web/b3desk/routes.py:1427 web/b3desk/routes.py:1474 #, python-format msgid "Aucune %(meeting_label)s ne correspond à ces paramètres" msgstr "" -#: web/flaskr/routes.py:1437 web/flaskr/routes.py:1589 +#: web/b3desk/routes.py:1437 web/b3desk/routes.py:1589 msgid "Lien invalide" msgstr "" -#: web/flaskr/routes.py:1442 web/flaskr/routes.py:1594 +#: web/b3desk/routes.py:1442 web/b3desk/routes.py:1594 msgid "Lien expiré" msgstr "" -#: web/flaskr/routes.py:1581 +#: web/b3desk/routes.py:1581 #, python-format msgid "%(meeting_label)s inexistante" msgstr "" -#: web/flaskr/routes.py:1638 +#: web/b3desk/routes.py:1638 msgid "Accès non autorisé" msgstr "" -#: web/flaskr/routes.py:1669 +#: web/b3desk/routes.py:1669 msgid "Élément supprimé" msgstr "" -#: web/flaskr/routes.py:1671 +#: web/b3desk/routes.py:1671 msgid "Vous ne pouvez pas supprimer cet élément" msgstr "" -#: web/flaskr/routes.py:1687 +#: web/b3desk/routes.py:1687 msgid "Vidéo supprimée" msgstr "" -#: web/flaskr/routes.py:1691 +#: web/b3desk/routes.py:1691 #, python-format msgid "Nous n'avons pas pu supprimer cette vidéo : %(code)s, %(message)s" msgstr "" -#: web/flaskr/routes.py:1700 +#: web/b3desk/routes.py:1700 msgid "Vous ne pouvez pas supprimer cette enregistrement" msgstr "" -#: web/flaskr/templates/brand.html:19 +#: web/b3desk/templates/brand.html:19 #, python-format msgid "%(service_title)s" msgstr "" -#: web/flaskr/templates/brand.html:26 +#: web/b3desk/templates/brand.html:26 #, python-format msgid "%(service_tagline)s" msgstr "" -#: web/flaskr/templates/content.py:6 +#: web/b3desk/templates/content.py:6 msgid "Quelles sont les conditions d’accès pour accéder aux services ?" msgstr "" -#: web/flaskr/templates/content.py:9 +#: web/b3desk/templates/content.py:9 msgid "" "Cette plateforme offre une solution complète et puissante, adaptée à de " "nombreux types d’événements en ligne, jusqu’à 350 participants " @@ -313,11 +313,11 @@ msgid "" "- Sur Android, utiliser le navigateur Chrome par défaut (Android 6.0+)\n" msgstr "" -#: web/flaskr/templates/content.py:33 +#: web/b3desk/templates/content.py:33 msgid "Quel est le matériel nécessaire ?" msgstr "" -#: web/flaskr/templates/content.py:34 +#: web/b3desk/templates/content.py:34 msgid "" "Pour utiliser l’outil Webinaire de l’État, il vous suffit de disposer du " "matériel suivant :\n" @@ -339,11 +339,11 @@ msgid "" "contexte d’intervention." msgstr "" -#: web/flaskr/templates/content.py:46 +#: web/b3desk/templates/content.py:46 msgid "Puis-je utiliser mon smartphone ou ma tablette pour me connecter ?" msgstr "" -#: web/flaskr/templates/content.py:49 +#: web/b3desk/templates/content.py:49 msgid "" "Le Webinaire de l’Etat fonctionne également sur les appareils mobiles par" " un simple lien (sans application) sur le portail ou dans le séminaire. " @@ -351,11 +351,11 @@ msgid "" "Sur Android, utiliser le navigateur chrome par défaut (Android 6.0+).\n" msgstr "" -#: web/flaskr/templates/content.py:55 +#: web/b3desk/templates/content.py:55 msgid "Comment créer un séminaire ?" msgstr "" -#: web/flaskr/templates/content.py:56 +#: web/b3desk/templates/content.py:56 msgid "" "Si vous êtes un agent de l’état, vous pouvez :\n" "- Créer des séminaires immédiatement en renseignant votre courriel " @@ -371,11 +371,11 @@ msgid "" "contact@webinaire.numerique.gouv.fr \n" msgstr "" -#: web/flaskr/templates/content.py:67 +#: web/b3desk/templates/content.py:67 msgid "Comment créer un compte ?" msgstr "" -#: web/flaskr/templates/content.py:68 +#: web/b3desk/templates/content.py:68 msgid "" "En tant qu’agent de l’État, si vous organisez régulièrement des " "séminaires vous pouvez créer un compte pour organiser et conserver " @@ -388,11 +388,11 @@ msgid "" "en grand nombre, …etc.)." msgstr "" -#: web/flaskr/templates/content.py:75 +#: web/b3desk/templates/content.py:75 msgid "Comment inviter les participants/ modérateurs" msgstr "" -#: web/flaskr/templates/content.py:76 +#: web/b3desk/templates/content.py:76 msgid "" "L’organisateur qui a créé le séminaire peut partager le lien :\n" "« Participants » qu’ils soient de l’administration ou de l’extérieur " @@ -400,11 +400,11 @@ msgid "" "« Organisateurs/modérateurs » qui géreront avec vous le séminaire." msgstr "" -#: web/flaskr/templates/content.py:83 +#: web/b3desk/templates/content.py:83 msgid "Rejoindre un Webinaire en appel téléphonique ?" msgstr "" -#: web/flaskr/templates/content.py:84 +#: web/b3desk/templates/content.py:84 msgid "" "Une fois dans le séminaire, il est possible d’utiliser aussi son " "téléphone fixe ou mobile pour suivre le séminaire.\n" @@ -419,11 +419,11 @@ msgid "" "téléphone afin d’activer ou de désactiver votre microphone." msgstr "" -#: web/flaskr/templates/content.py:95 +#: web/b3desk/templates/content.py:95 msgid "J'ai des perturbations audio ou vidéo ?" msgstr "" -#: web/flaskr/templates/content.py:96 +#: web/b3desk/templates/content.py:96 msgid "" "\n" "Pour l’audio, rapprochez-vous de votre borne wifi, ou/et coupez votre " @@ -444,85 +444,85 @@ msgid "" "de vous connecter hors VPN.\n" msgstr "" -#: web/flaskr/templates/content.py:110 +#: web/b3desk/templates/content.py:110 msgid "Besoin de contacter l'équipe du Webinaire de l’Etat ?" msgstr "" -#: web/flaskr/templates/content.py:113 +#: web/b3desk/templates/content.py:113 msgid "contact@webinaire.numerique.gouv.fr" msgstr "" -#: web/flaskr/templates/content.py:116 +#: web/b3desk/templates/content.py:116 msgid "Besoin de contacter l'équipe du ministére de l'Éducation nationale ?" msgstr "" -#: web/flaskr/templates/content.py:119 +#: web/b3desk/templates/content.py:119 msgid "" "Rendez-vous sur votre portail d'assistance académique " "https://www.education.gouv.fr/la-messagerie-professionnelle-3446 ou sur " "Apps.education.fr" msgstr "" -#: web/flaskr/templates/empty.html:2 +#: web/b3desk/templates/empty.html:2 msgid "Vous devez vous identifier pour consulter la liste des visioconférences." msgstr "" -#: web/flaskr/templates/faq.html:8 +#: web/b3desk/templates/faq.html:8 msgid "FAQ - Modalités d'accès" msgstr "Ukrainian translation here" -#: web/flaskr/templates/footer.html:12 +#: web/b3desk/templates/footer.html:12 msgid "" "Service proposé par la Direction interministérielle du numérique et la " "Direction du numérique pour l'éducation" msgstr "" -#: web/flaskr/templates/footer.html:15 +#: web/b3desk/templates/footer.html:15 msgid "Le code source est ouvert et les contributions sont bienvenues." msgstr "" -#: web/flaskr/templates/footer.html:16 +#: web/b3desk/templates/footer.html:16 msgid "Voir le code source - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/footer.html:16 +#: web/b3desk/templates/footer.html:16 msgid "Voir le code source" msgstr "" -#: web/flaskr/templates/footer.html:37 +#: web/b3desk/templates/footer.html:37 msgid "Accessibilité : non conforme" msgstr "" -#: web/flaskr/templates/footer.html:40 -#: web/flaskr/templates/footer/mentions_legales.html:10 +#: web/b3desk/templates/footer.html:40 +#: web/b3desk/templates/footer/mentions_legales.html:10 msgid "Mentions légales" msgstr "" -#: web/flaskr/templates/footer.html:43 +#: web/b3desk/templates/footer.html:43 msgid "Données personnelles et cookies" msgstr "" -#: web/flaskr/templates/footer.html:46 web/flaskr/templates/footer/cgu.html:10 +#: web/b3desk/templates/footer.html:46 web/b3desk/templates/footer/cgu.html:10 msgid "Conditions générales d’utilisation" msgstr "" -#: web/flaskr/templates/jumbotron.html:8 +#: web/b3desk/templates/jumbotron.html:8 #, python-format msgid "Lancer %(a_meeting)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:9 +#: web/b3desk/templates/jumbotron.html:9 #, python-format msgid "Lancer %(the_meeting)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/jumbotron.html:9 +#: web/b3desk/templates/jumbotron.html:9 #, python-format -msgid "Démarrer %(a_meeting)s immédiatement" +msgid "Ouvrir %(a_meeting)s temporaire" msgstr "" -#: web/flaskr/templates/jumbotron.html:19 -#: web/flaskr/templates/jumbotron.html:49 +#: web/b3desk/templates/jumbotron.html:19 +#: web/b3desk/templates/jumbotron.html:49 #, python-format msgid "Actuellement, il y a %(count)s webinaire" msgid_plural "Actuellement, il y a %(count)s webinaires" @@ -530,8 +530,8 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: web/flaskr/templates/jumbotron.html:24 -#: web/flaskr/templates/jumbotron.html:54 +#: web/b3desk/templates/jumbotron.html:24 +#: web/b3desk/templates/jumbotron.html:54 #, python-format msgid "et %(count)s participant" msgid_plural "et %(count)s participants" @@ -539,133 +539,133 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: web/flaskr/templates/jumbotron.html:29 -#: web/flaskr/templates/jumbotron.html:59 +#: web/b3desk/templates/jumbotron.html:29 +#: web/b3desk/templates/jumbotron.html:59 #, python-format msgid "" " sur une capacité moyenne pour la plateforme de %(max_participants)s " "participants." msgstr "" -#: web/flaskr/templates/jumbotron.html:42 +#: web/b3desk/templates/jumbotron.html:42 #, python-format msgid "Vous organisez régulièrement des %(some_meetings)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:43 +#: web/b3desk/templates/jumbotron.html:43 #, python-format msgid "" "Vous êtes agent de l’État, créez un compte pour organiser et conserver " "vos %(some_meetings)s." msgstr "" -#: web/flaskr/templates/jumbotron.html:44 +#: web/b3desk/templates/jumbotron.html:44 msgid "Se connecter ou créer un compte" msgstr "" -#: web/flaskr/templates/jumbotron.html:73 +#: web/b3desk/templates/jumbotron.html:73 #, python-format msgid "Démarrer %(a_meeting)s en ligne immédiatement" msgstr "" -#: web/flaskr/templates/jumbotron.html:83 +#: web/b3desk/templates/jumbotron.html:83 #, python-format msgid "" "Recevez par courriel un lien organisateur %(of_the_meeting)s, actif une " "semaine, à envoyer aux participants." msgstr "" -#: web/flaskr/templates/jumbotron.html:88 +#: web/b3desk/templates/jumbotron.html:88 msgid "Votre courriel professionnel" msgstr "" -#: web/flaskr/templates/jumbotron.html:92 +#: web/b3desk/templates/jumbotron.html:92 #, python-format msgid "Créer %(my_meeting)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:108 +#: web/b3desk/templates/jumbotron.html:108 #, python-format msgid "Vous essayez de rejoindre %(a_meeting)s" msgstr "" -#: web/flaskr/templates/jumbotron.html:109 +#: web/b3desk/templates/jumbotron.html:109 #, python-format msgid "" "Pour rejoindre %(a_meeting_to_which)s vous êtes invité, cliquez sur le " "lien que vous a transmis l'organisateur/modérateur." msgstr "" -#: web/flaskr/templates/redirections.html:4 +#: web/b3desk/templates/redirections.html:4 msgid "Connectez-vous ou créez un compte" msgstr "" -#: web/flaskr/templates/redirections.html:10 +#: web/b3desk/templates/redirections.html:10 msgid "Autres profils" msgstr "" -#: web/flaskr/templates/rie.html:3 +#: web/b3desk/templates/rie.html:3 msgid "Service accessible suivant les politiques de sécurité de votre ministère." msgstr "" -#: web/flaskr/templates/rie.html:4 +#: web/b3desk/templates/rie.html:4 msgid "" "Si l'audio ou la vidéo ne fonctionne pas, vous devez utiliser un autre " "appareil (ordinateur, smartphone)." msgstr "" -#: web/flaskr/templates/rie.html:5 +#: web/b3desk/templates/rie.html:5 msgid "en savoir plus" msgstr "" -#: web/flaskr/templates/tools.html:13 +#: web/b3desk/templates/tools.html:13 #, fuzzy msgid "Modalités d'accès" msgstr "Ukrainian translation here" -#: web/flaskr/templates/tools.html:32 +#: web/b3desk/templates/tools.html:32 msgid "se déconnecter" msgstr "" -#: web/flaskr/templates/tools.html:40 +#: web/b3desk/templates/tools.html:40 msgid "S’identifier" msgstr "" -#: web/flaskr/templates/errors/403.html:11 +#: web/b3desk/templates/errors/403.html:11 msgid "Erreur 403" msgstr "" -#: web/flaskr/templates/errors/403.html:12 +#: web/b3desk/templates/errors/403.html:12 msgid "" "Vous n’êtes pas autorisé à accéder cette page. Vous pouvez retourner à l’accueil." msgstr "" -#: web/flaskr/templates/errors/404.html:11 +#: web/b3desk/templates/errors/404.html:11 msgid "Erreur 404" msgstr "" -#: web/flaskr/templates/errors/404.html:12 +#: web/b3desk/templates/errors/404.html:12 msgid "" "Cette page n'existe pas. Vous pouvez retourner à " "l’accueil." msgstr "" -#: web/flaskr/templates/errors/500.html:11 +#: web/b3desk/templates/errors/500.html:11 msgid "Erreur 500" msgstr "" -#: web/flaskr/templates/errors/500.html:12 +#: web/b3desk/templates/errors/500.html:12 msgid "" "Le serveur a rencontré une erreur interne, veuillez réessayer " "ultérieurement." msgstr "" -#: web/flaskr/templates/footer/accessibilite.html:9 +#: web/b3desk/templates/footer/accessibilite.html:9 msgid "Accessibilité" msgstr "" -#: web/flaskr/templates/footer/accessibilite.html:10 +#: web/b3desk/templates/footer/accessibilite.html:10 msgid "" "Le site webinaire.numerique.gouv.fr est développé selon les " "recommendations du annuaire de l'administration" msgstr "" -#: web/flaskr/templates/footer/cgu.html:11 +#: web/b3desk/templates/footer/cgu.html:11 msgid "" "Le webinaire, Visio-ecoles/colleges/lycees/agents de l’État permet " "d’accéder à la page d’accueil du sous-domaine internet utilisé par l’Etat" @@ -746,7 +746,7 @@ msgid "" "les partenaires du service public." msgstr "" -#: web/flaskr/templates/footer/cgu.html:12 +#: web/b3desk/templates/footer/cgu.html:12 msgid "" "Le sous-domaine « https://visio-" @@ -768,25 +768,25 @@ msgid "" "Nationale, de la Jeunesse et des Sports." msgstr "" -#: web/flaskr/templates/footer/cgu.html:14 +#: web/b3desk/templates/footer/cgu.html:14 msgid "" "Le service est maintenu en conditions opérationnelles et ses évolutions " "sont assurées par le Ministère de l’Éducation Nationale, de la Jeunesse " "et des Sports, ci-après dénommé « l’éditeur »." msgstr "" -#: web/flaskr/templates/footer/cgu.html:15 +#: web/b3desk/templates/footer/cgu.html:15 msgid "" "Toute utilisation des ressources de domaine de publication est " "subordonnée au respect des présentes conditions générales d’utilisation " "(CGU)." msgstr "" -#: web/flaskr/templates/footer/cgu.html:17 +#: web/b3desk/templates/footer/cgu.html:17 msgid "Objet" msgstr "" -#: web/flaskr/templates/footer/cgu.html:18 +#: web/b3desk/templates/footer/cgu.html:18 msgid "" "Le sous-domaine permet de publier sur internet l’offre de service " "interministérielle de webconférence.

    " msgstr "" -#: web/flaskr/templates/footer/cgu.html:19 +#: web/b3desk/templates/footer/cgu.html:19 msgid "Code de conduite et responsabilités des Utilisateurs" msgstr "" -#: web/flaskr/templates/footer/cgu.html:20 +#: web/b3desk/templates/footer/cgu.html:20 msgid "" "L’utilisation de ce service interministériel est libre et gratuite pour " "les utilisateurs des services de l’Etat, et sur invitation, pour les " @@ -810,14 +810,14 @@ msgid "" "et responsabilités de l’éditeur." msgstr "" -#: web/flaskr/templates/footer/cgu.html:21 +#: web/b3desk/templates/footer/cgu.html:21 msgid "" "Sitôt entré sur la page d’accueil, l’utilisateur peut en consulter les " "contenus ou accéder à un salon en saisissant le nom de ce salon ou, pour " "les agents de l’Etat, en créant ledit salon." msgstr "" -#: web/flaskr/templates/footer/cgu.html:22 +#: web/b3desk/templates/footer/cgu.html:22 msgid "" "À l’instant où l’utilisateur accède à un salon de webconférence, il " "devient seul responsable des données et des contenus qu’il échange sur le" @@ -825,17 +825,17 @@ msgid "" "netiquette." msgstr "" -#: web/flaskr/templates/footer/cgu.html:23 +#: web/b3desk/templates/footer/cgu.html:23 msgid "Usage professionnel" msgstr "" -#: web/flaskr/templates/footer/cgu.html:24 +#: web/b3desk/templates/footer/cgu.html:24 msgid "" "Le service de Webinaire, Visio-ecoles/colleges/lycees/agents mis à " "disposition est à usage professionnel." msgstr "" -#: web/flaskr/templates/footer/cgu.html:25 +#: web/b3desk/templates/footer/cgu.html:25 msgid "" "Seule l’utilisation à usage professionnel de cette ressource mise à " "disposition est tolérée, l’utilisateur est attentif à ce que ces usages " @@ -843,11 +843,11 @@ msgid "" "service auquel il accède." msgstr "" -#: web/flaskr/templates/footer/cgu.html:26 +#: web/b3desk/templates/footer/cgu.html:26 msgid "Engagements et responsabilités de l’éditeur" msgstr "" -#: web/flaskr/templates/footer/cgu.html:27 +#: web/b3desk/templates/footer/cgu.html:27 msgid "" "L’éditeur donne accès au service interministériel de webconférence aux " "adresses suivantes : (\n" "56 rue de Varenne
    \n" "75007 Paris" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:95 +#: web/b3desk/templates/footer/donnees_personnelles.html:95 msgid "" "Si vous estimez, après nous avoir contactés, que vos droits Informatiques" " et Libertés ne sont pas respectés vous pouvez adresser une réclamation à" " la CNIL :" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:96 +#: web/b3desk/templates/footer/donnees_personnelles.html:96 msgid "" "Commission nationale informatique et libertés
    \n" "3 place de Fontenoy – TSA 80715 –
    \n" "75334 PARIS CEDEX 07" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:100 +#: web/b3desk/templates/footer/donnees_personnelles.html:100 msgid "" "Les modalités de réclamation sont précisées sur le site de la CNIL : " "www.cnil.fr." msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:102 +#: web/b3desk/templates/footer/donnees_personnelles.html:102 msgid "" "Contactez le Délégué à la protection des données pour les services " "Écoles/Colléges/Lycées/Agents" msgstr "" -#: web/flaskr/templates/footer/donnees_personnelles.html:103 +#: web/b3desk/templates/footer/donnees_personnelles.html:103 msgid "" "Pour ce faire, envoyez un courriel à " "dpd[chez]education.gouv.fr" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:11 +#: web/b3desk/templates/footer/mentions_legales.html:11 msgid "Éditeur" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:12 +#: web/b3desk/templates/footer/mentions_legales.html:12 msgid "" "Ministère de l’Éducation nationale et de la jeunesse Direction du " "numérique pour l’éducation 110 rue Grenelle, 75007 Paris" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:12 +#: web/b3desk/templates/footer/mentions_legales.html:12 msgid "Directeur de publication" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:13 +#: web/b3desk/templates/footer/mentions_legales.html:13 msgid "Directeur de la publication" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:14 +#: web/b3desk/templates/footer/mentions_legales.html:14 msgid "M. Audran Le Baron, Directeur du numérique pour l’éducation" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:15 +#: web/b3desk/templates/footer/mentions_legales.html:15 msgid "Gestionnaire des statistiques" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:16 +#: web/b3desk/templates/footer/mentions_legales.html:16 msgid "Il n’y a pas d’outil de mesure d’audience pour ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:17 +#: web/b3desk/templates/footer/mentions_legales.html:17 msgid "Conception et gestion du site" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:18 +#: web/b3desk/templates/footer/mentions_legales.html:18 msgid "" "Le suivi éditorial, graphique et technique du site est assuré au " "quotidien par les équipes de la DINUM et du Pôle de compétence Identité " "du MENJS." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:19 +#: web/b3desk/templates/footer/mentions_legales.html:19 msgid "Droits de reproduction" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:20 +#: web/b3desk/templates/footer/mentions_legales.html:20 msgid "" "Conformément au droit public de la propriété intellectuelle et notamment " "selon l’article L122-5 du Code de la propriété intellectuelle, les " "’’documents officiels’’ sont librement réutilisables." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:21 +#: web/b3desk/templates/footer/mentions_legales.html:21 msgid "" "Cependant, le bon usage veut que la reprise de ces contenus de façon " "partielle ou intégrale mentionne clairement la source, et le cas échéant " "avec un lien vers le document original en ligne sur ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:22 +#: web/b3desk/templates/footer/mentions_legales.html:22 msgid "" "Toutes les infographies et vidéos réalisées par le service de " "communication de l’éditeur se trouvent sous « Licence Ouverte V2.0 » et " "sont librement réutilisables sous les conditions suivantes :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:23 +#: web/b3desk/templates/footer/mentions_legales.html:23 msgid "" "Attribution : vous devez attribuer l’œuvre de la manière indiquée par " "l’auteur de l’œuvre ou le titulaire des droits (mais pas d’une manière " @@ -1361,32 +1361,32 @@ msgid "" "l’œuvre)." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:24 +#: web/b3desk/templates/footer/mentions_legales.html:24 msgid "Liens hypertextes pointant vers ce site :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:25 +#: web/b3desk/templates/footer/mentions_legales.html:25 msgid "" "Tout site public ou privé est autorisé à établir, sans autorisation " "préalable, un lien (y compris profond) vers les informations diffusées " "par ce site de webinaire, Visio-ecoles/colleges/lycees/agents." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:26 +#: web/b3desk/templates/footer/mentions_legales.html:26 msgid "" "Pour les sites Internet, la reproduction, après autorisation, d’un " "contenu doit mentionner très clairement l’origine du document sous forme " "d’une adresse internet :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:27 +#: web/b3desk/templates/footer/mentions_legales.html:27 msgid "" "La mise en place de “liens profonds” pointant directement sur le document" " souhaité devra être privilégiée par rapport à la reproduction de " "contenus." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:28 +#: web/b3desk/templates/footer/mentions_legales.html:28 msgid "" "En effet, dans ce cas, la mise en place de liens vers ce site de " "Webinaire/Visio-ecoles/colleges/lycees/agents n’est conditionnée à aucun " @@ -1394,20 +1394,20 @@ msgid "" "du lien est recommandée." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:29 +#: web/b3desk/templates/footer/mentions_legales.html:29 msgid "" "Les sites qui font le choix de pointer vers ce site de Webinaire, Visio-" "ecoles/colleges/lycees/agents engagent leur responsabilité dès lors " "qu’ils porteraient atteinte à l’image du site public." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:30 +#: web/b3desk/templates/footer/mentions_legales.html:30 msgid "" "Liens hypertextes proposés par ce site de Webinaire, Visio-" "ecoles/colleges/lycees/agents :" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:31 +#: web/b3desk/templates/footer/mentions_legales.html:31 msgid "" "Les liens vers chaque service interministériel référencé dans le " "catalogue que proposé par de ce site. Leur présence engage l’éditeur et " @@ -1417,43 +1417,43 @@ msgid "" "disposition au plan interministériel." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:32 +#: web/b3desk/templates/footer/mentions_legales.html:32 msgid "Clause de responsabilité" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:33 +#: web/b3desk/templates/footer/mentions_legales.html:33 msgid "" "Les informations proposées sur ce site le sont à titre de service rendu " "aux agents du service public, notamment aux agents des services de " "l’État." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:34 +#: web/b3desk/templates/footer/mentions_legales.html:34 msgid "" "Les informations et/ou documents disponibles sur ce site sont " "susceptibles d’être modifiés à tout moment, et peuvent faire l’objet de " "mises à jour pour faciliter l’accès aux ressources numériques." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:35 +#: web/b3desk/templates/footer/mentions_legales.html:35 msgid "" "Les informations et/ou documents accédés à partir de ce site relèvent de " "la responsabilité des porteurs de chaque service interministériel ainsi " "mis à disposition." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:36 +#: web/b3desk/templates/footer/mentions_legales.html:36 msgid "" "L’éditeur ne pourra en aucun cas être tenue responsable de tout dommage " "de quelque nature qu’il soit résultant de la mauvaise utilisation des " "ressources accessibles à partir de ce site." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:37 +#: web/b3desk/templates/footer/mentions_legales.html:37 msgid "Droit à la compensation" msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:38 +#: web/b3desk/templates/footer/mentions_legales.html:38 msgid "" "Dans l’attente d’une mise en conformité totale d’un de ces services, vous" " pouvez obtenir une version accessible des documents ou des informations " @@ -1463,69 +1463,69 @@ msgid "" "demandées vous seront transmises dans les plus brefs délais." msgstr "" -#: web/flaskr/templates/footer/mentions_legales.html:40 +#: web/b3desk/templates/footer/mentions_legales.html:40 msgid "" "Vous pouvez nous aider à améliorer l’accessibilité du site en nous " "signalant les problèmes éventuels que vous rencontrez. Pour ce faire, " "envoyez-nous un courriel à apps[chez]education.gouv.fr" msgstr "" -#: web/flaskr/templates/meeting/form.html:36 +#: web/b3desk/templates/meeting/form.html:36 msgid "Modifier" msgstr "" -#: web/flaskr/templates/meeting/form.html:38 -#: web/flaskr/templates/meeting/submit.html:5 +#: web/b3desk/templates/meeting/form.html:38 +#: web/b3desk/templates/meeting/submit.html:5 msgid "Créer" msgstr "" -#: web/flaskr/templates/meeting/form.html:43 +#: web/b3desk/templates/meeting/form.html:43 msgid "Enregistrement impossible car certains champs sont mal renseignés." msgstr "" -#: web/flaskr/templates/meeting/form.html:51 +#: web/b3desk/templates/meeting/form.html:51 msgid "Configuration" msgstr "" -#: web/flaskr/templates/meeting/form.html:67 +#: web/b3desk/templates/meeting/form.html:67 msgid "" "Gestion des permissions, elles peuvent être ajustées une fois dans le " "salon" msgstr "" -#: web/flaskr/templates/meeting/form.html:84 +#: web/b3desk/templates/meeting/form.html:84 msgid "Personnalisation" msgstr "" -#: web/flaskr/templates/meeting/form.html:99 +#: web/b3desk/templates/meeting/form.html:99 msgid "Enregistrement" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:3 +#: web/b3desk/templates/meeting/jumbotron.html:3 msgid "Webinaire" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:5 +#: web/b3desk/templates/meeting/jumbotron.html:5 msgid "Nouveau webinaire" msgstr "" -#: web/flaskr/templates/meeting/jumbotron.html:8 +#: web/b3desk/templates/meeting/jumbotron.html:8 msgid "Retour au tableau de bord" msgstr "" -#: web/flaskr/templates/meeting/list.html:2 +#: web/b3desk/templates/meeting/list.html:2 #, python-format msgid "Mes salles de %(some_meetings)s" msgstr "" -#: web/flaskr/templates/meeting/list.html:4 +#: web/b3desk/templates/meeting/list.html:4 #, python-format msgid "" "Créer une salle de %(meeting_label)s
    vous permet de conserver les " "réglages et le lien de la salle." msgstr "" -#: web/flaskr/templates/meeting/list.html:9 +#: web/b3desk/templates/meeting/list.html:9 #, python-format msgid "" "Vous avez atteint la limite des %(max_meetings_per_user)s " @@ -1533,22 +1533,22 @@ msgid "" "des %(meeting_label)ss inactives." msgstr "" -#: web/flaskr/templates/meeting/modals.html:75 +#: web/b3desk/templates/meeting/modals.html:75 #, python-format msgid "" "%(the_meeting)s est toujours en cours. Si un enregistrement est en cours," " il ne sera encodé qu'après la fin %(of_the_meeting)s." msgstr "" -#: web/flaskr/templates/meeting/modals.html:77 -#: web/flaskr/templates/meeting/recordings.html:22 +#: web/b3desk/templates/meeting/modals.html:77 +#: web/b3desk/templates/meeting/recordings.html:22 #, python-format msgid "" "Après la fin d'%(a_meeting)s, l'encodage de l'enregistrement peut prendre" " autant de temps que la durée %(of_the_meeting)s." msgstr "" -#: web/flaskr/templates/meeting/modals.html:78 +#: web/b3desk/templates/meeting/modals.html:78 #, python-format msgid "" "Si aucun modérateur ne met fin %(to_the_meeting)s, un délai " @@ -1556,54 +1556,54 @@ msgid "" "utilisateurs l'aient quitté." msgstr "" -#: web/flaskr/templates/meeting/modals.html:84 +#: web/b3desk/templates/meeting/modals.html:84 msgid "Images" msgstr "" -#: web/flaskr/templates/meeting/modals.html:85 +#: web/b3desk/templates/meeting/modals.html:85 msgid "Lien" msgstr "" -#: web/flaskr/templates/meeting/modals.html:105 -#: web/flaskr/templates/meeting/modals.html:106 -#: web/flaskr/templates/meeting/recordings.html:71 -#: web/flaskr/templates/meeting/recordings.html:72 +#: web/b3desk/templates/meeting/modals.html:105 +#: web/b3desk/templates/meeting/modals.html:106 +#: web/b3desk/templates/meeting/recordings.html:71 +#: web/b3desk/templates/meeting/recordings.html:72 #, python-format msgid "Supprimer video de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/modals.html:108 -#: web/flaskr/templates/meeting/recordings.html:74 +#: web/b3desk/templates/meeting/modals.html:108 +#: web/b3desk/templates/meeting/recordings.html:74 msgid "Suppression d'enregistrement" msgstr "" -#: web/flaskr/templates/meeting/modals.html:111 +#: web/b3desk/templates/meeting/modals.html:111 msgid "Copier le lien de l'enregistrement dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:11 +#: web/b3desk/templates/meeting/recordings.html:11 #, python-format msgid "Enregistrements de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:13 +#: web/b3desk/templates/meeting/recordings.html:13 #, python-format msgid "Retour à mes %(meeting_label)ss" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:18 +#: web/b3desk/templates/meeting/recordings.html:18 #, python-format msgid "%(this_meeting)s est toujours en cours" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:19 +#: web/b3desk/templates/meeting/recordings.html:19 #, python-format msgid "" "Si un enregistrement est en cours, il ne sera encodé qu'après la fin " "%(of_the_meeting)s" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:23 +#: web/b3desk/templates/meeting/recordings.html:23 #, python-format msgid "" "Si aucun modérateur ne met fin %(of_the_meeting)s, un délai " @@ -1611,199 +1611,199 @@ msgid "" "utilisateurs l'aient quitté." msgstr "" -#: web/flaskr/templates/meeting/recordings.html:42 +#: web/b3desk/templates/meeting/recordings.html:42 msgid "Visuels" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:43 +#: web/b3desk/templates/meeting/recordings.html:43 msgid "Actions" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:76 -#: web/flaskr/templates/meeting/row.html:29 -#: web/flaskr/templates/meeting/row.html:40 -#: web/flaskr/templates/meeting/row.html:59 +#: web/b3desk/templates/meeting/recordings.html:76 +#: web/b3desk/templates/meeting/row.html:29 +#: web/b3desk/templates/meeting/row.html:40 +#: web/b3desk/templates/meeting/row.html:59 msgid "Fermer la fenêtre modale" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:91 +#: web/b3desk/templates/meeting/recordings.html:91 msgid "Supprimer" msgstr "" -#: web/flaskr/templates/meeting/recordings.html:92 -#: web/flaskr/templates/meeting/submit.html:7 +#: web/b3desk/templates/meeting/recordings.html:92 +#: web/b3desk/templates/meeting/submit.html:7 msgid "Annuler" msgstr "" -#: web/flaskr/templates/meeting/row.html:5 -#: web/flaskr/templates/meeting/row.html:33 +#: web/b3desk/templates/meeting/row.html:5 +#: web/b3desk/templates/meeting/row.html:33 #, python-format msgid "Lancer %(meeting_name)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/meeting/row.html:7 +#: web/b3desk/templates/meeting/row.html:7 msgid "Envoyer un courriel aux modérateurs" msgstr "" -#: web/flaskr/templates/meeting/row.html:9 +#: web/b3desk/templates/meeting/row.html:9 msgid "Copier le lien Modérateur dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/row.html:13 +#: web/b3desk/templates/meeting/row.html:13 #, python-format msgid "Participer à %(meeting_name)s - nouvelle fenêtre" msgstr "" -#: web/flaskr/templates/meeting/row.html:15 +#: web/b3desk/templates/meeting/row.html:15 msgid "Envoyer un courriel aux participants" msgstr "" -#: web/flaskr/templates/meeting/row.html:17 +#: web/b3desk/templates/meeting/row.html:17 msgid "Copier le lien Participant dans le presse-papiers" msgstr "" -#: web/flaskr/templates/meeting/row.html:20 -#: web/flaskr/templates/meeting/row.html:50 +#: web/b3desk/templates/meeting/row.html:20 +#: web/b3desk/templates/meeting/row.html:50 #, python-format msgid "Modifier %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:24 -#: web/flaskr/templates/meeting/row.html:25 -#: web/flaskr/templates/meeting/row.html:27 -#: web/flaskr/templates/meeting/row.html:54 -#: web/flaskr/templates/meeting/row.html:55 -#: web/flaskr/templates/meeting/row.html:57 +#: web/b3desk/templates/meeting/row.html:24 +#: web/b3desk/templates/meeting/row.html:25 +#: web/b3desk/templates/meeting/row.html:27 +#: web/b3desk/templates/meeting/row.html:54 +#: web/b3desk/templates/meeting/row.html:55 +#: web/b3desk/templates/meeting/row.html:57 #, python-format msgid "Supprimer %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:33 +#: web/b3desk/templates/meeting/row.html:33 msgid "Lancer" msgstr "" -#: web/flaskr/templates/meeting/row.html:36 -#: web/flaskr/templates/meeting/row.html:38 +#: web/b3desk/templates/meeting/row.html:36 +#: web/b3desk/templates/meeting/row.html:38 #, python-format msgid "Inviter à %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/row.html:41 +#: web/b3desk/templates/meeting/row.html:41 msgid "Inviter" msgstr "" -#: web/flaskr/templates/meeting/row.html:46 +#: web/b3desk/templates/meeting/row.html:46 #, python-format msgid "Voir les enregistrements de %(meeting_name)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:1 -#: web/flaskr/templates/meeting/signinmail.html:1 +#: web/b3desk/templates/meeting/signin.html:1 +#: web/b3desk/templates/meeting/signinmail.html:1 #, python-format msgid "Rejoindre %(the_meeting)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:16 +#: web/b3desk/templates/meeting/signin.html:16 #, python-format msgid "%(meeting_attente)s" msgstr "" -#: web/flaskr/templates/meeting/signin.html:24 -#: web/flaskr/templates/meeting/signinmail.html:16 +#: web/b3desk/templates/meeting/signin.html:24 +#: web/b3desk/templates/meeting/signinmail.html:16 msgid "Votre nom" msgstr "" -#: web/flaskr/templates/meeting/signin.html:25 -#: web/flaskr/templates/meeting/signinmail.html:17 +#: web/b3desk/templates/meeting/signin.html:25 +#: web/b3desk/templates/meeting/signinmail.html:17 msgid "Vous pouvez également préciser votre service ou votre fonction." msgstr "" -#: web/flaskr/templates/meeting/signin.html:44 -#: web/flaskr/templates/meeting/signinmail.html:23 +#: web/b3desk/templates/meeting/signin.html:44 +#: web/b3desk/templates/meeting/signinmail.html:23 msgid "Rejoindre" msgstr "" -#: web/flaskr/templates/meeting/signinmail.html:10 +#: web/b3desk/templates/meeting/signinmail.html:10 #, python-format msgid "Votre %(meeting_label)s n'a pas encore été activée par un modérateur" msgstr "" -#: web/flaskr/templates/meeting/submit.html:3 +#: web/b3desk/templates/meeting/submit.html:3 msgid "Enregistrer" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:4 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:4 msgid "Modérateur" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:6 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:6 msgid "Participant" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:9 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:9 #, python-format msgid "À %(the_meeting)s suivante :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:13 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:13 msgid "Le lien pour s'y inscrire est le suivant :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:21 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:21 #, python-format msgid "Le mot de passe de %(this_meeting)s est :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_body.txt:29 +#: web/b3desk/templates/meeting/mailto/mail_body.txt:29 msgid "Vous devez rentrer votre nom complet et le mot de passe pour y accéder." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:2 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:2 msgid "Bonjour," msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:5 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:5 #, python-format msgid "" "Vous avez demandé l’organisation d’%(a_quick_meeting)s au travers du " "webinaire de l’Etat." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:8 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:8 msgid "" "Le lien du webinaire que vous trouvez ci-dessous reste actif et " "accessible pendant une semaine depuis un navigateur internet sur un " "ordinateur ou un smartphone :" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:11 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:11 #, python-format msgid "" "%(moderator_mail_signin_url)s" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:14 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:14 msgid "" "Vous pouvez dès à présent transmettre ce lien de connexion aux " "participants que vous souhaitez inviter." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:17 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:17 msgid "" "Une fois sur la page d’accueil, vous êtes invité à rentrer votre nom " "complet pour accéder au webinaire." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:20 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:20 msgid "Vous y êtes !" msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:23 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:23 msgid "L’équipe du webinaire de l’Etat vous souhaite un excellent séminaire." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_quick_meeting_body.txt:26 +#: web/b3desk/templates/meeting/mailto/mail_quick_meeting_body.txt:26 #, python-format msgid "" "Si vous organisez régulièrement des %(meeting_label)ss, nous vous " @@ -1812,7 +1812,7 @@ msgid "" "mesure." msgstr "" -#: web/flaskr/templates/meeting/mailto/mail_subject.txt:1 +#: web/b3desk/templates/meeting/mailto/mail_subject.txt:1 msgid "Invitation" msgstr "" @@ -1854,20 +1854,20 @@ msgstr "" #: web/instance/config.py:185 msgid "" -"Créez un cours immédiatement avec des réglages standards. Ce cours ne " -"sera pas enregistré dans votre liste de salons." +"Créez en un clic un cours aux réglages standards. " +"Il ne sera pas enregistré dans votre liste de salles." msgstr "" #: web/instance/config.py:188 msgid "" -"Créez une réunion immédiatement avec des réglages standards. Cette " -"réunion ne sera pas enregistrée dans votre liste de salons." +"Créez en un clic une réunion aux réglages standards. " +"Elle ne sera pas enregistrée dans votre liste de salles." msgstr "" #: web/instance/config.py:191 msgid "" -"Créez un séminaire immédiatement avec des réglages standards. Ce " -"séminaire ne sera pas enregistré dans votre liste de salons." +"Créez en un clic un séminaire aux réglages standards. " +"Il ne sera pas enregistré dans votre liste de salles." msgstr "" #: web/instance/config.py:196 @@ -2337,4 +2337,3 @@ msgstr "" #~ " \n" #~ "« Organisateurs/modérateurs » qui géreront avec vous le séminaire." #~ msgstr "" -