diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4ede45d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +*.md +app/tests +__pycache__ +.env +*example* +.git +.vscode +.venv +*cache* +.github +app/logs +app/essensfindung.db \ No newline at end of file diff --git a/.github/workflows/python-validation.yml b/.github/workflows/python-validation.yml index aa76008..1f9b60d 100644 --- a/.github/workflows/python-validation.yml +++ b/.github/workflows/python-validation.yml @@ -22,6 +22,7 @@ jobs: uses: actions/setup-python@v2 with: python-version: 3.9 + - name: Install dependencies run: | python -m pip install --upgrade pip @@ -30,12 +31,17 @@ jobs: - uses: psf/black@stable with: options: "--line-length 120" + - name: Lint with flake8 + working-directory: ./app run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + + - name: Test with pytest + working-directory: ./app run: | pytest ./tests diff --git a/.gitignore b/.gitignore index 55c36bb..9767637 100644 --- a/.gitignore +++ b/.gitignore @@ -134,7 +134,10 @@ dmypy.json # Ignore all Configuration Files *.conf !example*.conf -tests/test_db.db +app/tests/test_db.db # Ignore Logs -*log* \ No newline at end of file +*log* + +# Ignore local data +app/data \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..751dd3f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,39 @@ +# Base Source https://fastapi.tiangolo.com/deployment/docker +# This is the first stage, to create the requirements.txt +FROM python:3.9 as requirements-stage + +WORKDIR /tmp +RUN apt-get update && apt-get install -y \ + build-essential \ + libssl-dev \ + libffi-dev \ + python3-dev \ + cargo \ + && rm -rf /var/lib/apt/lists/* +RUN pip install poetry +COPY ["./pyproject.toml", "./poetry.lock", "/tmp/"] +RUN poetry export -f requirements.txt --output requirements.txt --without-hashes + +# Start final stage +FROM python:3.9 + +# Install Dependencies +COPY --from=requirements-stage /tmp/requirements.txt /tmp/requirements.txt +RUN /usr/local/bin/python -m pip install --upgrade pip && \ + pip install --no-cache-dir --upgrade -r /tmp/requirements.txt + +# Expose port 80 +EXPOSE 80 + +# Copy the app +RUN ["mkdir", "-p", "/essensfindung/"] +COPY ./app /essensfindung/app +WORKDIR /essensfindung/app + + +# Setup local DB if needed +RUN ["mkdir", "data"] +VOLUME [ "/essensfindung/app/data" ] + +# Start gunicorn server with 2 workers, uvicorn worker type and use the 0.0.0.0 host with port 80 +ENTRYPOINT ["gunicorn", "-w", "2", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:80", "main:app"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b8dc075 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +build: clean_python + docker build -t essensfindung . + +clean_python: + find . -type d -name __pycache__ -exec rm -r {} \+ + rm -r -f app/logs + rm -f app/essensfindung.db + +clean_docker: + docker rm --force essensfindung + docker container prune --force + docker volume prune --force + +clean_all: clean_python clean_python clean_docker diff --git a/README.md b/README.md index d674704..0ccb2ba 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ Student project for DHBW-Friedrichshafen to search for restaurant or recipe suggestions. # Usage +If you want to run it make sure you habe a GoogleAPI KEY
+The Application use [place-details](https://developers.google.com/maps/billing-and-pricing/pricing#places-details) and [nearby-search](https://developers.google.com/maps/billing-and-pricing/pricing#nearby-search)
+**!!! The GoogleAPI Requests are not for free, so pay attention on the pricing !!!** +## Direct with Python +### Requirements To run the application install the requirements: ```console pip install requirements.txt @@ -10,8 +15,55 @@ OR ```console poetry install --no-dev ``` -You also need the configuration files in the `configuration` Folder.
-Just copy the examples in the Folder and fill in the Data. + +### Configuration +If you **dont** have a PostgreSQL Database use `.env-example1` with only the GOOGLE_API. With this Configuration it will create a SQL-Lite DB in the app folder. Not Recommended for Production! +```console +# Copy the Example +cp .env-example1 .env +# Edit the File +nano .env +``` + +If you have a PostgreSQL Database use `.env-example2` +```console +# Copy the Example +cp .env-example2 .env +# Edit the File +nano .env +``` + +## Docker +You also can build a docker container +```console +git clone https://github.com/DHBW-FN-TIT20/essensfindung.git +cd essensfindung +docker build essensfindung . +``` +If you **dont** have a PostgreSQL Database start the container: +```console +docker run -p 8080:80 \ +-v /essensfindung/app/data \ +-e GOOGLE_API_KEY=KEY \ +--name essensfindung \ +essensfindung +``` + +If you have a PostgreSQL Database: +```console +docker run -p 8080:80 \ +-e GOOGLE_API_KEY=KEY \ +-e POSTGRES_USER=postgres \ +-e POSTGRES_PASSWORD=PASSWORD \ +-e POSTGRES_SERVER=localhost \ +-e POSTGRES_DATABASE=essensfindung \ +-e POSTGRES_PORT=5432 \ +--name essensfindung \ +essensfindung +``` + +## Docker-Compose +See the `docker-compose.yml` File # Developing Python-Verison 3.9 or higher
You can use [pyenv](https://github.com/pyenv/pyenv) to manage you virtual envioremnts. @@ -31,8 +83,10 @@ pre-commit install ``` If you want to manuall start the pre-commit check run: ```console -pre-commit run --all-files +pre-commit run ``` + + ## Dependencies To develop on this project we recommend to use [venv](https://docs.python.org/3/library/venv.html).
You can use some extra tools like: diff --git a/api/README.md b/api/README.md deleted file mode 100644 index 4363514..0000000 --- a/api/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# API -In this dictonary you add the files for the api interface like `restaurant_api.py` or `rescepe_api.py` \ No newline at end of file diff --git a/app/.env-example1 b/app/.env-example1 new file mode 100644 index 0000000..b8a2111 --- /dev/null +++ b/app/.env-example1 @@ -0,0 +1 @@ +GOOGLE_API_KEY=KEY \ No newline at end of file diff --git a/app/.env-example2 b/app/.env-example2 new file mode 100644 index 0000000..94895e6 --- /dev/null +++ b/app/.env-example2 @@ -0,0 +1,6 @@ +GOOGLE_API_KEY=KEY +POSTGRES_USER=USER! +POSTGRES_PASSWORD=PASSWORD! +POSTGRES_SERVER=DB_SERVER! +POSTGRES_DATABASE=DATABASE! +POSTGRES_PORT=5432 \ No newline at end of file diff --git a/db/__init__.py b/app/db/__init__.py similarity index 100% rename from db/__init__.py rename to app/db/__init__.py diff --git a/db/base.py b/app/db/base.py similarity index 100% rename from db/base.py rename to app/db/base.py diff --git a/db/base_class.py b/app/db/base_class.py similarity index 100% rename from db/base_class.py rename to app/db/base_class.py diff --git a/db/crud/__init__.py b/app/db/crud/__init__.py similarity index 100% rename from db/crud/__init__.py rename to app/db/crud/__init__.py diff --git a/db/crud/bewertung.py b/app/db/crud/bewertung.py similarity index 100% rename from db/crud/bewertung.py rename to app/db/crud/bewertung.py diff --git a/db/crud/restaurant.py b/app/db/crud/restaurant.py similarity index 100% rename from db/crud/restaurant.py rename to app/db/crud/restaurant.py diff --git a/db/crud/user.py b/app/db/crud/user.py similarity index 100% rename from db/crud/user.py rename to app/db/crud/user.py diff --git a/app/db/database.py b/app/db/database.py new file mode 100644 index 0000000..ea82cfb --- /dev/null +++ b/app/db/database.py @@ -0,0 +1,27 @@ +"""Create the connection to the Database""" +from pathlib import Path +from typing import Generator + +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from tools.config import settings + +if settings.SQL_LITE: + Path("./data").mkdir(exist_ok=True) + SQLALCHEMY_DATABASE_URL = "sqlite:///./data/essensfindung.db" + # Use connect_args parameter only with sqlite + engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}) +else: + SQLALCHEMY_DATABASE_URL = f"postgresql://{settings.POSTGRES_USER}:{settings.POSTGRES_PASSWORD}@{settings.POSTGRES_SERVER}:{settings.POSTGRES_PORT}/{settings.POSTGRES_DATABASE}" + engine = create_engine(SQLALCHEMY_DATABASE_URL) + + +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + + +def get_db() -> Generator: + try: + database = SessionLocal() + yield database + finally: + database.close() diff --git a/db/models/__init__.py b/app/db/models/__init__.py similarity index 100% rename from db/models/__init__.py rename to app/db/models/__init__.py diff --git a/db/models/allergie.py b/app/db/models/allergie.py similarity index 100% rename from db/models/allergie.py rename to app/db/models/allergie.py diff --git a/db/models/bewertung.py b/app/db/models/bewertung.py similarity index 100% rename from db/models/bewertung.py rename to app/db/models/bewertung.py diff --git a/db/models/filter.py b/app/db/models/filter.py similarity index 100% rename from db/models/filter.py rename to app/db/models/filter.py diff --git a/db/models/person.py b/app/db/models/person.py similarity index 100% rename from db/models/person.py rename to app/db/models/person.py diff --git a/db/models/restaurant.py b/app/db/models/restaurant.py similarity index 100% rename from db/models/restaurant.py rename to app/db/models/restaurant.py diff --git a/infrastructure/README.md b/app/infrastructure/README.md similarity index 100% rename from infrastructure/README.md rename to app/infrastructure/README.md diff --git a/infrastructure/__init__.py b/app/infrastructure/__init__.py similarity index 100% rename from infrastructure/__init__.py rename to app/infrastructure/__init__.py diff --git a/main.py b/app/main.py similarity index 91% rename from main.py rename to app/main.py index 3e66be7..c4ff324 100644 --- a/main.py +++ b/app/main.py @@ -5,10 +5,10 @@ import fastapi import uvicorn -from starlette.staticfiles import StaticFiles - from db.base import Base from db.database import engine +from sqlalchemy import exc +from starlette.staticfiles import StaticFiles from views import index from views import restaurant from views import signin @@ -62,7 +62,11 @@ def configure_routing(): def configure_database(): """Configure connection to the Database""" - Base.metadata.create_all(bind=engine) + try: + Base.metadata.create_all(bind=engine) + except exc.OperationalError: + # Ignore if Tables already exist + pass if __name__ == "__main__": diff --git a/schemes/README.md b/app/schemes/README.md similarity index 100% rename from schemes/README.md rename to app/schemes/README.md diff --git a/schemes/__init__.py b/app/schemes/__init__.py similarity index 100% rename from schemes/__init__.py rename to app/schemes/__init__.py diff --git a/schemes/exceptions.py b/app/schemes/exceptions.py similarity index 100% rename from schemes/exceptions.py rename to app/schemes/exceptions.py diff --git a/schemes/scheme_filter.py b/app/schemes/scheme_filter.py similarity index 100% rename from schemes/scheme_filter.py rename to app/schemes/scheme_filter.py diff --git a/schemes/scheme_rest.py b/app/schemes/scheme_rest.py similarity index 100% rename from schemes/scheme_rest.py rename to app/schemes/scheme_rest.py diff --git a/schemes/scheme_user.py b/app/schemes/scheme_user.py similarity index 100% rename from schemes/scheme_user.py rename to app/schemes/scheme_user.py diff --git a/services/README.md b/app/services/README.md similarity index 100% rename from services/README.md rename to app/services/README.md diff --git a/services/__init__.py b/app/services/__init__.py similarity index 100% rename from services/__init__.py rename to app/services/__init__.py diff --git a/services/service_res.py b/app/services/service_res.py similarity index 100% rename from services/service_res.py rename to app/services/service_res.py diff --git a/static/README.md b/app/static/README.md similarity index 100% rename from static/README.md rename to app/static/README.md diff --git a/static/css/bootstrap.min.css b/app/static/css/bootstrap.min.css similarity index 100% rename from static/css/bootstrap.min.css rename to app/static/css/bootstrap.min.css diff --git a/static/css/bootstrap.min.css.map b/app/static/css/bootstrap.min.css.map similarity index 100% rename from static/css/bootstrap.min.css.map rename to app/static/css/bootstrap.min.css.map diff --git a/static/img/glaser.JPG b/app/static/img/glaser.JPG similarity index 100% rename from static/img/glaser.JPG rename to app/static/img/glaser.JPG diff --git a/static/js/bootstrap.bundle.min.js b/app/static/js/bootstrap.bundle.min.js similarity index 100% rename from static/js/bootstrap.bundle.min.js rename to app/static/js/bootstrap.bundle.min.js diff --git a/static/js/bootstrap.bundle.min.js.map b/app/static/js/bootstrap.bundle.min.js.map similarity index 100% rename from static/js/bootstrap.bundle.min.js.map rename to app/static/js/bootstrap.bundle.min.js.map diff --git a/static/js/restaurant.js b/app/static/js/restaurant.js similarity index 100% rename from static/js/restaurant.js rename to app/static/js/restaurant.js diff --git a/static/text/privacy.txt b/app/static/text/privacy.txt similarity index 100% rename from static/text/privacy.txt rename to app/static/text/privacy.txt diff --git a/static/text/tos.txt b/app/static/text/tos.txt similarity index 100% rename from static/text/tos.txt rename to app/static/text/tos.txt diff --git a/templates/README.md b/app/templates/README.md similarity index 100% rename from templates/README.md rename to app/templates/README.md diff --git a/templates/examples/example.html b/app/templates/examples/example.html similarity index 100% rename from templates/examples/example.html rename to app/templates/examples/example.html diff --git a/templates/index.html b/app/templates/index.html similarity index 100% rename from templates/index.html rename to app/templates/index.html diff --git a/templates/restaurant/restaurant_filter_modal.html b/app/templates/restaurant/restaurant_filter_modal.html similarity index 100% rename from templates/restaurant/restaurant_filter_modal.html rename to app/templates/restaurant/restaurant_filter_modal.html diff --git a/templates/restaurant/restaurant_result.html b/app/templates/restaurant/restaurant_result.html similarity index 100% rename from templates/restaurant/restaurant_result.html rename to app/templates/restaurant/restaurant_result.html diff --git a/templates/shared/layout.html b/app/templates/shared/layout.html similarity index 100% rename from templates/shared/layout.html rename to app/templates/shared/layout.html diff --git a/templates/shared/layout_singleform.html b/app/templates/shared/layout_singleform.html similarity index 100% rename from templates/shared/layout_singleform.html rename to app/templates/shared/layout_singleform.html diff --git a/templates/signin/register.html b/app/templates/signin/register.html similarity index 100% rename from templates/signin/register.html rename to app/templates/signin/register.html diff --git a/templates/signin/signin.html b/app/templates/signin/signin.html similarity index 100% rename from templates/signin/signin.html rename to app/templates/signin/signin.html diff --git a/tests/__init__.py b/app/tests/__init__.py similarity index 100% rename from tests/__init__.py rename to app/tests/__init__.py diff --git a/tests/example_nearby_search.json b/app/tests/example_nearby_search.json similarity index 100% rename from tests/example_nearby_search.json rename to app/tests/example_nearby_search.json diff --git a/tests/example_place_details.json b/app/tests/example_place_details.json similarity index 100% rename from tests/example_place_details.json rename to app/tests/example_place_details.json diff --git a/tests/example_restaurants.json b/app/tests/example_restaurants.json similarity index 100% rename from tests/example_restaurants.json rename to app/tests/example_restaurants.json diff --git a/tests/example_restaurants_with_own_rating.json b/app/tests/example_restaurants_with_own_rating.json similarity index 100% rename from tests/example_restaurants_with_own_rating.json rename to app/tests/example_restaurants_with_own_rating.json diff --git a/tests/test_db.py b/app/tests/test_db.py similarity index 100% rename from tests/test_db.py rename to app/tests/test_db.py diff --git a/tests/test_gapi.py b/app/tests/test_gapi.py similarity index 94% rename from tests/test_gapi.py rename to app/tests/test_gapi.py index 474a187..0ea4227 100644 --- a/tests/test_gapi.py +++ b/app/tests/test_gapi.py @@ -5,7 +5,6 @@ import pytest from pytest_httpx import HTTPXMock from pytest_mock import MockerFixture - from schemes import Cuisine from schemes.scheme_rest import Restaurant from tools import gapi @@ -56,7 +55,7 @@ def test_nearby_search( httpx_mock.add_response(status_code=status_code, json=fake_nearby_search) # Mock other functions - mocker.patch("configuration.config.Setting.GOOGLE_API_KEY", "42") + mocker.patch("tools.config.Setting.GOOGLE_API_KEY", "42") if status_code != 200: with pytest.raises(httpx.HTTPStatusError): @@ -78,7 +77,7 @@ def test_place_details( httpx_mock.add_response(status_code=200, json=fake_place_details[0], url=url) # Mock other functions - mocker.patch("configuration.config.Setting.GOOGLE_API_KEY", "42") + mocker.patch("tools.config.Setting.GOOGLE_API_KEY", "42") restaurant = gapi.place_details(fake_nearby_search_restaurants[0]) assert fake_restaurants[0] == restaurant diff --git a/tests/test_restaurant_service.py b/app/tests/test_restaurant_service.py similarity index 98% rename from tests/test_restaurant_service.py rename to app/tests/test_restaurant_service.py index 1562969..c01807d 100644 --- a/tests/test_restaurant_service.py +++ b/app/tests/test_restaurant_service.py @@ -2,14 +2,10 @@ from typing import List import pytest -from pytest_httpx import HTTPXMock -from pytest_mock import MockerFixture -from sqlalchemy import create_engine -from sqlalchemy.orm import Session -from sqlalchemy.orm import sessionmaker - from db.base_class import Base from db.crud.user import create_user +from pytest_httpx import HTTPXMock +from pytest_mock import MockerFixture from schemes import Allergies from schemes import Cuisine from schemes.scheme_filter import FilterRest @@ -17,6 +13,9 @@ from schemes.scheme_rest import Restaurant from schemes.scheme_user import UserCreate from services import service_res +from sqlalchemy import create_engine +from sqlalchemy.orm import Session +from sqlalchemy.orm import sessionmaker SQLALCHEMY_DATABASE_URL = "sqlite:///./tests/test_db.db" engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}) @@ -68,7 +67,7 @@ def test_search_for_restaurant( # ...googleapi mocker.patch("tools.gapi.search_restaurant", return_value=google_api_restaurants) - mocker.patch("configuration.config.Setting.GOOGLE_API_KEY", "42") + mocker.patch("tools.config.Setting.GOOGLE_API_KEY", "42") url = f"https://maps.googleapis.com/maps/api/place/details/json?key=42&place_id={random_res.place_id}" httpx_mock.add_response(status_code=200, json={"result": random_res.dict()}, url=url) diff --git a/tools/__init__.py b/app/tools/__init__.py similarity index 100% rename from tools/__init__.py rename to app/tools/__init__.py diff --git a/app/tools/config.py b/app/tools/config.py new file mode 100644 index 0000000..9574f15 --- /dev/null +++ b/app/tools/config.py @@ -0,0 +1,26 @@ +import os +from pathlib import Path + +from dotenv import load_dotenv + +ENV_PATH = Path("./.env") +load_dotenv(dotenv_path=ENV_PATH) + + +class Setting: + """Contains all Settings - Loads from the os env""" + + GOOGLE_API_KEY: str = os.getenv("GOOGLE_API_KEY") + + if os.getenv("POSTGRES_SERVER"): + SQL_LITE: bool = False + POSTGRES_USER: str = os.getenv("POSTGRES_USER") + POSTGRES_PASSWORD: str = os.getenv("POSTGRES_PASSWORD") + POSTGRES_SERVER: str = os.getenv("POSTGRES_SERVER") + POSTGRES_DATABASE: str = os.getenv("POSTGRES_DATABASE") + POSTGRES_PORT: str = os.getenv("POSTGRES_PORT") + else: + SQL_LITE: bool = True + + +settings = Setting() diff --git a/tools/gapi.py b/app/tools/gapi.py similarity index 98% rename from tools/gapi.py rename to app/tools/gapi.py index d8547c8..23d36af 100644 --- a/tools/gapi.py +++ b/app/tools/gapi.py @@ -3,11 +3,10 @@ from typing import List import httpx - -from configuration.config import settings from schemes.exceptions import GoogleApiException from schemes.scheme_filter import FilterRest from schemes.scheme_rest import Restaurant +from tools.config import settings # TODO: Asynchrone Funktionen # TODO: Asynchrone API Anfragen diff --git a/tools/hashing.py b/app/tools/hashing.py similarity index 100% rename from tools/hashing.py rename to app/tools/hashing.py diff --git a/views/README.md b/app/views/README.md similarity index 100% rename from views/README.md rename to app/views/README.md diff --git a/views/index.py b/app/views/index.py similarity index 100% rename from views/index.py rename to app/views/index.py diff --git a/views/restaurant.py b/app/views/restaurant.py similarity index 100% rename from views/restaurant.py rename to app/views/restaurant.py diff --git a/views/signin.py b/app/views/signin.py similarity index 100% rename from views/signin.py rename to app/views/signin.py diff --git a/configuration/__init__.py b/configuration/__init__.py deleted file mode 100644 index c3419cc..0000000 --- a/configuration/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -import shutil -from pathlib import Path - -PATH_GOOGLE = Path("./configuration/google_api.conf") -PATH_DB = Path("./configuration/db.conf") - -if not PATH_GOOGLE.exists(): - shutil.copy("./configuration/example_google_api.conf", str(PATH_GOOGLE)) -if not PATH_DB.exists(): - shutil.copy("./configuration/example_db.conf", str(PATH_DB)) diff --git a/configuration/config.py b/configuration/config.py deleted file mode 100644 index aab08ab..0000000 --- a/configuration/config.py +++ /dev/null @@ -1,18 +0,0 @@ -from configparser import ConfigParser - -from . import PATH_DB -from . import PATH_GOOGLE - -config = ConfigParser() -config.read((PATH_GOOGLE, PATH_DB)) - - -class Setting: - GOOGLE_API_KEY: str = config["API"]["KEY"] - POSTGRES_USER: str = config["USER"]["USERNAME"] - POSTGRES_PASSWORD: str = config["USER"]["PASSWORD"] - POSTGRES_SERVER: str = config["CONNECTION"]["HOST"] - POSTGRES_DATABASE: str = config["CONNECTION"]["DATABASE"] - - -settings = Setting() diff --git a/configuration/example_db.conf b/configuration/example_db.conf deleted file mode 100644 index 4ebee07..0000000 --- a/configuration/example_db.conf +++ /dev/null @@ -1,8 +0,0 @@ -[CONNECTION] -HOST=192.168.10.200 -PORT=5432 -DATABASE=essensfinder - -[USER] -USERNAME=postgres -PASSWORD=[PASSWORD] \ No newline at end of file diff --git a/configuration/example_google_api.conf b/configuration/example_google_api.conf deleted file mode 100644 index bb8d4b7..0000000 --- a/configuration/example_google_api.conf +++ /dev/null @@ -1,2 +0,0 @@ -[API] -KEY = [KEY] \ No newline at end of file diff --git a/db/database.py b/db/database.py deleted file mode 100644 index f60c3d8..0000000 --- a/db/database.py +++ /dev/null @@ -1,20 +0,0 @@ -"""Create the connection to the Database""" -from typing import Generator - -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker - -from configuration.config import settings - -SQLALCHEMY_DATABASE_URL = f"postgresql://{settings.POSTGRES_USER}:{settings.POSTGRES_PASSWORD}@{settings.POSTGRES_SERVER}/{settings.POSTGRES_DATABASE}" - -engine = create_engine(SQLALCHEMY_DATABASE_URL) -SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) - - -def get_db() -> Generator: - try: - database = SessionLocal() - yield database - finally: - database.close() diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d155e70 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,32 @@ +version: '3.5' +services: + + essensfindung: + image: essensfindung + container_name: essensfindung + hostname: essensfindung + depends_on: + - db + ports: + - "8888:80" + environment: + - TZ=Europe/Berlin + - GOOGLE_API_KEY=CHANGE_TO_KEY + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=SAVE_PASSWORD + - POSTGRES_SERVER=db + - POSTGRES_DATABASE=essensfinder + - POSTGRES_PORT=5432 + volumes: + - ./app/data:/essensfindung/app/data:rw + + db: + image: postgres + container_name: postgresDB_essensfindung + hostname: db + environment: + - TZ=Europe/Berlin + - PUID=1000 + - PGID=1000 + - POSTGRES_PASSWORD=SAVE_PASSWORD + - POSTGRES_DB=essensfindung \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index cc2099c..e87a4fb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -231,6 +231,20 @@ python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" [package.extras] docs = ["sphinx"] +[[package]] +name = "gunicorn" +version = "20.1.0" +description = "WSGI HTTP Server for UNIX" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +eventlet = ["eventlet (>=0.24.1)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +tornado = ["tornado (>=0.2)"] + [[package]] name = "h11" version = "0.12.0" @@ -577,6 +591,17 @@ pytest = ">=5.0" [package.extras] dev = ["pre-commit", "tox", "pytest-asyncio"] +[[package]] +name = "python-dotenv" +version = "0.19.2" +description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +cli = ["click (>=5.0)"] + [[package]] name = "pyyaml" version = "6.0" @@ -738,7 +763,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "d53531e2d868d5513f44ed892f1a9d354b6030819599c28c8cdbba2f293d8e05" +content-hash = "2b62bf788ed5e813d7f73680785c98c909b64f20ea98ee009c3b422a219b81ab" [metadata.files] aiofiles = [ @@ -926,6 +951,10 @@ greenlet = [ {file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"}, {file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"}, ] +gunicorn = [ + {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, + {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, +] h11 = [ {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, @@ -1175,6 +1204,10 @@ pytest-mock = [ {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"}, ] +python-dotenv = [ + {file = "python-dotenv-0.19.2.tar.gz", hash = "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f"}, + {file = "python_dotenv-0.19.2-py2.py3-none-any.whl", hash = "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3"}, +] pyyaml = [ {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, @@ -1219,6 +1252,11 @@ regex = [ {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f"}, {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0"}, {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9ed0b1e5e0759d6b7f8e2f143894b2a7f3edd313f38cf44e1e15d360e11749b"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:473e67837f786404570eae33c3b64a4b9635ae9f00145250851a1292f484c063"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2fee3ed82a011184807d2127f1733b4f6b2ff6ec7151d83ef3477f3b96a13d03"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d5fd67df77bab0d3f4ea1d7afca9ef15c2ee35dfb348c7b57ffb9782a6e4db6e"}, + {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5d408a642a5484b9b4d11dea15a489ea0928c7e410c7525cd892f4d04f2f617b"}, {file = "regex-2021.11.10-cp310-cp310-win32.whl", hash = "sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a"}, {file = "regex-2021.11.10-cp310-cp310-win_amd64.whl", hash = "sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12"}, {file = "regex-2021.11.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc"}, @@ -1228,6 +1266,11 @@ regex = [ {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733"}, {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23"}, {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:74cbeac0451f27d4f50e6e8a8f3a52ca074b5e2da9f7b505c4201a57a8ed6286"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:3598893bde43091ee5ca0a6ad20f08a0435e93a69255eeb5f81b85e81e329264"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:50a7ddf3d131dc5633dccdb51417e2d1910d25cbcf842115a3a5893509140a3a"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:61600a7ca4bcf78a96a68a27c2ae9389763b5b94b63943d5158f2a377e09d29a"}, + {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:563d5f9354e15e048465061509403f68424fef37d5add3064038c2511c8f5e00"}, {file = "regex-2021.11.10-cp36-cp36m-win32.whl", hash = "sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4"}, {file = "regex-2021.11.10-cp36-cp36m-win_amd64.whl", hash = "sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e"}, {file = "regex-2021.11.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e"}, @@ -1237,6 +1280,11 @@ regex = [ {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a"}, {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e"}, {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:42b50fa6666b0d50c30a990527127334d6b96dd969011e843e726a64011485da"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6e1d2cc79e8dae442b3fa4a26c5794428b98f81389af90623ffcc650ce9f6732"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:0416f7399e918c4b0e074a0f66e5191077ee2ca32a0f99d4c187a62beb47aa05"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ce298e3d0c65bd03fa65ffcc6db0e2b578e8f626d468db64fdf8457731052942"}, + {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dc07f021ee80510f3cd3af2cad5b6a3b3a10b057521d9e6aaeb621730d320c5a"}, {file = "regex-2021.11.10-cp37-cp37m-win32.whl", hash = "sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec"}, {file = "regex-2021.11.10-cp37-cp37m-win_amd64.whl", hash = "sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4"}, {file = "regex-2021.11.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83"}, @@ -1247,6 +1295,11 @@ regex = [ {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec"}, {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe"}, {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f5be7805e53dafe94d295399cfbe5227f39995a997f4fd8539bf3cbdc8f47ca8"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a955b747d620a50408b7fdf948e04359d6e762ff8a85f5775d907ceced715129"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:139a23d1f5d30db2cc6c7fd9c6d6497872a672db22c4ae1910be22d4f4b2068a"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ca49e1ab99593438b204e00f3970e7a5f70d045267051dfa6b5f4304fcfa1dbf"}, + {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:96fc32c16ea6d60d3ca7f63397bff5c75c5a562f7db6dec7d412f7c4d2e78ec0"}, {file = "regex-2021.11.10-cp38-cp38-win32.whl", hash = "sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc"}, {file = "regex-2021.11.10-cp38-cp38-win_amd64.whl", hash = "sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d"}, {file = "regex-2021.11.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b"}, @@ -1257,6 +1310,11 @@ regex = [ {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449"}, {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b"}, {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cd410a1cbb2d297c67d8521759ab2ee3f1d66206d2e4328502a487589a2cb21b"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e6096b0688e6e14af6a1b10eaad86b4ff17935c49aa774eac7c95a57a4e8c296"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:529801a0d58809b60b3531ee804d3e3be4b412c94b5d267daa3de7fadef00f49"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f594b96fe2e0821d026365f72ac7b4f0b487487fb3d4aaf10dd9d97d88a9737"}, + {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2409b5c9cef7054dde93a9803156b411b677affc84fca69e908b1cb2c540025d"}, {file = "regex-2021.11.10-cp39-cp39-win32.whl", hash = "sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a"}, {file = "regex-2021.11.10-cp39-cp39-win_amd64.whl", hash = "sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29"}, {file = "regex-2021.11.10.tar.gz", hash = "sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6"}, diff --git a/pyproject.toml b/pyproject.toml index f81fd13..0a8f81e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,8 @@ SQLAlchemy = "^1.4.31" psycopg2 = "^2.9.3" passlib = "^1.7.4" bcrypt = "^3.2.0" +gunicorn = "^20.1.0" +python-dotenv = "^0.19.2" [tool.poetry.dev-dependencies] black = "^21.10b0" diff --git a/requirements-dev.txt b/requirements-dev.txt index baab60d..fc1ddb0 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -164,6 +164,9 @@ greenlet==1.1.2; python_version >= "3" and python_full_version < "3.0.0" and (pl --hash=sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf \ --hash=sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd \ --hash=sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a +gunicorn==20.1.0; python_version >= "3.5" \ + --hash=sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e \ + --hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8 h11==0.12.0; python_version >= "3.6" \ --hash=sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6 \ --hash=sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042 @@ -383,6 +386,9 @@ pytest-mock==3.6.1; python_version >= "3.6" \ pytest==6.2.5; python_version >= "3.6" \ --hash=sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134 \ --hash=sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89 +python-dotenv==0.19.2; python_version >= "3.5" \ + --hash=sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f \ + --hash=sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3 pyyaml==6.0; python_version >= "3.6" and python_full_version >= "3.6.1" \ --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \ --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \ @@ -426,6 +432,11 @@ regex==2021.11.10; python_full_version >= "3.6.2" \ --hash=sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f \ --hash=sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0 \ --hash=sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4 \ + --hash=sha256:b9ed0b1e5e0759d6b7f8e2f143894b2a7f3edd313f38cf44e1e15d360e11749b \ + --hash=sha256:473e67837f786404570eae33c3b64a4b9635ae9f00145250851a1292f484c063 \ + --hash=sha256:2fee3ed82a011184807d2127f1733b4f6b2ff6ec7151d83ef3477f3b96a13d03 \ + --hash=sha256:d5fd67df77bab0d3f4ea1d7afca9ef15c2ee35dfb348c7b57ffb9782a6e4db6e \ + --hash=sha256:5d408a642a5484b9b4d11dea15a489ea0928c7e410c7525cd892f4d04f2f617b \ --hash=sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a \ --hash=sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12 \ --hash=sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc \ @@ -435,6 +446,11 @@ regex==2021.11.10; python_full_version >= "3.6.2" \ --hash=sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733 \ --hash=sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23 \ --hash=sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e \ + --hash=sha256:74cbeac0451f27d4f50e6e8a8f3a52ca074b5e2da9f7b505c4201a57a8ed6286 \ + --hash=sha256:3598893bde43091ee5ca0a6ad20f08a0435e93a69255eeb5f81b85e81e329264 \ + --hash=sha256:50a7ddf3d131dc5633dccdb51417e2d1910d25cbcf842115a3a5893509140a3a \ + --hash=sha256:61600a7ca4bcf78a96a68a27c2ae9389763b5b94b63943d5158f2a377e09d29a \ + --hash=sha256:563d5f9354e15e048465061509403f68424fef37d5add3064038c2511c8f5e00 \ --hash=sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4 \ --hash=sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e \ --hash=sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e \ @@ -444,6 +460,11 @@ regex==2021.11.10; python_full_version >= "3.6.2" \ --hash=sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a \ --hash=sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e \ --hash=sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f \ + --hash=sha256:42b50fa6666b0d50c30a990527127334d6b96dd969011e843e726a64011485da \ + --hash=sha256:6e1d2cc79e8dae442b3fa4a26c5794428b98f81389af90623ffcc650ce9f6732 \ + --hash=sha256:0416f7399e918c4b0e074a0f66e5191077ee2ca32a0f99d4c187a62beb47aa05 \ + --hash=sha256:ce298e3d0c65bd03fa65ffcc6db0e2b578e8f626d468db64fdf8457731052942 \ + --hash=sha256:dc07f021ee80510f3cd3af2cad5b6a3b3a10b057521d9e6aaeb621730d320c5a \ --hash=sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec \ --hash=sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4 \ --hash=sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83 \ @@ -454,6 +475,11 @@ regex==2021.11.10; python_full_version >= "3.6.2" \ --hash=sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec \ --hash=sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe \ --hash=sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94 \ + --hash=sha256:f5be7805e53dafe94d295399cfbe5227f39995a997f4fd8539bf3cbdc8f47ca8 \ + --hash=sha256:a955b747d620a50408b7fdf948e04359d6e762ff8a85f5775d907ceced715129 \ + --hash=sha256:139a23d1f5d30db2cc6c7fd9c6d6497872a672db22c4ae1910be22d4f4b2068a \ + --hash=sha256:ca49e1ab99593438b204e00f3970e7a5f70d045267051dfa6b5f4304fcfa1dbf \ + --hash=sha256:96fc32c16ea6d60d3ca7f63397bff5c75c5a562f7db6dec7d412f7c4d2e78ec0 \ --hash=sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc \ --hash=sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d \ --hash=sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b \ @@ -464,6 +490,11 @@ regex==2021.11.10; python_full_version >= "3.6.2" \ --hash=sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449 \ --hash=sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b \ --hash=sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef \ + --hash=sha256:cd410a1cbb2d297c67d8521759ab2ee3f1d66206d2e4328502a487589a2cb21b \ + --hash=sha256:e6096b0688e6e14af6a1b10eaad86b4ff17935c49aa774eac7c95a57a4e8c296 \ + --hash=sha256:529801a0d58809b60b3531ee804d3e3be4b412c94b5d267daa3de7fadef00f49 \ + --hash=sha256:0f594b96fe2e0821d026365f72ac7b4f0b487487fb3d4aaf10dd9d97d88a9737 \ + --hash=sha256:2409b5c9cef7054dde93a9803156b411b677affc84fca69e908b1cb2c540025d \ --hash=sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a \ --hash=sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29 \ --hash=sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6 diff --git a/requirements.txt b/requirements.txt index 8d66730..f395a47 100644 --- a/requirements.txt +++ b/requirements.txt @@ -140,6 +140,9 @@ greenlet==1.1.2; python_version >= "3" and python_full_version < "3.0.0" and (pl --hash=sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf \ --hash=sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd \ --hash=sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a +gunicorn==20.1.0; python_version >= "3.5" \ + --hash=sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e \ + --hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8 h11==0.12.0; python_version >= "3.6" \ --hash=sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6 \ --hash=sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042 @@ -279,6 +282,9 @@ pydantic==1.9.0; python_full_version >= "3.6.1" \ --hash=sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16 \ --hash=sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3 \ --hash=sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a +python-dotenv==0.19.2; python_version >= "3.5" \ + --hash=sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f \ + --hash=sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3 rfc3986==1.5.0; python_version >= "3.6" \ --hash=sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97 \ --hash=sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835