diff --git a/poetry.lock b/poetry.lock index fb3954b1..30067803 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "alembic" version = "1.10.4" description = "A database migration tool for SQLAlchemy." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -26,7 +25,6 @@ tz = ["python-dateutil"] name = "amqp" version = "5.1.1" description = "Low-level AMQP client for Python (fork of amqplib)." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -37,11 +35,24 @@ files = [ [package.dependencies] vine = ">=5.0.0" +[[package]] +name = "annotated-types" +version = "0.5.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.7" +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"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + [[package]] name = "async-timeout" version = "4.0.2" description = "Timeout context manager for asyncio programs" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -53,7 +64,6 @@ files = [ name = "babel" version = "2.12.1" description = "Internationalization utilities" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -64,29 +74,10 @@ files = [ [package.dependencies] pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} -[[package]] -name = "beaker" -version = "1.12.1" -description = "A Session and Caching library with WSGI Middleware" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "Beaker-1.12.1.tar.gz", hash = "sha256:57770b40956e6c5cf1d8221dc59519029e470080ed8d3065c4e6ab36ce7e3c81"}, -] - -[package.extras] -crypto = ["pycryptopp (>=0.5.12)"] -cryptography = ["cryptography"] -pycrypto = ["pycrypto"] -pycryptodome = ["pycryptodome"] -testsuite = ["Mock", "coverage", "cryptography", "pycryptodome", "pylibmc", "pymongo", "pytest", "python-memcached", "redis", "sqlalchemy", "webtest"] - [[package]] name = "beautifulsoup4" version = "4.12.2" description = "Screen-scraping library" -category = "dev" optional = false python-versions = ">=3.6.0" files = [ @@ -105,7 +96,6 @@ lxml = ["lxml"] name = "billiard" version = "3.6.4.0" description = "Python multiprocessing fork with improvements and bugfixes" -category = "main" optional = false python-versions = "*" files = [ @@ -117,7 +107,6 @@ files = [ name = "black" version = "23.3.0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -167,7 +156,6 @@ uvloop = ["uvloop (>=0.15.2)"] name = "blinker" version = "1.6.2" description = "Fast, simple object-to-object and broadcast signaling" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -179,7 +167,6 @@ files = [ name = "cachelib" version = "0.9.0" description = "A collection of cache libraries in the same API interface." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -191,7 +178,6 @@ files = [ name = "celery" version = "5.2.7" description = "Distributed Task Queue." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -246,7 +232,6 @@ zstd = ["zstandard"] name = "certifi" version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -258,7 +243,6 @@ files = [ name = "cffi" version = "1.14.0" description = "Foreign Function Interface for Python calling C code." -category = "main" optional = false python-versions = "*" files = [ @@ -299,7 +283,6 @@ pycparser = "*" name = "cfgv" version = "3.3.1" description = "Validate configuration and produce human readable error messages." -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -307,23 +290,10 @@ files = [ {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, ] -[[package]] -name = "chardet" -version = "3.0.4" -description = "Universal encoding detector for Python 2 and 3" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, - {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, -] - [[package]] name = "charset-normalizer" version = "2.0.12" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = ">=3.5.0" files = [ @@ -338,7 +308,6 @@ unicode-backport = ["unicodedata2"] name = "click" version = "8.1.3" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -353,7 +322,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "click-didyoumean" version = "0.3.0" description = "Enables git-like *did-you-mean* feature in click" -category = "main" optional = false python-versions = ">=3.6.2,<4.0.0" files = [ @@ -368,7 +336,6 @@ click = ">=7" name = "click-plugins" version = "1.1.1" description = "An extension module for click to enable registering CLI commands via setuptools entry-points." -category = "main" optional = false python-versions = "*" files = [ @@ -386,7 +353,6 @@ dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] name = "click-repl" version = "0.2.0" description = "REPL plugin for Click" -category = "main" optional = false python-versions = "*" files = [ @@ -403,7 +369,6 @@ six = "*" name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -415,7 +380,6 @@ files = [ name = "coverage" version = "7.2.4" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -482,7 +446,6 @@ toml = ["tomli"] name = "cryptography" version = "41.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -524,7 +487,6 @@ test-randomorder = ["pytest-randomly"] name = "defusedxml" version = "0.7.1" description = "XML bomb protection for Python stdlib modules" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -536,7 +498,6 @@ files = [ name = "distlib" version = "0.3.6" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" files = [ @@ -548,7 +509,6 @@ files = [ name = "exceptiongroup" version = "1.1.1" description = "Backport of PEP 654 (exception groups)" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -563,7 +523,6 @@ test = ["pytest (>=6)"] name = "filelock" version = "3.12.0" description = "A platform independent file lock." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -579,7 +538,6 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "p name = "filetype" version = "1.2.0" description = "Infer file type and MIME type of any file/buffer. No external dependencies." -category = "main" optional = false python-versions = "*" files = [ @@ -591,7 +549,6 @@ files = [ name = "flake8" version = "6.0.0" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = ">=3.8.1" files = [ @@ -608,7 +565,6 @@ pyflakes = ">=3.0.0,<3.1.0" name = "flask" version = "2.2.5" description = "A simple framework for building complex web applications." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -631,7 +587,6 @@ dotenv = ["python-dotenv"] name = "flask-babel" version = "2.0.0" description = "Adds i18n/l10n support to Flask applications" -category = "main" optional = false python-versions = "*" files = [ @@ -652,7 +607,6 @@ dev = ["Pallets-Sphinx-Themes", "bumpversion", "ghp-import", "pytest", "pytest-m name = "flask-caching" version = "2.0.2" description = "Adds caching support to Flask applications." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -668,7 +622,6 @@ Flask = "<3" name = "flask-migrate" version = "3.1.0" description = "SQLAlchemy database migrations for Flask applications using Alembic." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -683,26 +636,25 @@ Flask-SQLAlchemy = ">=1.0" [[package]] name = "flask-pyoidc" -version = "3.10.0" +version = "3.14.2" description = "Flask extension for OpenID Connect authentication." -category = "main" optional = false python-versions = "*" files = [ - {file = "Flask_pyoidc-3.10.0-py3-none-any.whl", hash = "sha256:858196f9fb6e5fa2d96c5aca84a1349a85bdffb21378d6acb860fad97d6370f2"}, + {file = "Flask-pyoidc-3.14.2.tar.gz", hash = "sha256:34cf5325f678754e1281904e06263a30595588c2947905625033d992a3d9d35b"}, + {file = "Flask_pyoidc-3.14.2-py3-none-any.whl", hash = "sha256:776eb64fd39d90d59c866d31c7a69b90f4e33e9311801e8ae36e68d6a97590d2"}, ] [package.dependencies] Flask = "*" importlib-resources = "*" -oic = ">=1.2.1" +oic = "1.6.1" requests = "*" [[package]] name = "flask-sqlalchemy" version = "3.0.3" description = "Add SQLAlchemy support to your Flask application." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -718,7 +670,6 @@ SQLAlchemy = ">=1.4.18" name = "flask-uploads" version = "0.2.1" description = "Flexible and efficient upload handling for Flask" -category = "main" optional = false python-versions = "*" files = [ @@ -730,14 +681,13 @@ Flask = ">=0.8.0" [[package]] name = "flask-webtest" -version = "0.1.1" +version = "0.1.3" description = "Utilities for testing Flask applications with WebTest." -category = "dev" optional = false python-versions = "*" files = [ - {file = "Flask-WebTest-0.1.1.tar.gz", hash = "sha256:ae1eda72cc5a350aba1398b349c1c74d0795dda13054b347b33eaacb0737a2f4"}, - {file = "Flask_WebTest-0.1.1-py2.py3-none-any.whl", hash = "sha256:0414ca2cf8a63b37285a8708db874cef786dd3e0f3d203cf87a1b43170f33e50"}, + {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"}, ] [package.dependencies] @@ -750,14 +700,13 @@ tests = ["flask-sqlalchemy"] [[package]] name = "flask-wtf" -version = "1.0.1" +version = "1.1.1" description = "Form rendering, validation, and CSRF protection for Flask with WTForms." -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Flask-WTF-1.0.1.tar.gz", hash = "sha256:34fe5c6fee0f69b50e30f81a3b7ea16aa1492a771fe9ad0974d164610c09a6c9"}, - {file = "Flask_WTF-1.0.1-py3-none-any.whl", hash = "sha256:9d733658c80be551ce7d5bc13c7a7ac0d80df509be1e23827c847d9520f4359a"}, + {file = "Flask-WTF-1.1.1.tar.gz", hash = "sha256:41c4244e9ae626d63bed42ae4785b90667b885b1535d5a4095e1f63060d12aa9"}, + {file = "Flask_WTF-1.1.1-py3-none-any.whl", hash = "sha256:7887d6f1ebb3e17bf648647422f0944c9a469d0fcf63e3b66fb9a83037e38b2c"}, ] [package.dependencies] @@ -772,7 +721,6 @@ email = ["email-validator"] name = "freezegun" version = "1.2.2" description = "Let your Python tests travel through time" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -787,7 +735,6 @@ python-dateutil = ">=2.7" name = "future" version = "0.18.3" description = "Clean single-source support for Python 3 and 2" -category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -798,7 +745,6 @@ files = [ name = "greenlet" version = "2.0.2" description = "Lightweight in-process concurrent programming" -category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" files = [ @@ -872,7 +818,6 @@ test = ["objgraph", "psutil"] name = "gunicorn" version = "20.1.0" description = "WSGI HTTP Server for UNIX" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -893,7 +838,6 @@ tornado = ["tornado (>=0.2)"] name = "identify" version = "2.5.23" description = "File identification library for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -908,7 +852,6 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -920,7 +863,6 @@ files = [ name = "importlib-metadata" version = "6.6.0" description = "Read metadata from Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -940,7 +882,6 @@ testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packag name = "importlib-resources" version = "5.12.0" description = "Read resources from Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -959,7 +900,6 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -971,7 +911,6 @@ files = [ name = "itsdangerous" version = "2.1.2" description = "Safely pass data to untrusted environments and back." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -983,7 +922,6 @@ files = [ name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1001,7 +939,6 @@ i18n = ["Babel (>=2.7)"] name = "kombu" version = "5.2.4" description = "Messaging library for Python." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1033,7 +970,6 @@ zookeeper = ["kazoo (>=1.3.1)"] name = "lxml" version = "4.9.2" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ @@ -1126,7 +1062,6 @@ source = ["Cython (>=0.29.7)"] name = "mako" version = "1.2.4" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1146,7 +1081,6 @@ testing = ["pytest"] name = "markupsafe" version = "2.1.2" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1206,7 +1140,6 @@ files = [ name = "mccabe" version = "0.7.0" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1218,7 +1151,6 @@ files = [ name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1230,7 +1162,6 @@ files = [ name = "netaddr" version = "0.8.0" description = "A network address manipulation library for Python" -category = "main" optional = false python-versions = "*" files = [ @@ -1242,7 +1173,6 @@ files = [ name = "nodeenv" version = "1.7.0" description = "Node.js virtual environment builder" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -1255,29 +1185,28 @@ setuptools = "*" [[package]] name = "oic" -version = "1.4.0" +version = "1.6.1" description = "Python implementation of OAuth2 and OpenID Connect" -category = "main" optional = false -python-versions = "~=3.5" +python-versions = "~=3.7" files = [ - {file = "oic-1.4.0-py3-none-any.whl", hash = "sha256:c1a46dd5f803349f1eea7393d70a3f2bdbc97e73b96f3ebb54843e1dc190f5e4"}, - {file = "oic-1.4.0.tar.gz", hash = "sha256:b82316c4b9633781b8fcb091a7d082ffc863f850a87d8725ead454746aeae677"}, + {file = "oic-1.6.1-py3-none-any.whl", hash = "sha256:fcbf948a22e4d4df66f6bf57d327933f32a7b539640d9b42883457634360ba78"}, + {file = "oic-1.6.1.tar.gz", hash = "sha256:385a1f64bb59519df1e23840530921bf416740240f505ea6d161e331d3d39fad"}, ] [package.dependencies] -beaker = "*" cryptography = "*" defusedxml = "*" mako = "*" pycryptodomex = "*" +pydantic-settings = "*" pyjwkest = ">=1.3.6" requests = "*" -typing-extensions = "*" [package.extras] develop = ["cherrypy (==3.2.4)", "pyOpenSSL"] -docs = ["Sphinx", "alabaster", "sphinx-autobuild"] +docs = ["Sphinx", "alabaster", "autodoc-pydantic", "sphinx-autobuild"] +examples = ["beaker"] ldap-authn = ["python-ldap"] quality = ["bandit", "black", "eradicate", "isort", "mypy", "pylama", "readme-renderer[md]"] testing = ["freezegun", "pytest", "responses", "testfixtures"] @@ -1287,7 +1216,6 @@ types = ["types-requests"] name = "packaging" version = "23.1" description = "Core utilities for Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1299,7 +1227,6 @@ files = [ name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1311,7 +1238,6 @@ files = [ name = "platformdirs" version = "3.5.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1327,7 +1253,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest- name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1343,7 +1268,6 @@ testing = ["pytest", "pytest-benchmark"] name = "pre-commit" version = "3.2.2" description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1362,7 +1286,6 @@ virtualenv = ">=20.10.0" name = "prompt-toolkit" version = "3.0.38" description = "Library for building powerful interactive command lines in Python" -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -1377,7 +1300,6 @@ wcwidth = "*" name = "psycopg2" version = "2.9.3" description = "psycopg2 - Python-PostgreSQL Database Adapter" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1398,7 +1320,6 @@ files = [ name = "pycodestyle" version = "2.10.0" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1410,7 +1331,6 @@ files = [ name = "pycparser" version = "2.21" description = "C parser in Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1422,7 +1342,6 @@ files = [ name = "pycryptodomex" version = "3.17" description = "Cryptographic library for Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1461,11 +1380,157 @@ files = [ {file = "pycryptodomex-3.17.tar.gz", hash = "sha256:0af93aad8d62e810247beedef0261c148790c52f3cd33643791cc6396dd217c1"}, ] +[[package]] +name = "pydantic" +version = "2.0.3" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic-2.0.3-py3-none-any.whl", hash = "sha256:614eb3321eb600c81899a88fa9858b008e3c79e0d4f1b49ab1f516b4b0c27cfb"}, + {file = "pydantic-2.0.3.tar.gz", hash = "sha256:94f13e0dcf139a5125e88283fc999788d894e14ed90cf478bcc2ee50bd4fc630"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.3.0" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.3.0" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-2.3.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:4542c98b8364b976593703a2dda97377433b102f380b61bc3a2cbc2fbdae1d1f"}, + {file = "pydantic_core-2.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9342de50824b40f55d2600f66c6f9a91a3a24851eca39145a749a3dc804ee599"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:539432f911686cb80284c30b33eaf9f4fd9a11e1111fe0dc98fdbdce69b49821"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38a0e7ee65c8999394d92d9c724434cb629279d19844f2b69d9bbc46dc8b8b61"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_armv7l.whl", hash = "sha256:e3ed6834cc005798187a56c248a2240207cb8ffdda1c89e9afda4c3d526c2ea0"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:e72ac299a6bf732a60852d052acf3999d234686755a02ba111e85e7ebf8155b1"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_s390x.whl", hash = "sha256:616b3451b05ca63b8f433c627f68046b39543faeaa4e50d8c6699a2a1e4b85a5"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:adcb9c8848e15c613e483e0b99767ae325af27fe0dbd866df01fe5849d06e6e1"}, + {file = "pydantic_core-2.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:464bf799b422be662e5e562e62beeffc9eaa907d381a9d63a2556615bbda286d"}, + {file = "pydantic_core-2.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4638ebc17de08c2f3acba557efeb6f195c88b7299d8c55c0bb4e20638bbd4d03"}, + {file = "pydantic_core-2.3.0-cp310-none-win32.whl", hash = "sha256:9ff322c7e1030543d35d83bb521b69114d3d150750528d7757544f639def9ad6"}, + {file = "pydantic_core-2.3.0-cp310-none-win_amd64.whl", hash = "sha256:4824eb018f0a4680b1e434697a9bf3f41c7799b80076d06530cbbd212e040ccc"}, + {file = "pydantic_core-2.3.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:0aa429578e23885b3984c49d687cd05ab06f0b908ea1711a8bf7e503b7f97160"}, + {file = "pydantic_core-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20d710c1f79af930b8891bcebd84096798e4387ab64023ef41521d58f21277d3"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:309f45d4d7481d6f09cb9e35c72caa0e50add4a30bb08c04c5fe5956a0158633"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bcfb7be905aa849bd882262e1df3f75b564e2f708b4b4c7ad2d3deaf5410562"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_armv7l.whl", hash = "sha256:85cd9c0af34e371390e3cb2f3a470b0b40cc07568c1e966c638c49062be6352d"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:37c5028cebdf731298724070838fb3a71ef1fbd201d193d311ac2cbdbca25a23"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_s390x.whl", hash = "sha256:e4208f23f12d0ad206a07a489ef4cb15722c10b62774c4460ee4123250be938e"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c24465dd11b65c8510f251b095fc788c7c91481c81840112fe3f76c30793a455"}, + {file = "pydantic_core-2.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3cd7ee8bbfab277ab56e272221886fd33a1b5943fbf45ae9195aa6a48715a8a0"}, + {file = "pydantic_core-2.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0fc7e0b056b66cc536e97ef60f48b3b289f6b3b62ac225afd4b22a42434617bf"}, + {file = "pydantic_core-2.3.0-cp311-none-win32.whl", hash = "sha256:4788135db4bd83a5edc3522b11544b013be7d25b74b155e08dd3b20cd6663bbb"}, + {file = "pydantic_core-2.3.0-cp311-none-win_amd64.whl", hash = "sha256:f93c867e5e85584a28c6a6feb6f2086d717266eb5d1210d096dd717b7f4dec04"}, + {file = "pydantic_core-2.3.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:73f62bb7fd862d9bcd886e10612bade6fe042eda8b47e8c129892bcfb7b45e84"}, + {file = "pydantic_core-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d889d498fce64bfcd8adf1a78579a7f626f825cbeb2956a24a29b35f9a1df32"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d55e38a89ec2ae17b2fa7ffeda6b70f63afab1888bd0d57aaa7b7879760acb4"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1aefebb506bc1fe355d91d25f12bcdea7f4d7c2d9f0f6716dd025543777c99a5"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_armv7l.whl", hash = "sha256:6441a29f42585f085db0c04cd0557d4cbbb46fa68a0972409b1cfe9f430280c1"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_ppc64le.whl", hash = "sha256:47e8f034be31390a8f525431eb5e803a78ce7e2e11b32abf5361a972e14e6b61"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_s390x.whl", hash = "sha256:ad814864aba263be9c83ada44a95f72d10caabbf91589321f95c29c902bdcff0"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9eff3837d447fccf2ac38c259b14ab9cbde700df355a45a1f3ff244d5e78f8b6"}, + {file = "pydantic_core-2.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:534f3f63c000f08050c6f7f4378bf2b52d7ba9214e9d35e3f60f7ad24a4d6425"}, + {file = "pydantic_core-2.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ef6a222d54f742c24f6b143aab088702db3a827b224e75b9dd28b38597c595fe"}, + {file = "pydantic_core-2.3.0-cp312-none-win32.whl", hash = "sha256:4e26944e64ecc1d7b19db954c0f7b471f3b141ec8e1a9f57cfe27671525cd248"}, + {file = "pydantic_core-2.3.0-cp312-none-win_amd64.whl", hash = "sha256:019c5c41941438570dfc7d3f0ae389b2425add1775a357ce1e83ed1434f943d6"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:27c1bbfb9d84a75cf33b7f19b53c29eb7ead99b235fce52aced5507174ab8f98"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:7cb496e934b71f1ade844ab91d6ccac78a3520e5df02fdb2357f85a71e541e69"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5af2d43b1978958d91351afbcc9b4d0cfe144c46c61740e82aaac8bb39ab1a4d"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3097c39d7d4e8dba2ef86de171dcccad876c36d8379415ba18a5a4d0533510"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_armv7l.whl", hash = "sha256:dd3b023f3317dbbbc775e43651ce1a31a9cea46216ad0b5be37afc18a2007699"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:27babb9879bf2c45ed655d02639f4c30e2b9ef1b71ce59c2305bbf7287910a18"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_s390x.whl", hash = "sha256:2183a9e18cdc0de53bdaa1675f237259162abeb62d6ac9e527c359c1074dc55d"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c089d8e7f1b4db08b2f8e4107304eec338df046275dad432635a9be9531e2fc8"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f10aa5452b865818dd0137f568d443f5e93b60a27080a01aa4b7512c7ba13a3"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f642313d559f9d9a00c4de6820124059cc3342a0d0127b18301de2c680d5ea40"}, + {file = "pydantic_core-2.3.0-cp37-none-win32.whl", hash = "sha256:45327fc57afbe3f2c3d7f54a335d5cecee8a9fdb3906a2fbed8af4092f4926df"}, + {file = "pydantic_core-2.3.0-cp37-none-win_amd64.whl", hash = "sha256:e427b66596a6441a5607dfc0085b47d36073f88da7ac48afd284263b9b99e6ce"}, + {file = "pydantic_core-2.3.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:0b3d781c71b8bfb621ef23b9c874933e2cd33237c1a65cc20eeb37437f8e7e18"}, + {file = "pydantic_core-2.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad46027dbd5c1db87dc0b49becbe23093b143a20302028d387dae37ee5ef95f5"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39aa09ed7ce2a648c904f79032d16dda29e6913112af8465a7bf710eef23c7ca"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05b4bf8c58409586a7a04c858a86ab10f28c6c1a7c33da65e0326c59d5b0ab16"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_armv7l.whl", hash = "sha256:ba2b807d2b62c446120906b8580cddae1d76d3de4efbb95ccc87f5e35c75b4b2"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:ea955e4ed21f4bbb9b83fea09fc6af0bed82e69ecf6b35ec89237a0a49633033"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_s390x.whl", hash = "sha256:06884c07956526ac9ebfef40fe21a11605569b8fc0e2054a375fb39c978bf48f"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f868e731a18b403b88aa434d960489ceeed0ddeb44ebc02389540731a67705e0"}, + {file = "pydantic_core-2.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cb08fab0fc1db15c277b72e33ac74ad9c0c789413da8984a3eacb22a94b42ef4"}, + {file = "pydantic_core-2.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6ca34c29fbd6592de5fd39e80c1993634d704c4e7e14ba54c87b2c7c53da68fe"}, + {file = "pydantic_core-2.3.0-cp38-none-win32.whl", hash = "sha256:cd782807d35c8a41aaa7d30b5107784420eefd9fdc1c760d86007d43ae00b15d"}, + {file = "pydantic_core-2.3.0-cp38-none-win_amd64.whl", hash = "sha256:01f56d5ee70b1d39c0fd08372cc5142274070ab7181d17c86035f130eebc05b8"}, + {file = "pydantic_core-2.3.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:78b1ac0151271ce62bc2b33755f1043eda6a310373143a2f27e2bcd3d5fc8633"}, + {file = "pydantic_core-2.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:64bfd2c35a2c350f73ac52dc134d8775f93359c4c969280a6fe5301b5b6e7431"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:937c0fe9538f1212b62df6a68f8d78df3572fe3682d9a0dd8851eac8a4e46063"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d965c7c4b40d1cedec9188782e98bd576f9a04868835604200c3a6e817b824f"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_armv7l.whl", hash = "sha256:ad442b8585ed4a3c2d22e4bf7b465d9b7d281e055b09719a8aeb5b576422dc9b"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:4bf20c9722821fce766e685718e739deeccc60d6bc7be5029281db41f999ee0c"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_s390x.whl", hash = "sha256:f3dd5333049b5b3faa739e0f40b77cc8b7a1aded2f2da0e28794c81586d7b08a"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dc5f516b24d24bc9e8dd9305460899f38302b3c4f9752663b396ef9848557bf"}, + {file = "pydantic_core-2.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:055f7ea6b1fbb37880d66d70eefd22dd319b09c79d2cb99b1dbfeb34b653b0b2"}, + {file = "pydantic_core-2.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:af693a89db6d6ac97dd84dd7769b3f2bd9007b578127d0e7dda03053f4d3b34b"}, + {file = "pydantic_core-2.3.0-cp39-none-win32.whl", hash = "sha256:f60e31e3e15e8c294bf70c60f8ae4d0c3caf3af8f26466e9aa8ea4c01302749b"}, + {file = "pydantic_core-2.3.0-cp39-none-win_amd64.whl", hash = "sha256:2b79f3681481f4424d7845cc7a261d5a4baa810d656b631fa844dc9967b36a7b"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:a666134b41712e30a71afaa26deeb4da374179f769fa49784cdf0e7698880fab"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c119e9227487ad3d7c3c737d896afe548a6be554091f9745da1f4b489c40561"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73929a2fb600a2333fce2efd92596cff5e6bf8946e20e93c067b220760064862"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:41bbc2678a5b6a19371b2cb51f30ccea71f0c14b26477d2d884fed761cea42c7"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dcbff997f47d45bf028bda4c3036bb3101e89a3df271281d392b6175f71c71d1"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:afa8808159169368b66e4fbeafac6c6fd8f26246dc4d0dcc2caf94bd9cf1b828"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:12be3b5f54f8111ca38e6b7277f26c23ba5cb3344fae06f879a0a93dfc8b479e"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ed5babdcd3d052ba5cf8832561f18df20778c7ccf12587b2d82f7bf3bf259a0e"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d642e5c029e2acfacf6aa0a7a3e822086b3b777c70d364742561f9ca64c1ffc"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ba3073eb38a1294e8c7902989fb80a7a147a69db2396818722bd078476586a0"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5146a6749b1905e04e62e0ad4622f079e5582f8b3abef5fb64516c623127908"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:deeb64335f489c3c11949cbd1d1668b3f1fb2d1c6a5bf40e126ef7bf95f9fa40"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:31acc37288b8e69e4849f618c3d5cf13b58077c1a1ff9ade0b3065ba974cd385"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e09d9f6d722de9d4c1c5f122ea9bc6b25a05f975457805af4dcab7b0128aacbf"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ba6a8cf089222a171b8f84e6ec2d10f7a9d14f26be3a347b14775a8741810676"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1fd1b24e9bcddcb168437686677104e205c8e25b066e73ffdf331d3bb8792b"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eda1a89c4526826c0a87d33596a4cd15b8f58e9250f503e39af1699ba9c878e8"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3e9a18401a28db4358da2e191508702dbf065f2664c710708cdf9552b9fa50c"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a439fd0d45d51245bbde799726adda5bd18aed3fa2b01ab2e6a64d6d13776fa3"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:bf6a1d2c920cc9528e884850a4b2ee7629e3d362d5c44c66526d4097bbb07a1a"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e33fcbea3b63a339dd94de0fc442fefacfe681cc7027ce63f67af9f7ceec7422"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:bf3ed993bdf4754909f175ff348cf8f78d4451215b8aa338633f149ca3b1f37a"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7584171eb3115acd4aba699bc836634783f5bd5aab131e88d8eeb8a3328a4a72"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1624baa76d1740711b2048f302ae9a6d73d277c55a8c3e88b53b773ebf73a971"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:06f33f695527f5a86e090f208978f9fd252c9cfc7e869d3b679bd71f7cb2c1fa"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7ecf0a67b212900e92f328181fed02840d74ed39553cdb38d27314e2b9c89dfa"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:45fa1e8ad6f4367ad73674ca560da8e827cc890eaf371f3ee063d6d7366a207b"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8d0dbcc57839831ae79fd24b1b83d42bc9448d79feaf3ed3fb5cbf94ffbf3eb7"}, + {file = "pydantic_core-2.3.0.tar.gz", hash = "sha256:5cfb5ac4e82c47d5dc25b209dd4c3989e284b80109f9e08b33c895080c424b4f"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pydantic-settings" +version = "2.0.2" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_settings-2.0.2-py3-none-any.whl", hash = "sha256:6183a2abeab465d5a3ab69758e9a22d38b0cc2ba193f0b85f6971a252ea630f6"}, + {file = "pydantic_settings-2.0.2.tar.gz", hash = "sha256:342337fff50b23585e807a86dec85037900972364435c55c2fc00d16ff080539"}, +] + +[package.dependencies] +pydantic = ">=2.0.1" +python-dotenv = ">=0.21.0" + [[package]] name = "pyflakes" version = "3.0.1" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1477,7 +1542,6 @@ files = [ name = "pyjwkest" version = "1.4.2" description = "Python implementation of JWT, JWE, JWS and JWK" -category = "main" optional = false python-versions = "*" files = [ @@ -1492,14 +1556,13 @@ six = "*" [[package]] name = "pytest" -version = "7.3.1" +version = "7.4.0" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, - {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, + {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, + {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, ] [package.dependencies] @@ -1511,18 +1574,17 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" -version = "4.0.0" +version = "4.1.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, - {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, ] [package.dependencies] @@ -1536,7 +1598,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-dotenv" version = "0.5.2" description = "A py.test plugin that parses environment files before running tests" -category = "dev" optional = false python-versions = "*" files = [ @@ -1548,16 +1609,34 @@ files = [ 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." +optional = false +python-versions = ">=3.5" +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"}, +] + +[package.dependencies] +Flask = "*" +pytest = ">=5.2" +Werkzeug = ">=0.7" + +[package.extras] +docs = ["Sphinx", "sphinx-rtd-theme"] + [[package]] name = "pytest-mock" -version = "3.10.0" +version = "3.11.1" description = "Thin-wrapper around the mock package for easier use with pytest" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-mock-3.10.0.tar.gz", hash = "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f"}, - {file = "pytest_mock-3.10.0-py3-none-any.whl", hash = "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b"}, + {file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"}, + {file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"}, ] [package.dependencies] @@ -1570,7 +1649,6 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -1585,7 +1663,6 @@ six = ">=1.5" name = "python-dotenv" version = "1.0.0" description = "Read key-value pairs from a .env file and set them as environment variables" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1600,7 +1677,6 @@ cli = ["click (>=5.0)"] name = "pytz" version = "2023.3" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" files = [ @@ -1612,7 +1688,6 @@ files = [ name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1662,7 +1737,6 @@ files = [ name = "redis" version = "4.4.4" description = "Python client for Redis database and key-value store" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1681,7 +1755,6 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1703,7 +1776,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "setuptools" version = "67.7.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1720,7 +1792,6 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1732,7 +1803,6 @@ files = [ name = "soupsieve" version = "2.4.1" description = "A modern CSS selector implementation for Beautiful Soup." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1744,7 +1814,6 @@ files = [ name = "sqlalchemy" version = "1.4.31" description = "Database Abstraction Library" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -1787,7 +1856,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and platform_machine == \"aarch64\" or python_version >= \"3\" and platform_machine == \"ppc64le\" or python_version >= \"3\" and platform_machine == \"x86_64\" or python_version >= \"3\" and platform_machine == \"amd64\" or python_version >= \"3\" and platform_machine == \"AMD64\" or python_version >= \"3\" and platform_machine == \"win32\" or python_version >= \"3\" and platform_machine == \"WIN32\""} +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\")"} [package.extras] aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] @@ -1814,7 +1883,6 @@ sqlcipher = ["sqlcipher3-binary"] name = "sqlalchemy-json" version = "0.4.0" description = "JSON type with nested change tracking for SQLAlchemy" -category = "main" optional = false python-versions = "*" files = [ @@ -1830,7 +1898,6 @@ sqlalchemy = ">=0.7" name = "sqlalchemy-utils" version = "0.38.1" description = "Various utility functions for SQLAlchemy." -category = "main" optional = false python-versions = "~=3.4" files = [ @@ -1860,7 +1927,6 @@ url = ["furl (>=0.4.1)"] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1870,21 +1936,19 @@ files = [ [[package]] name = "typing-extensions" -version = "4.5.0" +version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, - {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] [[package]] name = "urllib3" version = "1.26.15" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -1901,7 +1965,6 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] name = "vine" version = "5.0.0" description = "Promises, promises, promises." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1913,7 +1976,6 @@ files = [ name = "virtualenv" version = "20.23.0" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1934,7 +1996,6 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess name = "waitress" version = "2.1.2" description = "Waitress WSGI server" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -1950,7 +2011,6 @@ testing = ["coverage (>=5.0)", "pytest", "pytest-cover"] name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" -category = "main" optional = false python-versions = "*" files = [ @@ -1962,7 +2022,6 @@ files = [ name = "webdavclient3" version = "3.14.6" description = "WebDAV client, based on original package https://github.com/designerror/webdav-client-python but uses requests instead of PyCURL" -category = "main" optional = false python-versions = "*" files = [ @@ -1978,7 +2037,6 @@ requests = "*" name = "webob" version = "1.8.7" description = "WSGI request and response object" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*" files = [ @@ -1994,7 +2052,6 @@ testing = ["coverage", "pytest (>=3.1.0)", "pytest-cov", "pytest-xdist"] name = "webtest" version = "3.0.0" description = "Helper to test WSGI applications" -category = "dev" optional = false python-versions = ">=3.6, <4" files = [ @@ -2013,27 +2070,25 @@ tests = ["PasteDeploy", "WSGIProxy2", "coverage", "pyquery", "pytest", "pytest-c [[package]] name = "werkzeug" -version = "2.3.4" +version = "2.2.3" description = "The comprehensive WSGI web application library." -category = "main" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "Werkzeug-2.3.4-py3-none-any.whl", hash = "sha256:48e5e61472fee0ddee27ebad085614ebedb7af41e88f687aaf881afb723a162f"}, - {file = "Werkzeug-2.3.4.tar.gz", hash = "sha256:1d5a58e0377d1fe39d061a5de4469e414e78ccb1e1e59c0f5ad6fa1c36c52b76"}, + {file = "Werkzeug-2.2.3-py3-none-any.whl", hash = "sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612"}, + {file = "Werkzeug-2.2.3.tar.gz", hash = "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe"}, ] [package.dependencies] MarkupSafe = ">=2.1.1" [package.extras] -watchdog = ["watchdog (>=2.3)"] +watchdog = ["watchdog"] [[package]] name = "wtforms" version = "3.0.1" description = "Form validation and rendering for Python web development." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2051,7 +2106,6 @@ email = ["email-validator"] name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2066,4 +2120,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "51b112794ce233cba0782dda62ab79326e2d597ea6d8401869529bb2627c2fae" +content-hash = "cc1af9cf28e12423b98cd67f7f2171260c9ea720dccda8f613e88c8a838cf29f" diff --git a/pyproject.toml b/pyproject.toml index 52a142b1..fedbae14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,9 +7,7 @@ readme = "README.md" [tool.poetry.dependencies] python = ">=3.8.1,<4.0" -cffi = "1.14.0" -chardet = "3.0.4" -flask-pyoidc = "3.10.0" +flask-pyoidc = "^3.14.2" flask-sqlalchemy = "^3.0.3" flask-uploads = "0.2.1" flask-migrate = "3.1.0" @@ -23,26 +21,27 @@ webdavclient3 = "3.14.6" filetype = "^1.2.0" flask-babel = "2.0.0" celery = "5.2.7" -flask = "2.2.5" +flask = "<2.3" flask-caching = "^2.0.2" -flask-wtf = "1.0.1" +flask-wtf = "^1.1.1" redis = "4.4.4" requests = "^2.27.1" -werkzeug = "^2.3.4" +werkzeug = "<2.3" [tool.poetry.group.dev] optional = true [tool.poetry.group.dev.dependencies] -pytest = "^7.2.2" -pytest-mock = "^3.10.0" -Flask-WebTest = "^0.1.1" +pytest = "^7.4.0" +pytest-mock = "^3.11.1" +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.0.0" +pytest-cov = "^4.1.0" pytest-dotenv = "^0.5.2" +pytest-flask = "^1.2.0" coverage = "^7.2.2" [build-system] diff --git a/web/flaskr/forms.py b/web/flaskr/forms.py index 3abdbaf7..6518e280 100644 --- a/web/flaskr/forms.py +++ b/web/flaskr/forms.py @@ -22,7 +22,7 @@ class JoinMeetingAsRoleForm(Form): class JoinMeetingForm(FlaskForm): fullname = StringField() meeting_fake_id = StringField() - user_id = StringField() + user_id = IntegerField() h = StringField() fullname_suffix = StringField() diff --git a/web/flaskr/models.py b/web/flaskr/models.py index 6f78fc73..a89e0aef 100755 --- a/web/flaskr/models.py +++ b/web/flaskr/models.py @@ -712,7 +712,7 @@ def get_join_url(self, meeting_role, fullname, fullname_suffix="", create=False) ) return self.bbb.prepare_request_to_join_bbb(meeting_role, nickname).url return url_for( - "waiting_meeting", + "routes.waiting_meeting", meeting_fake_id=self.fake_id, user_id=self.user.id, h=self.get_hash(meeting_role), @@ -722,7 +722,7 @@ def get_join_url(self, meeting_role, fullname, fullname_suffix="", create=False) def get_signin_url(self, meeting_role): return current_app.config["SERVER_FQDN"] + url_for( - "signin_meeting", + "routes.signin_meeting", meeting_fake_id=self.fake_id, user_id=self.user.id, h=self.get_hash(meeting_role), @@ -740,7 +740,7 @@ def get_mail_signin_url(self): ] # remove milliseconds hash_param = self.get_mail_signin_hash(self.fake_id, expiration) return current_app.config["SERVER_FQDN"] + url_for( - "signin_mail_meeting", + "routes.signin_mail_meeting", meeting_fake_id=self.fake_id, expiration=expiration, h=hash_param, @@ -767,8 +767,10 @@ def get_data_as_dict(self, fullname, fetch_recording=False): d["attendee_join_url"] = self.get_join_url("attendee", fullname) return d - def get_role(self, hashed_role): - if self.get_hash("attendee") == hashed_role: + 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" diff --git a/web/flaskr/routes.py b/web/flaskr/routes.py index 2112ec87..ac74e5aa 100755 --- a/web/flaskr/routes.py +++ b/web/flaskr/routes.py @@ -85,7 +85,7 @@ from .templates.content import FAQ_CONTENT -bp = Blueprint("", __name__) +bp = Blueprint("routes", __name__) user_provider_configuration = ProviderConfiguration( @@ -95,6 +95,7 @@ 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"], + post_logout_redirect_uris=[f'{current_app.config.get("SERVER_FQDN")}/logout'], ), auth_request_params={"scope": current_app.config["OIDC_SCOPES"]}, ) @@ -107,6 +108,7 @@ token_endpoint_auth_method=current_app.config.get( "OIDC_ATTENDEE_CLIENT_AUTH_METHOD" ), + post_logout_redirect_uris=[f'{current_app.config.get("SERVER_FQDN")}/logout'], ), auth_request_params={ "scope": current_app.config.get("OIDC_ATTENDEE_SCOPES") @@ -207,6 +209,26 @@ def get_current_user(): 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( @@ -252,8 +274,6 @@ def api_meetings(): user = get_or_create_user(info) fullname = user.fullname stats = get_meetings_stats() - if user is not None: - logged_in = True return { "meetings": [ { @@ -267,7 +287,7 @@ def api_meetings(): # called by NextcloudfilePicker when documents should be added to a running room: -@bp.route("/meeting/files//insertDocuments", methods=["POST"]) +@bp.route("/meeting/files//insertDocuments", methods=["POST"]) @auth.oidc_auth("default") def insertDocuments(meeting_id): from flask import request @@ -317,20 +337,8 @@ def insertDocuments(meeting_id): @bp.route("/mentions_legales") def mentions_legales(): - user_session = UserSession(session, "default") - if user_session.is_authenticated(): - logged_in = True - user = get_current_user() - fullname = user.fullname - else: - user = None - fullname = None - logged_in = False return render_template( "footer/mentions_legales.html", - logged_in=logged_in, - user=user, - fullname=fullname, service_title=current_app.config["SERVICE_TITLE"], service_tagline=current_app.config["SERVICE_TAGLINE"], ) @@ -338,20 +346,8 @@ def mentions_legales(): @bp.route("/cgu") def cgu(): - user_session = UserSession(session, "default") - if user_session.is_authenticated(): - logged_in = True - user = get_current_user() - fullname = user.fullname - else: - user = None - fullname = None - logged_in = False return render_template( "footer/cgu.html", - logged_in=logged_in, - user=user, - fullname=fullname, service_title=current_app.config["SERVICE_TITLE"], service_tagline=current_app.config["SERVICE_TAGLINE"], ) @@ -359,20 +355,8 @@ def cgu(): @bp.route("/donnees_personnelles") def donnees_personnelles(): - user_session = UserSession(session, "default") - if user_session.is_authenticated(): - logged_in = True - user = get_current_user() - fullname = user.fullname - else: - user = None - fullname = None - logged_in = False return render_template( "footer/donnees_personnelles.html", - logged_in=logged_in, - user=user, - fullname=fullname, service_title=current_app.config["SERVICE_TITLE"], service_tagline=current_app.config["SERVICE_TAGLINE"], ) @@ -380,20 +364,8 @@ def donnees_personnelles(): @bp.route("/accessibilite") def accessibilite(): - user_session = UserSession(session, "default") - if user_session.is_authenticated(): - logged_in = True - user = get_current_user() - fullname = user.fullname - else: - user = None - fullname = None - logged_in = False return render_template( "footer/accessibilite.html", - logged_in=logged_in, - user=user, - fullname=fullname, service_title=current_app.config["SERVICE_TITLE"], service_tagline=current_app.config["SERVICE_TAGLINE"], ) @@ -403,51 +375,22 @@ def accessibilite(): def documentation(): if current_app.config["DOCUMENTATION_LINK"]["is_external"]: return redirect(current_app.config["DOCUMENTATION_LINK"]["url"]) - user_session = UserSession(session, "default") - if user_session.is_authenticated(): - logged_in = True - user = get_current_user() - fullname = user.fullname - else: - user = None - fullname = None - logged_in = False return render_template( "footer/documentation.html", - logged_in=logged_in, - user=user, - fullname=fullname, ) @bp.route("/faq") def faq(): - user_session = UserSession(session, "default") - if user_session.is_authenticated(): - logged_in = True - user = get_current_user() - fullname = user.fullname - else: - user = None - fullname = None - logged_in = False return render_template( "faq.html", - logged_in=logged_in, - user=user, contents=FAQ_CONTENT, - fullname=fullname, ) @bp.route("/") def index(): - user_session = UserSession(session, "default") - if user_session.is_authenticated(): - logged_in = True - else: - logged_in = False - if logged_in: + if has_user_session(): return redirect("/welcome") else: return redirect("/home") @@ -475,22 +418,15 @@ def home(): @auth.oidc_auth("default") def welcome(): user = get_current_user() - fullname = user.fullname stats = get_meetings_stats() - if user is not None: - logged_in = True - return render_template( "welcome.html", title=current_app.config["TITLE"], - user=user, - fullname=fullname, stats=stats, max_participants=current_app.config["MAX_PARTICIPANTS"], meetings=[ - add_mailto_links(m.get_data_as_dict(fullname)) for m in user.meetings + add_mailto_links(m.get_data_as_dict(user.fullname)) for m in user.meetings ], - logged_in=logged_in, can_create_meetings=user.can_create_meetings, max_meetings_per_user=current_app.config["MAX_MEETINGS_PER_USER"], mailto=current_app.config["MAILTO_LINKS"], @@ -596,7 +532,7 @@ def quick_meeting(): return redirect(m.get_join_url("moderator", fullname, create=True)) -@bp.route("/meeting/show/", methods=["GET"]) +@bp.route("/meeting/show/", methods=["GET"]) @auth.oidc_auth("default") def show_meeting(meeting_id): form = ShowMeetingForm(data={"meeting_id": meeting_id}) @@ -607,23 +543,17 @@ def show_meeting(meeting_id): ) return redirect("/welcome") user = get_current_user() - fullname = user.fullname - if user is not None: - logged_in = True meeting = Meeting.query.get(meeting_id) if meeting.user_id == user.id: return render_template( "meeting/show.html", - user=user, - fullname=fullname, - meeting=add_mailto_links(meeting.get_data_as_dict(fullname)), - logged_in=logged_in, + 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("/welcome") -@bp.route("/meeting/recordings/", methods=["GET"]) +@bp.route("/meeting/recordings/", methods=["GET"]) @auth.oidc_auth("default") def show_meeting_recording(meeting_id): form = ShowMeetingForm(data={"meeting_id": meeting_id}) @@ -634,26 +564,20 @@ def show_meeting_recording(meeting_id): ) return redirect("/welcome") user = get_current_user() - fullname = user.fullname - if user is not None: - logged_in = True meeting = Meeting.query.get(meeting_id) if meeting.user_id == user.id: - meeting_dict = meeting.get_data_as_dict(fullname, fetch_recording=True) + meeting_dict = meeting.get_data_as_dict(user.fullname, fetch_recording=True) form = RecordingForm() return render_template( "meeting/recordings.html", - user=user, - fullname=fullname, meeting=add_mailto_links(meeting_dict), - logged_in=logged_in, form=form, ) flash(lazy_gettext("Vous ne pouvez pas consulter cet élément"), "warning") return redirect("/welcome") -@bp.route("/meeting//recordings/", methods=["POST"]) +@bp.route("/meeting//recordings/", methods=["POST"]) @auth.oidc_auth("default") def update_recording_name(meeting_id, recording_id): user = get_current_user() @@ -675,17 +599,13 @@ def update_recording_name(meeting_id, recording_id): ) else: flash("Vous ne pouvez pas modifier cet enregistrement", "error") - return redirect(url_for("show_meeting_recording", meeting_id=meeting_id)) + 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() - fullname = user.fullname - if user is not None: - logged_in = True - if not user.can_create_meetings: return redirect("/welcome") @@ -693,22 +613,16 @@ def new_meeting(): return render_template( "meeting/wizard.html", - user=user, - fullname=fullname, meeting=None, form=form, recording=current_app.config["RECORDING"], - logged_in=logged_in, ) -@bp.route("/meeting/edit/", methods=["GET"]) +@bp.route("/meeting/edit/", methods=["GET"]) @auth.oidc_auth("default") def edit_meeting(meeting_id): user = get_current_user() - fullname = user.fullname - if user is not None: - logged_in = True meeting = Meeting.query.get(meeting_id) form = ( @@ -719,25 +633,18 @@ def edit_meeting(meeting_id): if meeting and meeting.user_id == user.id: return render_template( "meeting/wizard.html", - user=user, - fullname=fullname, meeting=meeting, form=form, recording=current_app.config["RECORDING"], - logged_in=logged_in, ) flash("Vous ne pouvez pas modifier cet élément", "warning") return redirect("/welcome") -@bp.route("/meeting/files/", methods=["GET"]) +@bp.route("/meeting/files/", methods=["GET"]) @auth.oidc_auth("default") def edit_meeting_files(meeting_id): user = get_current_user() - fullname = user.fullname - if user is not None: - logged_in = True - meeting = Meeting.query.get(meeting_id) form = MeetingFilesForm() @@ -762,19 +669,16 @@ def edit_meeting_files(meeting_id): if user is not None and meeting.user_id == user.id: return render_template( "meeting/filesform.html", - user=user, - fullname=fullname, meeting=meeting, form=form, fqdn=current_app.config["SERVER_FQDN"], beta=current_app.config["BETA"], - logged_in=logged_in, ) flash(lazy_gettext("Vous ne pouvez pas modifier cet élément"), "warning") return redirect("/welcome") -@bp.route("/meeting/files//", methods=["GET"]) +@bp.route("/meeting/files//", methods=["GET"]) @auth.oidc_auth("default") def download_meeting_files(meeting_id, file_id): user = get_current_user() @@ -786,7 +690,7 @@ def download_meeting_files(meeting_id, file_id): fileToSend = None if user is not None and meeting.user_id == user.id: for curFile in meeting.files: - if curFile.id == int(file_id): + if curFile.id == file_id: fileToSend = curFile break if not fileToSend: @@ -826,7 +730,7 @@ def download_meeting_files(meeting_id, file_id): return redirect("/welcome") -@bp.route("/meeting/files//toggledownload", methods=["POST"]) +@bp.route("/meeting/files//toggledownload", methods=["POST"]) @auth.oidc_auth("default") def toggledownload(meeting_id): user = get_current_user() @@ -844,14 +748,12 @@ def toggledownload(meeting_id): return redirect("/welcome") -@bp.route("/meeting/files//default", methods=["POST"]) +@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() - if user is not None: - logged_in = True meeting = Meeting.query.get(meeting_id) if meeting.user_id == user.id: actual_default_file = meeting.default_file @@ -1062,15 +964,12 @@ def add_external_meeting_file_nextcloud(path, meeting_id): return externalMeetingFile.id -@bp.route("/meeting/files/", methods=["POST"]) +@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) - if user is not None: - logged_in = True - data = request.get_json() is_default = False if len(meeting.files) == 0: @@ -1095,7 +994,7 @@ def add_meeting_files(meeting_id): # for dropzone multiple files uploading at once -@bp.route("/meeting/files//dropzone", methods=["POST"]) +@bp.route("/meeting/files//dropzone", methods=["POST"]) @auth.oidc_auth("default") def add_dropzone_files(meeting_id): user = get_current_user() @@ -1151,9 +1050,6 @@ def upload(user, meeting_id, file): @auth.oidc_auth("default") def delete_meeting_file(): user = get_current_user() - if user is not None: - logged_in = True - data = request.get_json() meeting_file_id = data["id"] meetingFile = MeetingFiles() @@ -1200,12 +1096,9 @@ def save_meeting(): flash("Le formulaire contient des erreurs", "error") return render_template( "meeting/wizard.html", - user=user, - fullname=user.fullname, meeting=None if is_new_meeting else Meeting.query.get(form.id.data), form=form, recording=current_app.config["RECORDING"], - logged_in=True, ) if is_new_meeting: @@ -1234,8 +1127,6 @@ def save_meeting(): EndMeetingForm.meeting_id.data = meeting.id return render_template( "meeting/end.html", - user=user, - logged_in=True, meeting=meeting, form=EndMeetingForm(data={"meeting_id": meeting_id}), ) @@ -1260,7 +1151,7 @@ def end_meeting(): return redirect("/welcome") -@bp.route("/meeting/create/", methods=["GET"]) +@bp.route("/meeting/create/", methods=["GET"]) @auth.oidc_auth("default") def create_meeting(meeting_id): user = get_current_user() @@ -1319,7 +1210,7 @@ def insertDoc(token): return make_response("ok", 200) -@bp.route("/meeting//externalUpload") +@bp.route("/meeting//externalUpload") @auth.oidc_auth("default") def externalUpload(meeting_id): user = get_current_user() @@ -1330,9 +1221,7 @@ def externalUpload(meeting_id): and user is not None and meeting.user_id == user.id ): - return render_template( - "meeting/externalUpload.html", user=user, meeting=meeting - ) + return render_template("meeting/externalUpload.html", meeting=meeting) else: return redirect("/welcome") @@ -1436,7 +1325,7 @@ def signin_mail_meeting(meeting_fake_id, expiration, h): @bp.route( - "/meeting/signin//creator//hash/", methods=["GET"] + "/meeting/signin//creator//hash/", methods=["GET"] ) def signin_meeting(meeting_fake_id, user_id, h): is_rie = any( @@ -1456,11 +1345,13 @@ def signin_meeting(meeting_fake_id, user_id, h): "success", ) return redirect("/") - role = meeting.get_role(h) + + 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("join_meeting_as_authenticated", meeting_id=meeting_fake_id) + url_for("routes.join_meeting_as_authenticated", meeting_id=meeting_fake_id) ) elif not role: return redirect("/") @@ -1476,19 +1367,36 @@ def signin_meeting(meeting_fake_id, user_id, h): @bp.route( - "/meeting/wait//creator//hash//fullname//fullname_suffix/", + "/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/", methods=["GET"], defaults={"fullname_suffix": ""}, ) @bp.route( - "/meeting/wait//creator//hash//fullname//fullname_suffix/", + "/meeting/wait//creator//hash//fullname//fullname_suffix/", methods=["GET"], ) 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("/") - role = meeting.get_role(h) + + 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("/") return render_template( @@ -1518,7 +1426,9 @@ def join_meeting(): meeting = get_meeting_from_meeting_id_and_user_id(meeting_fake_id, user_id) if meeting is None: return redirect("/") - role = meeting.get_role(h) + + 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() @@ -1578,7 +1488,7 @@ def get_authenticated_attendee_fullname(): return fullname -@bp.route("/meeting/join//authenticated", methods=["GET"]) +@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) @@ -1586,7 +1496,7 @@ def join_meeting_as_authenticated(meeting_id): fullname = get_authenticated_attendee_fullname() return redirect( url_for( - "waiting_meeting", + "routes.waiting_meeting", meeting_fake_id=meeting_id, user_id=meeting.user.id, h=meeting.get_hash(role), @@ -1596,7 +1506,7 @@ def join_meeting_as_authenticated(meeting_id): ) -@bp.route("/meeting/join//", methods=["GET"]) +@bp.route("/meeting/join//", methods=["GET"]) @auth.oidc_auth("default") def join_meeting_as_role(meeting_id, role): user = get_current_user() diff --git a/web/flaskr/templates/jumbotron.html b/web/flaskr/templates/jumbotron.html index 48c97721..4ce19f38 100644 --- a/web/flaskr/templates/jumbotron.html +++ b/web/flaskr/templates/jumbotron.html @@ -1,5 +1,5 @@ {% include 'rie.html' %} -{% if logged_in == true %} +{% if user %}
diff --git a/web/flaskr/templates/meeting/end.html b/web/flaskr/templates/meeting/end.html index ebbdb272..a3a2169b 100644 --- a/web/flaskr/templates/meeting/end.html +++ b/web/flaskr/templates/meeting/end.html @@ -13,10 +13,10 @@
{{ form.hidden_tag() }} - Patienter jusqu'à la fin {{ of_the_meeting }} + Patienter jusqu'à la fin {{ of_the_meeting }}
{% endblock %} {% block footer %} {% include 'footer.html' %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/web/flaskr/templates/meeting/recordings.html b/web/flaskr/templates/meeting/recordings.html index 05f20bf3..2b36bfd4 100644 --- a/web/flaskr/templates/meeting/recordings.html +++ b/web/flaskr/templates/meeting/recordings.html @@ -99,7 +99,7 @@

{% endif %} + {% if role != "authenticated" and not user %} +
+
+ {% trans %}Vous êtes propriétaire de cette salle ?{% endtrans %} + + {% trans %}S’identifier{% endtrans %} + +
+
+ {% endif %}

diff --git a/web/flaskr/templates/meeting/signinmail.html b/web/flaskr/templates/meeting/signinmail.html index 91384b65..8e066362 100644 --- a/web/flaskr/templates/meeting/signinmail.html +++ b/web/flaskr/templates/meeting/signinmail.html @@ -5,7 +5,7 @@

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

- {% if fullname is defined %} + {% if fullname and not user %}

{% trans %}Votre {{ meeting_label }} n'a pas encore été activée par un modérateur{% endtrans %}

@@ -15,7 +15,7 @@

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

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

- +
diff --git a/web/flaskr/templates/tools.html b/web/flaskr/templates/tools.html index 9ed98cfb..fb24ec10 100644 --- a/web/flaskr/templates/tools.html +++ b/web/flaskr/templates/tools.html @@ -19,7 +19,7 @@ {{ documentation_link.label }} - {% if logged_in == true %} + {% if user %} " in response.data.decode() + response.mustcontain("") def test_show_meeting_recording( client_app, app, authenticated_user, meeting, bbb_response ): - with app.app_context(): - meeting = Meeting.query.get(1) - meeting_id = meeting.id - - response = client_app.get(f"/meeting/recordings/{meeting_id}") + response = client_app.get(f"/meeting/recordings/{meeting.id}", status=200) - assert response.status_code == 200 - assert "" in response.data.decode() + response.mustcontain("") def test_new_meeting(client_app, authenticated_user): - response = client_app.get("/meeting/new") + response = client_app.get("/meeting/new", status=200) - assert response.status_code == 200 - assert "" in response.data.decode() + response.mustcontain("") def test_new_meeting_when_recording_not_configured(client_app, app, authenticated_user): @@ -46,18 +35,13 @@ def test_new_meeting_when_recording_not_configured(client_app, app, authenticate response = client_app.get("/meeting/new") - assert "Enregistrement" not in response.get_data(as_text=True) + response.mustcontain(no="Enregistrement") def test_edit_meeting(client_app, app, authenticated_user, meeting, bbb_response): - with app.app_context(): - meeting = Meeting.query.get(1) - meeting_id = meeting.id + response = client_app.get(f"/meeting/edit/{meeting.id}", status=200) - response = client_app.get(f"/meeting/edit/{meeting_id}") - - assert response.status_code == 200 - assert "" in response.data.decode() + response.mustcontain("") MEETING_DATA = { @@ -87,81 +71,76 @@ def test_save_new_meeting( ): response = client_app.post( "/meeting/save", - data=MEETING_DATA, + MEETING_DATA, + status=302, ) - assert response.status_code == 302 assert "welcome" in response.location - with app.app_context(): - meeting = Meeting.query.get(1) - - assert meeting.user_id == 1 - assert meeting.name == "Mon meeting de test" - assert meeting.welcome == "Bienvenue dans mon meeting de test" - assert meeting.maxParticipants == 5 - assert meeting.duration == 60 - assert meeting.guestPolicy is True - assert meeting.webcamsOnlyForModerator is True - assert meeting.muteOnStart is True - assert meeting.lockSettingsDisableCam is True - assert meeting.lockSettingsDisableMic is True - assert meeting.lockSettingsDisablePrivateChat is True - assert meeting.lockSettingsDisablePublicChat is True - assert meeting.lockSettingsDisableNote is True - assert meeting.moderatorOnlyMessage == "Bienvenue aux modérateurs" - assert meeting.logoutUrl == "https://log.out" - assert meeting.moderatorPW == "Motdepasse1" - assert meeting.attendeePW == "Motdepasse2" - assert meeting.record is True - assert meeting.autoStartRecording is True - assert meeting.allowStartStopRecording is True + meeting = Meeting.query.get(1) + + assert meeting.user_id == 1 + assert meeting.name == "Mon meeting de test" + assert meeting.welcome == "Bienvenue dans mon meeting de test" + assert meeting.maxParticipants == 5 + assert meeting.duration == 60 + assert meeting.guestPolicy is True + assert meeting.webcamsOnlyForModerator is True + assert meeting.muteOnStart is True + assert meeting.lockSettingsDisableCam is True + assert meeting.lockSettingsDisableMic is True + assert meeting.lockSettingsDisablePrivateChat is True + assert meeting.lockSettingsDisablePublicChat is True + assert meeting.lockSettingsDisableNote is True + assert meeting.moderatorOnlyMessage == "Bienvenue aux modérateurs" + assert meeting.logoutUrl == "https://log.out" + assert meeting.moderatorPW == "Motdepasse1" + assert meeting.attendeePW == "Motdepasse2" + assert meeting.record is True + assert meeting.autoStartRecording is True + assert meeting.allowStartStopRecording is True def test_save_existing_meeting( app, client_app, authenticated_user, meeting, mocked_is_meeting_running ): - with app.app_context(): - meeting = Meeting.query.get(1) - meeting_id = meeting.id - assert len(Meeting.query.all()) == 1 + assert len(Meeting.query.all()) == 1 data = MEETING_DATA.copy() - data["id"] = meeting_id + data["id"] = meeting.id response = client_app.post( "/meeting/save", - data=data, + data, + status=302, ) - assert response.status_code == 302 assert "welcome" in response.location - with app.app_context(): - assert len(Meeting.query.all()) == 1 - - meeting = Meeting.query.get(1) - - assert meeting.user_id == 1 - assert not meeting.name # Name can not be edited - assert meeting.welcome == "Bienvenue dans mon meeting de test" - assert meeting.maxParticipants == 5 - assert meeting.duration == 60 - assert meeting.guestPolicy is True - assert meeting.webcamsOnlyForModerator is True - assert meeting.muteOnStart is True - assert meeting.lockSettingsDisableCam is True - assert meeting.lockSettingsDisableMic is True - assert meeting.lockSettingsDisablePrivateChat is True - assert meeting.lockSettingsDisablePublicChat is True - assert meeting.lockSettingsDisableNote is True - assert meeting.moderatorOnlyMessage == "Bienvenue aux modérateurs" - assert meeting.logoutUrl == "https://log.out" - assert meeting.moderatorPW == "Motdepasse1" - assert meeting.attendeePW == "Motdepasse2" - assert meeting.record is True - assert meeting.autoStartRecording is True - assert meeting.allowStartStopRecording is True + assert len(Meeting.query.all()) == 1 + + meeting = Meeting.query.get(1) + + assert meeting.user_id == 1 + assert not meeting.name # Name can not be edited + assert meeting.welcome == "Bienvenue dans mon meeting de test" + assert meeting.maxParticipants == 5 + assert meeting.duration == 60 + assert meeting.guestPolicy is True + assert meeting.webcamsOnlyForModerator is True + assert meeting.muteOnStart is True + assert meeting.lockSettingsDisableCam is True + assert meeting.lockSettingsDisableMic is True + assert meeting.lockSettingsDisablePrivateChat is True + assert meeting.lockSettingsDisablePublicChat is True + assert meeting.lockSettingsDisableNote is True + assert meeting.moderatorOnlyMessage == "Bienvenue aux modérateurs" + assert meeting.logoutUrl == "https://log.out" + assert meeting.moderatorPW == "Motdepasse1" + assert meeting.attendeePW == "Motdepasse2" + assert meeting.record is True + assert meeting.autoStartRecording is True + assert meeting.allowStartStopRecording is True def test_save_moderatorOnlyMessage_too_long( @@ -173,18 +152,15 @@ def test_save_moderatorOnlyMessage_too_long( response = client_app.post( "/meeting/save", - data=data, - follow_redirects=True, + data, + status=200, ) - assert response.status_code == 200 - response_html = response.get_data(as_text=True) - assert "" in response_html - assert "Le formulaire contient des erreurs" in response_html - assert moderator_only_message in response_html - assert "Le message est trop long" in response_html - with app.app_context(): - assert not Meeting.query.all() + response.mustcontain("") + response.mustcontain("Le formulaire contient des erreurs") + response.mustcontain(moderator_only_message) + response.mustcontain("Le message est trop long") + assert not Meeting.query.all() def test_save_no_recording_by_default( @@ -194,14 +170,12 @@ def test_save_no_recording_by_default( del data["autoStartRecording"] del data["allowStartStopRecording"] - response = client_app.post("/meeting/save", data=data) + client_app.post("/meeting/save", data, status=302) - assert response.status_code == 302 - with app.app_context(): - meeting = Meeting.query.get(1) - assert meeting.record is False - assert meeting.autoStartRecording is False - assert meeting.allowStartStopRecording is False + meeting = Meeting.query.get(1) + assert meeting.record is False + assert meeting.autoStartRecording is False + assert meeting.allowStartStopRecording is False def test_save_meeting_in_no_recording_environment( @@ -211,16 +185,15 @@ def test_save_meeting_in_no_recording_environment( response = client_app.post( "/meeting/save", - data=MEETING_DATA, + MEETING_DATA, + status=302, ) - assert response.status_code == 302 assert "welcome" in response.location - with app.app_context(): - assert len(Meeting.query.all()) == 1 - meeting = Meeting.query.get(1) - assert meeting.record is False + assert len(Meeting.query.all()) == 1 + meeting = Meeting.query.get(1) + assert meeting.record is False def test_create(app, meeting, mocker): @@ -234,9 +207,7 @@ class Resp: "flaskr.tasks.background_upload.delay", return_value=True ) - with app.app_context(), app.test_request_context(): - meeting = Meeting.query.get(1) - + with app.test_request_context(): meeting.name = "My Meeting" meeting.attendeePW = "Password1" meeting.moderatorPW = "Password2" @@ -314,16 +285,15 @@ def test_create_without_logout_url_gets_default( data = MEETING_DATA.copy() del data["logoutUrl"] - response = client_app.post( + client_app.post( "/meeting/save", - data=data, + data, + status=302, ) - assert response.status_code == 302 - with app.app_context(): - meeting = Meeting.query.get(1) - assert meeting - assert meeting.logoutUrl == app.config["MEETING_LOGOUT_URL"] + meeting = Meeting.query.get(1) + assert meeting + assert meeting.logoutUrl == app.config["MEETING_LOGOUT_URL"] def test_create_quick_meeting(app, monkeypatch, user, mocker): @@ -334,7 +304,7 @@ class Resp: mocked_bbb_create_request = mocker.patch("requests.post", return_value=Resp) mocker.patch("flaskr.tasks.background_upload.delay", return_value=True) - with app.app_context(), app.test_request_context(): + 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) @@ -363,14 +333,10 @@ class Resp: def test_edit_files_meeting(client_app, app, authenticated_user, meeting, bbb_response): app.config["FILE_SHARING"] = True - with app.app_context(): - meeting = Meeting.query.get(1) - meeting_id = meeting.id - response = client_app.get(f"/meeting/files/{meeting_id}") + response = client_app.get(f"/meeting/files/{meeting.id}", status=200) - assert response.status_code == 200 - assert "" in response.data.decode() + response.mustcontain("") def test_deactivated_meeting_files_cannot_access_files( @@ -378,21 +344,16 @@ def test_deactivated_meeting_files_cannot_access_files( ): app.config["FILE_SHARING"] = False - response = client_app.get("/welcome") + response = client_app.get("/welcome", status=200) - assert response.status_code == 200 - assert "Fichiers associés à " not in response.data.decode() + response.mustcontain(no="Fichiers associés à ") def test_deactivated_meeting_files_cannot_edit( client_app, app, authenticated_user, meeting, bbb_response ): app.config["FILE_SHARING"] = False - with app.app_context(): - meeting = Meeting.query.get(1) - meeting_id = meeting.id - response = client_app.get(f"/meeting/files/{meeting_id}") + response = client_app.get(f"/meeting/files/{meeting.id}", status=302) - assert response.status_code == 302 assert "welcome" in response.location diff --git a/web/tests/meeting/test_recordings.py b/web/tests/meeting/test_recordings.py index 13fcb76b..59786f39 100644 --- a/web/tests/meeting/test_recordings.py +++ b/web/tests/meeting/test_recordings.py @@ -116,9 +116,7 @@ class Resp: def test_get_recordings(app, meeting, bbb_getRecordings_response): - with app.app_context(): - meeting = Meeting.query.get(1) - recordings = meeting.bbb.get_recordings() + recordings = meeting.bbb.get_recordings() assert len(recordings) == 2 first_recording = recordings[0] @@ -158,13 +156,10 @@ class Resp: mocked_bbb_request = mocker.patch("requests.get", return_value=Resp) - with app.app_context(): - meeting = Meeting.query.get(1) - meeting_id = meeting.id - response = client_app.post( - f"meeting/{meeting_id}/recordings/recording_id", - data={"name": "First recording"}, + f"/meeting/{meeting.id}/recordings/recording_id", + {"name": "First recording"}, + status=302, ) bbb_url = mocked_bbb_request.call_args.args @@ -173,5 +168,4 @@ class Resp: assert ("meta_name", "First recording") in bbb_params assert ("recordID", "recording_id") in bbb_params - assert response.status_code == 302 - assert f"meeting/recordings/{meeting_id}" in response.location + assert f"meeting/recordings/{meeting.id}" in response.location diff --git a/web/tests/test_default.py b/web/tests/test_default.py index a1c02df1..c976dd11 100644 --- a/web/tests/test_default.py +++ b/web/tests/test_default.py @@ -1,17 +1,12 @@ -from flask import session - - def test_root__anonymous_user(client_app): - response = client_app.get("/") + response = client_app.get("/", status=302) - assert response.status_code == 302 assert "/home" in response.location def test_root__authenticated_user(client_app, authenticated_user): - response = client_app.get("/") + response = client_app.get("/", status=302) - assert response.status_code == 302 assert "/welcome" in response.location @@ -22,10 +17,11 @@ def test_home__anonymous_user(client_app, mocker): } mocker.patch("flaskr.routes.get_meetings_stats", return_value=STATS) - response = client_app.get("/home", environ_base={"REMOTE_ADDR": "127.0.0.1"}) + response = client_app.get( + "/home", extra_environ={"REMOTE_ADDR": "127.0.0.1"}, status=200 + ) - assert response.status_code == 200 - assert "" in response.data.decode() + response.mustcontain("") def test_home__authenticated_user(client_app, mocker, authenticated_user): @@ -35,122 +31,106 @@ def test_home__authenticated_user(client_app, mocker, authenticated_user): } mocker.patch("flaskr.routes.get_meetings_stats", return_value=STATS) - response = client_app.get("/home", environ_base={"REMOTE_ADDR": "127.0.0.1"}) + response = client_app.get( + "/home", extra_environ={"REMOTE_ADDR": "127.0.0.1"}, status=200 + ) - assert response.status_code == 200 - assert "" in response.data.decode() + response.mustcontain("") def test_change_language(client_app): - with client_app: - response = client_app.get("/faq?lang=fr") - - assert response.status_code == 200 + response = client_app.get("/faq?lang=fr", status=200) + with client_app.session_transaction() as session: assert session["lang"] == "fr" - response = client_app.get("/faq?lang=uk") - - assert response.status_code == 200 + response = client_app.get("/faq?lang=uk", status=200) + with client_app.session_transaction() as session: assert session["lang"] == "uk" - response = client_app.get("/faq") - - assert response.status_code == 200 + response = client_app.get("/faq", status=200) + with client_app.session_transaction() as session: assert session["lang"] == "uk" def test_faq__anonymous_user(client_app): - response = client_app.get("/faq") + response = client_app.get("/faq", status=200) - assert response.status_code == 200 - assert "Alice Cooper" not in response.data.decode() + response.mustcontain(no="Alice Cooper") def test_faq__authenticated_user(client_app, authenticated_user): - response = client_app.get("/faq") + response = client_app.get("/faq", status=200) - assert response.status_code == 200 - assert "Alice Cooper" in response.data.decode() + 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 - response = client_app.get("/documentation") + response = client_app.get("/documentation", status=200) - assert response.status_code == 200 - assert "Alice Cooper" not in response.data.decode() + 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 - response = client_app.get("/documentation") + response = client_app.get("/documentation", status=200) - assert response.status_code == 200 - assert "Alice Cooper" in response.data.decode() + 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 - response = client_app.get("/documentation") + response = client_app.get("/documentation", status=302) - assert response.status_code == 302 - assert app.config["DOCUMENTATION_LINK"]["url"] in response.data.decode() + response.mustcontain(app.config["DOCUMENTATION_LINK"]["url"]) def test_accessibilite__anonymous_user(client_app): - response = client_app.get("/accessibilite") + response = client_app.get("/accessibilite", status=200) - assert response.status_code == 200 - assert "Alice Cooper" not in response.data.decode() + response.mustcontain(no="Alice Cooper") def test_accessibilite__authenticated_user(client_app, authenticated_user): - response = client_app.get("/accessibilite") + response = client_app.get("/accessibilite", status=200) - assert response.status_code == 200 - assert "Alice Cooper" in response.data.decode() + response.mustcontain("Alice Cooper") def test_mentions_legales__anonymous_user(client_app): - response = client_app.get("/mentions_legales") + response = client_app.get("/mentions_legales", status=200) - assert response.status_code == 200 - assert "Alice Cooper" not in response.data.decode() + response.mustcontain(no="Alice Cooper") def test_mentions_legales__authenticated_user(client_app, authenticated_user): - response = client_app.get("/mentions_legales") + response = client_app.get("/mentions_legales", status=200) - assert response.status_code == 200 - assert "Alice Cooper" in response.data.decode() + response.mustcontain("Alice Cooper") def test_cgu__anonymous_user(client_app): - response = client_app.get("/cgu") + response = client_app.get("/cgu", status=200) - assert response.status_code == 200 - assert "Alice Cooper" not in response.data.decode() + response.mustcontain(no="Alice Cooper") def test_cgu__authenticated_user(client_app, authenticated_user): - response = client_app.get("/cgu") + response = client_app.get("/cgu", status=200) - assert response.status_code == 200 - assert "Alice Cooper" in response.data.decode() + response.mustcontain("Alice Cooper") def test_donnees_personnelles__anonymous_user(client_app): - response = client_app.get("/donnees_personnelles") + response = client_app.get("/donnees_personnelles", status=200) - assert response.status_code == 200 - assert "Alice Cooper" not in response.data.decode() + response.mustcontain(no="Alice Cooper") def test_donnees_personnelles__authenticated_user(client_app, authenticated_user): - response = client_app.get("/donnees_personnelles") + response = client_app.get("/donnees_personnelles", status=200) - assert response.status_code == 200 - assert "Alice Cooper" in response.data.decode() + response.mustcontain("Alice Cooper") diff --git a/web/tests/test_user.py b/web/tests/test_user.py index fa938e01..03091759 100644 --- a/web/tests/test_user.py +++ b/web/tests/test_user.py @@ -4,38 +4,36 @@ from flaskr.models import User, get_or_create_user -def test_get_or_create_user(app): +def test_get_or_create_user(client_app): user_info = { "given_name": "Alice", "family_name": "Cooper", "preferred_username": "alice", "email": "alice@mydomain.test", } - with app.app_context(): - get_or_create_user(user_info) + get_or_create_user(user_info) - user = User.query.get(1) - assert user.given_name == "Alice" - assert user.family_name == "Cooper" - assert user.email == "alice@mydomain.test" - assert user.last_connection_utc_datetime.date() == date.today() + user = User.query.get(1) + assert user.given_name == "Alice" + assert user.family_name == "Cooper" + assert user.email == "alice@mydomain.test" + assert user.last_connection_utc_datetime.date() == date.today() -def test_update_last_connection_if_more_than_24h(app): +def test_update_last_connection_if_more_than_24h(client_app): user_info = { "given_name": "Alice", "family_name": "Cooper", "preferred_username": "alice", "email": "alice@mydomain.test", } - with app.app_context(): - with freeze_time("2021-08-10"): - get_or_create_user(user_info) + with freeze_time("2021-08-10"): + get_or_create_user(user_info) - with freeze_time("2021-08-11"): - user = User.query.get(1) - assert user.last_connection_utc_datetime.date() == date(2021, 8, 10) + with freeze_time("2021-08-11"): + user = User.query.get(1) + assert user.last_connection_utc_datetime.date() == date(2021, 8, 10) - get_or_create_user(user_info) + get_or_create_user(user_info) - assert user.last_connection_utc_datetime.date() == date(2021, 8, 11) + assert user.last_connection_utc_datetime.date() == date(2021, 8, 11)