From 5e4a59e15ff15fccf3cfa934fa41d939081dbc96 Mon Sep 17 00:00:00 2001 From: Lunaresk Date: Sun, 16 Jul 2023 23:53:30 +0200 Subject: [PATCH] Merge remote-tracking branch 'origin/feat_receipt_upload' --- Dockerfile | 21 +- Pipfile | 12 - Pipfile.lock | 141 -------- backend/Pipfile | 11 +- backend/Pipfile.lock | 312 ++++++++++-------- backend/configs/config.py | 2 +- .../f6f97ed9c053_receipt_id_reorganized.py | 64 ++++ backend/{src => }/models/__init__.py | 0 backend/{src => }/models/amount_change.py | 0 backend/{src => }/models/bought.py | 0 backend/{src => }/models/brand.py | 2 +- backend/{src => }/models/category.py | 4 +- backend/{src => }/models/establishment.py | 2 +- .../models/establishment_candidate.py | 0 backend/{src => }/models/item.py | 2 +- backend/{src => }/models/item_category.py | 0 backend/{src => }/models/login_token.py | 0 backend/{src => }/models/payment.py | 0 backend/{src => }/models/price_change.py | 0 backend/{src => }/models/receipt.py | 4 +- backend/{src => }/models/receipt_item.py | 0 backend/{src => }/models/schemas/__init__.py | 0 .../{src => }/models/schemas/amount_change.py | 4 +- backend/{src => }/models/schemas/bought.py | 5 +- backend/{src => }/models/schemas/brand.py | 2 +- backend/{src => }/models/schemas/category.py | 2 +- .../{src => }/models/schemas/establishment.py | 4 +- .../models/schemas/establishment_candidate.py | 5 +- backend/models/schemas/item.py | 18 + .../{src => }/models/schemas/login_token.py | 5 +- backend/{src => }/models/schemas/payment.py | 4 +- .../{src => }/models/schemas/price_change.py | 5 +- backend/{src => }/models/schemas/receipt.py | 7 +- .../{src => }/models/schemas/receipt_item.py | 5 +- backend/{src => }/models/schemas/user.py | 2 +- backend/{src => }/models/user.py | 2 +- backend/requirements.txt | Bin 0 -> 3634 bytes backend/run.py | 2 +- backend/src/__init__.py | 4 +- backend/src/api/v1/routes.py | 2 +- backend/src/auth/forms.py | 2 +- backend/src/auth/routes.py | 2 +- .../src/establishment/candidates/routes.py | 2 +- backend/src/establishment/list/routes.py | 4 +- backend/src/establishment/list/utils.py | 2 +- backend/src/establishment/new/routes.py | 2 +- backend/src/establishment/overview/routes.py | 2 +- backend/src/establishment/payment/forms.py | 2 +- backend/src/establishment/payment/routes.py | 2 +- backend/src/item/__init__.py | 6 +- backend/src/item/details/__init__.py | 5 + backend/src/item/details/routes.py | 14 + backend/src/item/list/routes.py | 4 +- backend/src/item/new/forms.py | 2 +- backend/src/item/new/routes.py | 2 +- backend/src/item/update/__init__.py | 7 + .../src/item/update/amount_change/__init__.py | 5 + .../src/item/update/amount_change/forms.py | 9 + .../src/item/update/amount_change/routes.py | 24 ++ .../src/item/update/price_change/__init__.py | 5 + backend/src/item/update/price_change/forms.py | 9 + .../src/item/update/price_change/routes.py | 24 ++ backend/src/models/schemas/item.py | 14 - backend/src/receipts/confirm/__init__.py | 5 + backend/src/receipts/confirm/forms.py | 18 + backend/src/receipts/confirm/routes.py | 36 ++ backend/src/receipts/routes.py | 41 +-- backend/src/receipts/upload/__init__.py | 5 + backend/src/receipts/upload/forms.py | 7 + backend/src/receipts/upload/routes.py | 37 +++ .../src/templates/item/list/show_items.html | 29 -- backend/src/utils/database_utils.py | 2 +- .../{ => utils}/modules/flatastic/__init__.py | 0 .../modules/flatastic/flatastic.py | 0 backend/src/utils/view_utils.py | 6 +- backend/{src => web}/static/sidebars.css | 0 .../{src => web}/templates/auth/login.html | 0 .../{src => web}/templates/auth/register.html | 0 .../templates/auth/reset_password.html | 0 .../auth/reset_password_request.html | 0 backend/{src => web}/templates/base.html | 0 .../templates/email/reset_password.html | 0 .../templates/email/reset_password.txt | 0 .../{src => web}/templates/errors/403.html | 0 .../{src => web}/templates/errors/404.html | 0 .../{src => web}/templates/errors/500.html | 0 .../candidates/_candidate_evaluation.html | 0 .../establishment/candidates/candidates.html | 0 .../list/establishment_list.html | 0 .../list/establishment_request.html | 0 .../establishment/new/new_establishment.html | 0 .../new/new_establishment_form.html | 0 .../establishment/overview/overview.html | 0 .../establishment/payment/new_payment.html | 0 .../payment/new_payment_form.html | 0 .../web/templates/item/details/show_item.html | 79 +++++ .../web/templates/item/list/show_items.html | 32 ++ .../templates/item/new/new_item.html | 0 .../templates/item/new/new_item_form.html | 0 .../item/update/_item_to_change.html | 1 + .../update/amount_change/amount_change.html | 7 + .../amount_change/amount_change_form.html | 7 + .../update/price_change/price_change.html | 7 + .../price_change/price_change_form.html | 7 + .../{src => web}/templates/main/overview.html | 0 .../templates/receipts/confirm_items.html | 0 .../templates/receipts/upload.html | 0 .../templates/utils/form/_render_field.html | 0 .../utils/general/_page_navigation.html | 0 109 files changed, 700 insertions(+), 431 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock create mode 100644 backend/migrations/versions/f6f97ed9c053_receipt_id_reorganized.py rename backend/{src => }/models/__init__.py (100%) rename backend/{src => }/models/amount_change.py (100%) rename backend/{src => }/models/bought.py (100%) rename backend/{src => }/models/brand.py (78%) rename backend/{src => }/models/category.py (74%) rename backend/{src => }/models/establishment.py (89%) rename backend/{src => }/models/establishment_candidate.py (100%) rename backend/{src => }/models/item.py (94%) rename backend/{src => }/models/item_category.py (100%) rename backend/{src => }/models/login_token.py (100%) rename backend/{src => }/models/payment.py (100%) rename backend/{src => }/models/price_change.py (100%) rename backend/{src => }/models/receipt.py (77%) rename backend/{src => }/models/receipt_item.py (100%) rename backend/{src => }/models/schemas/__init__.py (100%) rename backend/{src => }/models/schemas/amount_change.py (65%) rename backend/{src => }/models/schemas/bought.py (72%) rename backend/{src => }/models/schemas/brand.py (83%) rename backend/{src => }/models/schemas/category.py (86%) rename backend/{src => }/models/schemas/establishment.py (74%) rename backend/{src => }/models/schemas/establishment_candidate.py (64%) create mode 100644 backend/models/schemas/item.py rename backend/{src => }/models/schemas/login_token.py (68%) rename backend/{src => }/models/schemas/payment.py (76%) rename backend/{src => }/models/schemas/price_change.py (74%) rename backend/{src => }/models/schemas/receipt.py (72%) rename backend/{src => }/models/schemas/receipt_item.py (72%) rename backend/{src => }/models/schemas/user.py (86%) rename backend/{src => }/models/user.py (95%) create mode 100644 backend/requirements.txt create mode 100644 backend/src/item/details/__init__.py create mode 100644 backend/src/item/details/routes.py create mode 100644 backend/src/item/update/__init__.py create mode 100644 backend/src/item/update/amount_change/__init__.py create mode 100644 backend/src/item/update/amount_change/forms.py create mode 100644 backend/src/item/update/amount_change/routes.py create mode 100644 backend/src/item/update/price_change/__init__.py create mode 100644 backend/src/item/update/price_change/forms.py create mode 100644 backend/src/item/update/price_change/routes.py delete mode 100644 backend/src/models/schemas/item.py create mode 100644 backend/src/receipts/confirm/__init__.py create mode 100644 backend/src/receipts/confirm/forms.py create mode 100644 backend/src/receipts/confirm/routes.py create mode 100644 backend/src/receipts/upload/__init__.py create mode 100644 backend/src/receipts/upload/forms.py create mode 100644 backend/src/receipts/upload/routes.py delete mode 100644 backend/src/templates/item/list/show_items.html rename backend/src/{ => utils}/modules/flatastic/__init__.py (100%) rename backend/src/{ => utils}/modules/flatastic/flatastic.py (100%) rename backend/{src => web}/static/sidebars.css (100%) rename backend/{src => web}/templates/auth/login.html (100%) rename backend/{src => web}/templates/auth/register.html (100%) rename backend/{src => web}/templates/auth/reset_password.html (100%) rename backend/{src => web}/templates/auth/reset_password_request.html (100%) rename backend/{src => web}/templates/base.html (100%) rename backend/{src => web}/templates/email/reset_password.html (100%) rename backend/{src => web}/templates/email/reset_password.txt (100%) rename backend/{src => web}/templates/errors/403.html (100%) rename backend/{src => web}/templates/errors/404.html (100%) rename backend/{src => web}/templates/errors/500.html (100%) rename backend/{src => web}/templates/establishment/candidates/_candidate_evaluation.html (100%) rename backend/{src => web}/templates/establishment/candidates/candidates.html (100%) rename backend/{src => web}/templates/establishment/list/establishment_list.html (100%) rename backend/{src => web}/templates/establishment/list/establishment_request.html (100%) rename backend/{src => web}/templates/establishment/new/new_establishment.html (100%) rename backend/{src => web}/templates/establishment/new/new_establishment_form.html (100%) rename backend/{src => web}/templates/establishment/overview/overview.html (100%) rename backend/{src => web}/templates/establishment/payment/new_payment.html (100%) rename backend/{src => web}/templates/establishment/payment/new_payment_form.html (100%) create mode 100644 backend/web/templates/item/details/show_item.html create mode 100644 backend/web/templates/item/list/show_items.html rename backend/{src => web}/templates/item/new/new_item.html (100%) rename backend/{src => web}/templates/item/new/new_item_form.html (100%) create mode 100644 backend/web/templates/item/update/_item_to_change.html create mode 100644 backend/web/templates/item/update/amount_change/amount_change.html create mode 100644 backend/web/templates/item/update/amount_change/amount_change_form.html create mode 100644 backend/web/templates/item/update/price_change/price_change.html create mode 100644 backend/web/templates/item/update/price_change/price_change_form.html rename backend/{src => web}/templates/main/overview.html (100%) rename backend/{src => web}/templates/receipts/confirm_items.html (100%) rename backend/{src => web}/templates/receipts/upload.html (100%) rename backend/{src => web}/templates/utils/form/_render_field.html (100%) rename backend/{src => web}/templates/utils/general/_page_navigation.html (100%) diff --git a/Dockerfile b/Dockerfile index b420c77..135ac14 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,26 @@ -FROM python@sha256:075fe10ae13ea0f081540bead850eeb7b6c71d07ed4766d75f8529abd0101c44 -# python:3.10.10-slim-bullseye +FROM python@sha256:21c9f0b22213295a13bd678c5b45aa587ff6cb01cd99b6cf0e6928f4c777006b +# python:3.11.4-slim-bullseye (arm/v7) RUN useradd costhive WORKDIR /home/costhive -RUN apt update && apt -y upgrade -RUN apt install -y libpq-dev gcc g++ swig make +RUN apt update && apt -y upgrade; \ + apt install -y libpq-dev gcc g++ swig make; \ + rm -rf /var/lib/apt/lists COPY boot.sh requirements.txt ./ -RUN python -m venv venv -RUN venv/bin/pip install -r requirements.txt -RUN venv/bin/pip install gunicorn -RUN chmod +x boot.sh +RUN python -m venv venv; \ + venv/bin/pip install --upgrade pip; \ + venv/bin/pip install wheel; \ + venv/bin/pip install gunicorn; \ + venv/bin/pip install -r requirements.txt COPY backend backend ENV FLASK_APP run.py -RUN chown -R costhive:costhive ./ +RUN chmod +x boot.sh; \ + chown -R costhive:costhive ./ USER costhive diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 22a7d0d..0000000 --- a/Pipfile +++ /dev/null @@ -1,12 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -flask-cors = "*" - -[dev-packages] - -[requires] -python_version = "3.10" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 204c297..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,141 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "2f46680952b8ccfaf093f8ef1315053afb3d2e15fc244d50f313d0961890dfc3" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.10" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "click": { - "hashes": [ - "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" - ], - "markers": "python_version >= '3.7'", - "version": "==8.1.3" - }, - "colorama": { - "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - ], - "markers": "platform_system == 'Windows'", - "version": "==0.4.6" - }, - "flask": { - "hashes": [ - "sha256:7eb373984bf1c770023fce9db164ed0c3353cd0b53f130f4693da0ca756a2e6d", - "sha256:c0bec9477df1cb867e5a67c9e1ab758de9cb4a3e52dd70681f59fa40a62b3f2d" - ], - "markers": "python_version >= '3.7'", - "version": "==2.2.3" - }, - "flask-cors": { - "hashes": [ - "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438", - "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de" - ], - "index": "pypi", - "version": "==3.0.10" - }, - "itsdangerous": { - "hashes": [ - "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", - "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.2" - }, - "jinja2": { - "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.2" - }, - "markupsafe": { - "hashes": [ - "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed", - "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc", - "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2", - "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460", - "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7", - "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0", - "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1", - "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa", - "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03", - "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323", - "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65", - "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013", - "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036", - "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f", - "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4", - "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419", - "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2", - "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619", - "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a", - "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a", - "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd", - "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7", - "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666", - "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65", - "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859", - "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625", - "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff", - "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156", - "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd", - "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba", - "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f", - "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1", - "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094", - "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a", - "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513", - "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed", - "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d", - "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3", - "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147", - "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c", - "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603", - "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601", - "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a", - "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1", - "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d", - "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3", - "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54", - "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2", - "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6", - "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.2" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.16.0" - }, - "werkzeug": { - "hashes": [ - "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe", - "sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612" - ], - "markers": "python_version >= '3.7'", - "version": "==2.2.3" - } - }, - "develop": {} -} diff --git a/backend/Pipfile b/backend/Pipfile index 136e31f..427a791 100644 --- a/backend/Pipfile +++ b/backend/Pipfile @@ -7,22 +7,23 @@ name = "pypi" email-validator = "*" flask = "*" flask-bootstrap = "*" +flask-cors = "*" flask-login = "*" flask-mail = "*" +flask-marshmallow = "*" flask-migrate = "*" flask-sqlalchemy = "*" flask-wtf = "*" +marshmallow-sqlalchemy = "*" psycopg2-binary = "*" pyjwt = "*" python-dotenv = "*" pymupdf = "*" -sqlalchemy-utils = "*" -flask-marshmallow = "*" -marshmallow-sqlalchemy = "*" requests = "*" +sqlalchemy-utils = "*" [dev-packages] [requires] -python_version = "3.10" -python_full_version = "3.10.10" +python_version = "3.11" +python_full_version = "3.11.4" diff --git a/backend/Pipfile.lock b/backend/Pipfile.lock index f1099e4..10319cb 100644 --- a/backend/Pipfile.lock +++ b/backend/Pipfile.lock @@ -1,12 +1,12 @@ { "_meta": { "hash": { - "sha256": "d2a442d0df6bf1581b3b231990af6de00853e9a6c1381b756a8056ac9f2bead3" + "sha256": "6aa4fc89c41e2a25283179a13d468214fdebcbd824a74a7f2f79482b920eed78" }, "pipfile-spec": 6, "requires": { - "python_full_version": "3.10.10", - "python_version": "3.10" + "python_full_version": "3.11.4", + "python_version": "3.11" }, "sources": [ { @@ -25,6 +25,14 @@ "markers": "python_version >= '3.7'", "version": "==1.11.1" }, + "anyio": { + "hashes": [ + "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780", + "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5" + ], + "markers": "python_version >= '3.7'", + "version": "==3.7.1" + }, "blinker": { "hashes": [ "sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213", @@ -43,92 +51,92 @@ }, "charset-normalizer": { "hashes": [ - "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6", - "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1", - "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e", - "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373", - "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62", - "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230", - "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be", - "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c", - "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0", - "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448", - "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f", - "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649", - "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d", - "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0", - "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706", - "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a", - "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59", - "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23", - "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5", - "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb", - "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e", - "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e", - "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c", - "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28", - "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d", - "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41", - "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974", - "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce", - "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f", - "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1", - "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d", - "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8", - "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017", - "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31", - "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7", - "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8", - "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e", - "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14", - "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd", - "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d", - "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795", - "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b", - "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b", - "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b", - "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203", - "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f", - "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19", - "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1", - "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a", - "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac", - "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9", - "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0", - "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137", - "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f", - "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6", - "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5", - "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909", - "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f", - "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0", - "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324", - "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755", - "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb", - "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854", - "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c", - "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60", - "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84", - "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0", - "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b", - "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1", - "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531", - "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1", - "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11", - "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326", - "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df", - "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab" + "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", + "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", + "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", + "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", + "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", + "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", + "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", + "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", + "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", + "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", + "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", + "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", + "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", + "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", + "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", + "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", + "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", + "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", + "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", + "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", + "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", + "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", + "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", + "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", + "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", + "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", + "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", + "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", + "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", + "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", + "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", + "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", + "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", + "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", + "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", + "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", + "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", + "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", + "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", + "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", + "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", + "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", + "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", + "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", + "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", + "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", + "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", + "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", + "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", + "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", + "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", + "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", + "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", + "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", + "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", + "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", + "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", + "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", + "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", + "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", + "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", + "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", + "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", + "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", + "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", + "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", + "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", + "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", + "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", + "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", + "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", + "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", + "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", + "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", + "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.1.0" + "version": "==3.2.0" }, "click": { "hashes": [ - "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" + "sha256:4be4b1af8d665c6d942909916d31a213a106800c47d0eeba73d34da3cbc11367", + "sha256:e576aa487d679441d7d30abb87e1b43d24fc53bffb8758443b1a9e1cee504548" ], "markers": "python_version >= '3.7'", - "version": "==8.1.3" + "version": "==8.1.5" }, "colorama": { "hashes": [ @@ -140,11 +148,11 @@ }, "dnspython": { "hashes": [ - "sha256:224e32b03eb46be70e12ef6d64e0be123a64e621ab4c0822ff6d450d52a540b9", - "sha256:89141536394f909066cabd112e3e1a37e4e654db00a25308b0f130bc3152eb46" + "sha256:46b4052a55b56beea3a3bdd7b30295c292bd6827dd442348bc116f2d35b17f0a", + "sha256:758e691dbb454d5ccf4e1b154a19e52847f79e21a42fef17b969144af29a4e6c" ], - "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==2.3.0" + "markers": "python_version >= '3.8' and python_version < '4.0'", + "version": "==2.4.0" }, "dominate": { "hashes": [ @@ -162,6 +170,14 @@ "index": "pypi", "version": "==2.0.0.post2" }, + "exceptiongroup": { + "hashes": [ + "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5", + "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f" + ], + "markers": "python_version < '3.11'", + "version": "==1.1.2" + }, "flask": { "hashes": [ "sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0", @@ -177,6 +193,14 @@ "index": "pypi", "version": "==3.3.7.1" }, + "flask-cors": { + "hashes": [ + "sha256:bc3492bfd6368d27cfe79c7821df5a8a319e1a6d5eab277a3794be19bdc51783", + "sha256:f268522fcb2f73e2ecdde1ef45e2fd5c71cc48fe03cffb4b441c6d1b40684eb0" + ], + "index": "pypi", + "version": "==4.0.0" + }, "flask-login": { "hashes": [ "sha256:1ef79843f5eddd0f143c2cd994c1b05ac83c0401dc6234c143495af9a939613f", @@ -290,6 +314,22 @@ "markers": "platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))", "version": "==2.0.2" }, + "h11": { + "hashes": [ + "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", + "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, + "httpcore": { + "hashes": [ + "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888", + "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87" + ], + "markers": "python_version >= '3.8'", + "version": "==0.17.3" + }, "idna": { "hashes": [ "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", @@ -530,52 +570,60 @@ "index": "pypi", "version": "==2.31.0" }, - "sqlalchemy": { + "sniffio": { "hashes": [ - "sha256:04383f1e3452f6739084184e427e9d5cb4e68ddc765d52157bf5ef30d5eca14f", - "sha256:125f9f7e62ddf8b590c069729080ffe18b68a20d9882eb0947f72e06274601d7", - "sha256:1822620c89779b85f7c23d535c8e04b79c517739ae07aaed48c81e591ed5498e", - "sha256:21583808d37f126a647652c90332ac1d3a102edf3c94bcc3319edcc0ea2300cc", - "sha256:218fb20c01e95004f50a3062bf4c447dcb360cab8274232f31947e254f118298", - "sha256:2269b1f9b8be47e52b70936069a25a3771eff53367aa5cc59bb94f28a6412e13", - "sha256:234678ed6576531b8e4be255b980f20368bf07241a2e67b84e6b0fe679edb9c4", - "sha256:28da17059ecde53e2d10ba813d38db942b9f6344360b2958b25872d5cb729d35", - "sha256:2c6ff5767d954f6091113fedcaaf49cdec2197ae4c5301fe83d5ae4393c82f33", - "sha256:36a87e26fe8fa8c466fae461a8fcb780d0a1cbf8206900759fc6fe874475a3ce", - "sha256:394ac3adf3676fad76d4b8fcecddf747627f17f0738dc94bac15f303d05b03d4", - "sha256:40a3dc52b2b16f08b5c16b9ee7646329e4b3411e9280e5e8d57b19eaa51cbef4", - "sha256:48111d56afea5699bab72c38ec95561796b81befff9e13d1dd5ce251ab25f51d", - "sha256:48b40dc2895841ea89d89df9eb3ac69e2950a659db20a369acf4259f68e6dc1f", - "sha256:513411d73503a6fc5804f01fae3b3d44f267c1b3a06cfeac02e9286a7330e857", - "sha256:51736cfb607cf4e8fafb693906f9bc4e5ee55be0b096d44bd7f20cd8489b8571", - "sha256:5f40e3a7d0a464f1c8593f2991e5520b2f5b26da24e88000bbd4423f86103d4f", - "sha256:6150560fcffc6aee5ec9a97419ac768c7a9f56baf7a7eb59cb4b1b6a4d463ad9", - "sha256:724355973297bbe547f3eb98b46ade65a67a3d5a6303f17ab59a2dc6fb938943", - "sha256:74ddcafb6488f382854a7da851c404c394be3729bb3d91b02ad86c5458140eff", - "sha256:7830e01b02d440c27f2a5be68296e74ccb55e6a5b5962ffafd360b98930b2e5e", - "sha256:7f31d4e7ca1dd8ca5a27fd5eaa0f9e2732fe769ff7dd35bf7bba179597e4df07", - "sha256:8741d3d401383e54b2aada37cbd10f55c5d444b360eae3a82f74a2be568a7710", - "sha256:910d45bf3673f0e4ef13858674bd23cfdafdc8368b45b948bf511797dbbb401d", - "sha256:aa995b21f853864996e4056d9fde479bcecf8b7bff4beb3555eebbbba815f35d", - "sha256:af7e2ba75bf84b64adb331918188dda634689a2abb151bc1a583e488363fd2f8", - "sha256:b0eaf82cc844f6b46defe15ad243ea00d1e39ed3859df61130c263dc7204da6e", - "sha256:b114a16bc03dfe20b625062e456affd7b9938286e05a3f904a025b9aacc29dd4", - "sha256:b47be4c6281a86670ea5cfbbbe6c3a65366a8742f5bc8b986f790533c60b5ddb", - "sha256:ba03518e64d86f000dc24ab3d3a1aa876bcbaa8aa15662ac2df5e81537fa3394", - "sha256:cc9c2630c423ac4973492821b2969f5fe99d9736f3025da670095668fbfcd4d5", - "sha256:cf07ff9920cb3ca9d73525dfd4f36ddf9e1a83734ea8b4f724edfd9a2c6e82d9", - "sha256:cf175d26f6787cce30fe6c04303ca0aeeb0ad40eeb22e3391f24b32ec432a1e1", - "sha256:d0aeb3afaa19f187a70fa592fbe3c20a056b57662691fd3abf60f016aa5c1848", - "sha256:e186e9e95fb5d993b075c33fe4f38a22105f7ce11cecb5c17b5618181e356702", - "sha256:e2d5c3596254cf1a96474b98e7ce20041c74c008b0f101c1cb4f8261cb77c6d3", - "sha256:e3189432db2f5753b4fde1aa90a61c69976f4e7e31d1cf4611bfe3514ed07478", - "sha256:e3a6b2788f193756076061626679c5c5a6d600ddf8324f986bc72004c3e9d92e", - "sha256:ead58cae2a089eee1b0569060999cb5f2b2462109498a0937cc230a7556945a1", - "sha256:f2f389f77c68dc22cb51f026619291c4a38aeb4b7ecb5f998fd145b2d81ca513", - "sha256:f593170fc09c5abb1205a738290b39532f7380094dc151805009a07ae0e85330" + "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", + "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" ], "markers": "python_version >= '3.7'", - "version": "==2.0.17" + "version": "==1.3.0" + }, + "sqlalchemy": { + "hashes": [ + "sha256:024d2f67fb3ec697555e48caeb7147cfe2c08065a4f1a52d93c3d44fc8e6ad1c", + "sha256:0bf0fd65b50a330261ec7fe3d091dfc1c577483c96a9fa1e4323e932961aa1b5", + "sha256:16a310f5bc75a5b2ce7cb656d0e76eb13440b8354f927ff15cbaddd2523ee2d1", + "sha256:1d90ccc15ba1baa345796a8fb1965223ca7ded2d235ccbef80a47b85cea2d71a", + "sha256:22bafb1da60c24514c141a7ff852b52f9f573fb933b1e6b5263f0daa28ce6db9", + "sha256:2c69ce70047b801d2aba3e5ff3cba32014558966109fecab0c39d16c18510f15", + "sha256:2e7b69d9ced4b53310a87117824b23c509c6fc1f692aa7272d47561347e133b6", + "sha256:314145c1389b021a9ad5aa3a18bac6f5d939f9087d7fc5443be28cba19d2c972", + "sha256:3afa8a21a9046917b3a12ffe016ba7ebe7a55a6fc0c7d950beb303c735c3c3ad", + "sha256:430614f18443b58ceb9dedec323ecddc0abb2b34e79d03503b5a7579cd73a531", + "sha256:43699eb3f80920cc39a380c159ae21c8a8924fe071bccb68fc509e099420b148", + "sha256:539010665c90e60c4a1650afe4ab49ca100c74e6aef882466f1de6471d414be7", + "sha256:57d100a421d9ab4874f51285c059003292433c648df6abe6c9c904e5bd5b0828", + "sha256:5831138f0cc06b43edf5f99541c64adf0ab0d41f9a4471fd63b54ae18399e4de", + "sha256:584f66e5e1979a7a00f4935015840be627e31ca29ad13f49a6e51e97a3fb8cae", + "sha256:5d6afc41ca0ecf373366fd8e10aee2797128d3ae45eb8467b19da4899bcd1ee0", + "sha256:61ada5831db36d897e28eb95f0f81814525e0d7927fb51145526c4e63174920b", + "sha256:6b54d1ad7a162857bb7c8ef689049c7cd9eae2f38864fc096d62ae10bc100c7d", + "sha256:7351c05db355da112e056a7b731253cbeffab9dfdb3be1e895368513c7d70106", + "sha256:77a14fa20264af73ddcdb1e2b9c5a829b8cc6b8304d0f093271980e36c200a3f", + "sha256:851a37898a8a39783aab603c7348eb5b20d83c76a14766a43f56e6ad422d1ec8", + "sha256:89bc2b374ebee1a02fd2eae6fd0570b5ad897ee514e0f84c5c137c942772aa0c", + "sha256:8e712cfd2e07b801bc6b60fdf64853bc2bd0af33ca8fa46166a23fe11ce0dbb0", + "sha256:8f9eb4575bfa5afc4b066528302bf12083da3175f71b64a43a7c0badda2be365", + "sha256:8fc05b59142445a4efb9c1fd75c334b431d35c304b0e33f4fa0ff1ea4890f92e", + "sha256:96f0463573469579d32ad0c91929548d78314ef95c210a8115346271beeeaaa2", + "sha256:9deaae357edc2091a9ed5d25e9ee8bba98bcfae454b3911adeaf159c2e9ca9e3", + "sha256:a752b7a9aceb0ba173955d4f780c64ee15a1a991f1c52d307d6215c6c73b3a4c", + "sha256:ae7473a67cd82a41decfea58c0eac581209a0aa30f8bc9190926fbf628bb17f7", + "sha256:b15afbf5aa76f2241184c1d3b61af1a72ba31ce4161013d7cb5c4c2fca04fd6e", + "sha256:c896d4e6ab2eba2afa1d56be3d0b936c56d4666e789bfc59d6ae76e9fcf46145", + "sha256:cb4e688f6784427e5f9479d1a13617f573de8f7d4aa713ba82813bcd16e259d1", + "sha256:cda283700c984e699e8ef0fcc5c61f00c9d14b6f65a4f2767c97242513fcdd84", + "sha256:cf7b5e3856cbf1876da4e9d9715546fa26b6e0ba1a682d5ed2fc3ca4c7c3ec5b", + "sha256:d6894708eeb81f6d8193e996257223b6bb4041cb05a17cd5cf373ed836ef87a2", + "sha256:d8f2afd1aafded7362b397581772c670f20ea84d0a780b93a1a1529da7c3d369", + "sha256:dd4d410a76c3762511ae075d50f379ae09551d92525aa5bb307f8343bf7c2c12", + "sha256:eb60699de43ba1a1f77363f563bb2c652f7748127ba3a774f7cf2c7804aa0d3d", + "sha256:f469f15068cd8351826df4080ffe4cc6377c5bf7d29b5a07b0e717dddb4c7ea2", + "sha256:f82c310ddf97b04e1392c33cf9a70909e0ae10a7e2ddc1d64495e3abdc5d19fb", + "sha256:fa51ce4aea583b0c6b426f4b0563d3535c1c75986c4373a0987d84d22376585b" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.19" }, "sqlalchemy-utils": { "hashes": [ @@ -587,11 +635,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:5d8c9dac95c27d20df12fb1d97b9793ab8b2af8a3a525e68c80e21060c161771", - "sha256:935ccf31549830cda708b42289d44b6f74084d616a00be651601a4f968e77c82" + "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36", + "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2" ], "markers": "python_version >= '3.7'", - "version": "==4.7.0" + "version": "==4.7.1" }, "urllib3": { "hashes": [ diff --git a/backend/configs/config.py b/backend/configs/config.py index 248d836..32543c8 100644 --- a/backend/configs/config.py +++ b/backend/configs/config.py @@ -18,4 +18,4 @@ class Config(object): MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') ADMINS = ['postmaster@wpgcommunity.net'] - POSTS_PER_PAGE = 10 + POSTS_PER_PAGE = 15 diff --git a/backend/migrations/versions/f6f97ed9c053_receipt_id_reorganized.py b/backend/migrations/versions/f6f97ed9c053_receipt_id_reorganized.py new file mode 100644 index 0000000..cfc264f --- /dev/null +++ b/backend/migrations/versions/f6f97ed9c053_receipt_id_reorganized.py @@ -0,0 +1,64 @@ +"""receipt-id reorganized + +Revision ID: f6f97ed9c053 +Revises: 4fec22c35530 +Create Date: 2023-07-02 14:16:06.260479 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f6f97ed9c053' +down_revision = '4fec22c35530' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('receipt_item', schema=None) as batch_op: + batch_op.add_column(sa.Column('accepted', sa.Boolean(), nullable=False)) + batch_op.drop_constraint("item_receipt_receipt_fkey") + batch_op.alter_column('receipt', + existing_type=sa.NUMERIC(precision=24, scale=0), + type_=sa.BigInteger(), + existing_nullable=False) + + with op.batch_alter_table('receipt', schema=None) as batch_op: + batch_op.add_column(sa.Column('bonid', sa.Numeric(precision=24, scale=0), nullable=True)) + + with op.batch_alter_table('receipt', schema=None) as batch_op: + batch_op.execute("UPDATE receipt SET bonid=id;") + batch_op.alter_column('id', + existing_type=sa.NUMERIC(precision=24, scale=0), + type_=sa.BigInteger(), + existing_nullable=False, + autoincrement=True) + batch_op.create_unique_constraint(None, ['bonid']) + + with op.batch_alter_table('receipt_item', schema=None) as batch_op: + batch_op.create_foreign_key(None, 'receipt', ['receipt'], ['id']) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('receipt_item', schema=None) as batch_op: + batch_op.alter_column('receipt', + existing_type=sa.BigInteger(), + type_=sa.NUMERIC(precision=24, scale=0), + existing_nullable=False) + batch_op.drop_column('accepted') + + with op.batch_alter_table('receipt', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='unique') + batch_op.alter_column('id', + existing_type=sa.BigInteger(), + type_=sa.NUMERIC(precision=24, scale=0), + existing_nullable=False, + autoincrement=True) + batch_op.drop_column('bonid') + + # ### end Alembic commands ### diff --git a/backend/src/models/__init__.py b/backend/models/__init__.py similarity index 100% rename from backend/src/models/__init__.py rename to backend/models/__init__.py diff --git a/backend/src/models/amount_change.py b/backend/models/amount_change.py similarity index 100% rename from backend/src/models/amount_change.py rename to backend/models/amount_change.py diff --git a/backend/src/models/bought.py b/backend/models/bought.py similarity index 100% rename from backend/src/models/bought.py rename to backend/models/bought.py diff --git a/backend/src/models/brand.py b/backend/models/brand.py similarity index 78% rename from backend/src/models/brand.py rename to backend/models/brand.py index 1d78a58..59080eb 100644 --- a/backend/src/models/brand.py +++ b/backend/models/brand.py @@ -2,7 +2,7 @@ from src import db class Brand(db.Model): - id = db.Column(db.Integer, primary_key=True) + id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(32), nullable=False) Item = db.relationship("Item", backref='Brand', lazy='dynamic') diff --git a/backend/src/models/category.py b/backend/models/category.py similarity index 74% rename from backend/src/models/category.py rename to backend/models/category.py index 9caf10e..5d2f997 100644 --- a/backend/src/models/category.py +++ b/backend/models/category.py @@ -1,9 +1,9 @@ from src import db -from src.models.item_category import item_category +from .item_category import item_category class Category(db.Model): - id = db.Column(db.Integer, primary_key=True) + id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(32), nullable=False, unique=True) Item = db.relationship("Item", secondary=item_category, diff --git a/backend/src/models/establishment.py b/backend/models/establishment.py similarity index 89% rename from backend/src/models/establishment.py rename to backend/models/establishment.py index 3d72f97..90b816c 100644 --- a/backend/src/models/establishment.py +++ b/backend/models/establishment.py @@ -2,7 +2,7 @@ from src import db class Establishment(db.Model): - id = db.Column(db.BigInteger, primary_key=True) + id = db.Column(db.BigInteger, primary_key=True, autoincrement=True) name = db.Column(db.String(64), nullable=False) owner = db.Column(db.ForeignKey('user.id'), nullable=False) diff --git a/backend/src/models/establishment_candidate.py b/backend/models/establishment_candidate.py similarity index 100% rename from backend/src/models/establishment_candidate.py rename to backend/models/establishment_candidate.py diff --git a/backend/src/models/item.py b/backend/models/item.py similarity index 94% rename from backend/src/models/item.py rename to backend/models/item.py index bcce584..87f9b39 100644 --- a/backend/src/models/item.py +++ b/backend/models/item.py @@ -1,5 +1,5 @@ from src import db, ma -from src.models.item_category import item_category +from .item_category import item_category class Item(db.Model): diff --git a/backend/src/models/item_category.py b/backend/models/item_category.py similarity index 100% rename from backend/src/models/item_category.py rename to backend/models/item_category.py diff --git a/backend/src/models/login_token.py b/backend/models/login_token.py similarity index 100% rename from backend/src/models/login_token.py rename to backend/models/login_token.py diff --git a/backend/src/models/payment.py b/backend/models/payment.py similarity index 100% rename from backend/src/models/payment.py rename to backend/models/payment.py diff --git a/backend/src/models/price_change.py b/backend/models/price_change.py similarity index 100% rename from backend/src/models/price_change.py rename to backend/models/price_change.py diff --git a/backend/src/models/receipt.py b/backend/models/receipt.py similarity index 77% rename from backend/src/models/receipt.py rename to backend/models/receipt.py index 20d0d44..6fdf206 100644 --- a/backend/src/models/receipt.py +++ b/backend/models/receipt.py @@ -2,9 +2,9 @@ from src import db class Receipt(db.Model): - id = db.Column(db.Numeric(precision=24, scale=0), - primary_key=True, autoincrement=False) + id = db.Column(db.BigInteger, primary_key=True, autoincrement=True) date = db.Column(db.Date, nullable=False) + bonid = db.Column(db.Numeric(precision=24, scale=0), unique=True) from_user = db.Column(db.ForeignKey("login_token.token"), server_onupdate=db.FetchedValue()) registered = db.Column(db.Boolean, nullable=False, diff --git a/backend/src/models/receipt_item.py b/backend/models/receipt_item.py similarity index 100% rename from backend/src/models/receipt_item.py rename to backend/models/receipt_item.py diff --git a/backend/src/models/schemas/__init__.py b/backend/models/schemas/__init__.py similarity index 100% rename from backend/src/models/schemas/__init__.py rename to backend/models/schemas/__init__.py diff --git a/backend/src/models/schemas/amount_change.py b/backend/models/schemas/amount_change.py similarity index 65% rename from backend/src/models/schemas/amount_change.py rename to backend/models/schemas/amount_change.py index 496e1e6..3951d69 100644 --- a/backend/src/models/schemas/amount_change.py +++ b/backend/models/schemas/amount_change.py @@ -1,6 +1,6 @@ from src import ma -from src.models import AmountChange -from src.models.schemas import ItemSchema +from ..amount_change import AmountChange +from .item import ItemSchema class AmountChangeSchema(ma.SQLAlchemySchema): diff --git a/backend/src/models/schemas/bought.py b/backend/models/schemas/bought.py similarity index 72% rename from backend/src/models/schemas/bought.py rename to backend/models/schemas/bought.py index 987c411..8d158f8 100644 --- a/backend/src/models/schemas/bought.py +++ b/backend/models/schemas/bought.py @@ -1,6 +1,7 @@ from src import ma -from src.models import Bought -from src.models.schemas import LoginTokenSchema, ItemSchema +from ..bought import Bought +from .login_token import LoginTokenSchema +from .item import ItemSchema class BoughtSchema(ma.SQLAlchemySchema): diff --git a/backend/src/models/schemas/brand.py b/backend/models/schemas/brand.py similarity index 83% rename from backend/src/models/schemas/brand.py rename to backend/models/schemas/brand.py index 1b63597..f9762fb 100644 --- a/backend/src/models/schemas/brand.py +++ b/backend/models/schemas/brand.py @@ -1,5 +1,5 @@ from src import ma -from src.models import Brand +from ..brand import Brand class BrandSchema(ma.SQLAlchemySchema): diff --git a/backend/src/models/schemas/category.py b/backend/models/schemas/category.py similarity index 86% rename from backend/src/models/schemas/category.py rename to backend/models/schemas/category.py index 62d4d97..43d8b5f 100644 --- a/backend/src/models/schemas/category.py +++ b/backend/models/schemas/category.py @@ -1,6 +1,6 @@ # from marshmallow import Schema, fields from src import ma -from src.models import Category +from ..category import Category class CategorySchema(ma.SQLAlchemySchema): diff --git a/backend/src/models/schemas/establishment.py b/backend/models/schemas/establishment.py similarity index 74% rename from backend/src/models/schemas/establishment.py rename to backend/models/schemas/establishment.py index fcaef87..578e3a0 100644 --- a/backend/src/models/schemas/establishment.py +++ b/backend/models/schemas/establishment.py @@ -1,6 +1,6 @@ from src import ma -from src.models import Establishment -from src.models.schemas import UserSchema +from ..establishment import Establishment +from .user import UserSchema class EstablishmentSchema(ma.SQLAlchemySchema): diff --git a/backend/src/models/schemas/establishment_candidate.py b/backend/models/schemas/establishment_candidate.py similarity index 64% rename from backend/src/models/schemas/establishment_candidate.py rename to backend/models/schemas/establishment_candidate.py index 7f8278e..51dd97c 100644 --- a/backend/src/models/schemas/establishment_candidate.py +++ b/backend/models/schemas/establishment_candidate.py @@ -1,6 +1,7 @@ from src import ma -from src.models import EstablishmentCandidate -from src.models.schemas import EstablishmentSchema, UserSchema +from ..establishment_candidate import EstablishmentCandidate +from .establishment import EstablishmentSchema +from .user import UserSchema class EstablishmentCandidateSchema(ma.SQLAlchemySchema): diff --git a/backend/models/schemas/item.py b/backend/models/schemas/item.py new file mode 100644 index 0000000..f3bf711 --- /dev/null +++ b/backend/models/schemas/item.py @@ -0,0 +1,18 @@ +from src import ma +from ..item import Item +from .brand import BrandSchema + +class ItemSchema(ma.SQLAlchemySchema): + class Meta: + model = Item + include_fk = True + + id = ma.auto_field() + name = ma.auto_field() + description = ma.auto_field() + Brand = ma.Nested(BrandSchema) + PriceChange = ma.List(ma.Nested(lambda: PriceChangeSchema(exclude=("Item",)))) + AmountChange = ma.List(ma.Nested(lambda: AmountChangeSchema(exclude=("Item",)))) + +from .price_change import PriceChangeSchema +from .amount_change import AmountChangeSchema \ No newline at end of file diff --git a/backend/src/models/schemas/login_token.py b/backend/models/schemas/login_token.py similarity index 68% rename from backend/src/models/schemas/login_token.py rename to backend/models/schemas/login_token.py index 2b23450..77eab3d 100644 --- a/backend/src/models/schemas/login_token.py +++ b/backend/models/schemas/login_token.py @@ -1,6 +1,7 @@ from src import ma -from src.models import LoginToken -from src.models.schemas import EstablishmentSchema, UserSchema +from ..login_token import LoginToken +from .establishment import EstablishmentSchema +from .user import UserSchema class LoginTokenSchema(ma.SQLAlchemySchema): diff --git a/backend/src/models/schemas/payment.py b/backend/models/schemas/payment.py similarity index 76% rename from backend/src/models/schemas/payment.py rename to backend/models/schemas/payment.py index a6e5681..df39aaf 100644 --- a/backend/src/models/schemas/payment.py +++ b/backend/models/schemas/payment.py @@ -1,6 +1,6 @@ from src import ma -from src.models import Payment -from src.models.schemas import LoginTokenSchema +from ..payment import Payment +from .login_token import LoginTokenSchema class PaymentSchema(ma.SQLAlchemySchema): diff --git a/backend/src/models/schemas/price_change.py b/backend/models/schemas/price_change.py similarity index 74% rename from backend/src/models/schemas/price_change.py rename to backend/models/schemas/price_change.py index da631b0..fc08fa2 100644 --- a/backend/src/models/schemas/price_change.py +++ b/backend/models/schemas/price_change.py @@ -1,7 +1,6 @@ from src import ma -from src.models import PriceChange -from src.models.schemas import ItemSchema - +from .item import ItemSchema +from ..price_change import PriceChange class PriceChangeSchema(ma.SQLAlchemySchema): class Meta: diff --git a/backend/src/models/schemas/receipt.py b/backend/models/schemas/receipt.py similarity index 72% rename from backend/src/models/schemas/receipt.py rename to backend/models/schemas/receipt.py index c5b3f1f..dddc722 100644 --- a/backend/src/models/schemas/receipt.py +++ b/backend/models/schemas/receipt.py @@ -1,6 +1,6 @@ from src import ma -from src.models import Receipt -from src.models.schemas import LoginTokenSchema +from ..receipt import Receipt +from .login_token import LoginTokenSchema class ReceiptSchema(ma.SQLAlchemySchema): @@ -10,5 +10,6 @@ class ReceiptSchema(ma.SQLAlchemySchema): id = ma.auto_field() date = ma.auto_field() - LoginToken = ma.Nested(LoginTokenSchema) + bonid = ma.auto_field() registered = ma.auto_field() + LoginToken = ma.Nested(LoginTokenSchema) diff --git a/backend/src/models/schemas/receipt_item.py b/backend/models/schemas/receipt_item.py similarity index 72% rename from backend/src/models/schemas/receipt_item.py rename to backend/models/schemas/receipt_item.py index 3d2bf6c..f2dae03 100644 --- a/backend/src/models/schemas/receipt_item.py +++ b/backend/models/schemas/receipt_item.py @@ -1,6 +1,7 @@ from src import ma -from src.models import ReceiptItem -from src.models.schemas import ItemSchema, ReceiptSchema +from ..receipt_item import ReceiptItem +from .item import ItemSchema +from .receipt import ReceiptSchema class ReceiptItemSchema(ma.SQLAlchemySchema): diff --git a/backend/src/models/schemas/user.py b/backend/models/schemas/user.py similarity index 86% rename from backend/src/models/schemas/user.py rename to backend/models/schemas/user.py index ed9eeb1..4f1d0b0 100644 --- a/backend/src/models/schemas/user.py +++ b/backend/models/schemas/user.py @@ -1,5 +1,5 @@ from src import ma -from src.models import User +from ..user import User class UserSchema(ma.SQLAlchemySchema): diff --git a/backend/src/models/user.py b/backend/models/user.py similarity index 95% rename from backend/src/models/user.py rename to backend/models/user.py index 5250569..cd4dae0 100644 --- a/backend/src/models/user.py +++ b/backend/models/user.py @@ -7,7 +7,7 @@ from werkzeug.security import generate_password_hash, check_password_hash class User(UserMixin, db.Model): - id = db.Column(db.BigInteger, primary_key=True) + id = db.Column(db.BigInteger, primary_key=True, autoincrement=True) email = db.Column(db.String(255), nullable=False, unique=True) password_hash = db.Column(db.String(128), nullable=False) diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a48cf01a2d14660de2815c2761e80d6b1a030db GIT binary patch literal 3634 zcmbuCOLG!Y5QTefmH&aAS|yr+gv4i+Rc>79Hp>*@o$xYDAo%0e^L5W<^1uj_nwmi1 z_PM7|pYFN*`CYe>)of_FuDLDjy}i{nx3%t(y|I~H*+8Ex^xs6EjjdPE7UITNgn2{pDi*LZJhITH7 zBkgtRJ12%M?boP?*m0y>sD0faHtaw*OpiQ|{g}3jygO2C`y~_FC`pMYeg@*t}~N>Y;C2abtOF zS-7g}wV)D7Nvg#?*FIFG;XT>28})ZjpW=IZcc7S=+&1^f==$AyDzpr?S;4I@R&DJU zE<}@XIrE_WuC6&V)0I23D@DZatmQt|ojKpzF?f=hLxxd7GQ5wBYX`0>>rfzO#Qk+i z!?fz%);(FpoN|)Ci6M*kOO`~*V0jm@8JW!3;XGsja8SS_s-h!(E;{H4a|iP( z<^cYt3#y(0F1$Jy!ftGMJ_V0{x)eWh4xIh-PF0E7bLq2rA>6)lPdyFxzIC~ayKSaX zrOcRw`#kw#Vn@xl&&#^1wSCIrvPQ8Zo|!98&M@s_h7XF2gIP6qa}Hh$btd$IcH`;8 zykoM*ti?rS-E!Y@g1FF>FDEEn5L2G-CSH;5tr^@9YMRuy&mVQUmZuyudAacfIR_f^ z`lrx(Vu;66b(`*;ShG+pCsfX;rLWMVYK{I?i}b9(0o9b=hFn*EoHfQpeq?{>`NdN! zm!kYOp||T&;-=7xUnrbU%IAHY3aT-?R;_t@k5v2SMrXKG?V_cy;FybLoVq}ZzQoBZ k<#Ht_bKbvJZe?xD6ZEdXsM17@CqMg53SGhn>|0HjzmG98<^TWy literal 0 HcmV?d00001 diff --git a/backend/run.py b/backend/run.py index 968918f..8361fd6 100644 --- a/backend/run.py +++ b/backend/run.py @@ -1,5 +1,5 @@ from src import create_app, db -from src.models import * +from models import * app = create_app() diff --git a/backend/src/__init__.py b/backend/src/__init__.py index 16a5233..6245975 100644 --- a/backend/src/__init__.py +++ b/backend/src/__init__.py @@ -38,7 +38,7 @@ migrate = Migrate() def create_app(config_class=Config): - app = Flask(__name__) + app = Flask(__name__, template_folder="../web/templates", static_folder="../web/static") app.config.from_object(config_class) bootstrap.init_app(app) cors.init_app(app) @@ -65,4 +65,4 @@ def create_app(config_class=Config): return app -from src.models import * \ No newline at end of file +from models import * \ No newline at end of file diff --git a/backend/src/api/v1/routes.py b/backend/src/api/v1/routes.py index 4c3190d..b55cdbc 100644 --- a/backend/src/api/v1/routes.py +++ b/backend/src/api/v1/routes.py @@ -1,6 +1,6 @@ from src import LOGGER from src.api.v1 import bp -from src.models.login_token import LoginToken +from models.login_token import LoginToken from src.utils import database_utils from flask import abort, request from flask.json import jsonify diff --git a/backend/src/auth/forms.py b/backend/src/auth/forms.py index 9d34847..5f2b1c4 100644 --- a/backend/src/auth/forms.py +++ b/backend/src/auth/forms.py @@ -1,4 +1,4 @@ -from src.models.user import User +from models.user import User from flask_wtf import FlaskForm from wtforms import BooleanField, PasswordField, StringField, SubmitField from wtforms.validators import DataRequired, Email, EqualTo, ValidationError diff --git a/backend/src/auth/routes.py b/backend/src/auth/routes.py index 741c89c..ae396c8 100644 --- a/backend/src/auth/routes.py +++ b/backend/src/auth/routes.py @@ -2,7 +2,7 @@ from src import db from . import bp from .email import send_password_reset_email from .forms import LoginForm, RegistrationForm, ResetPasswordForm, ResetPasswordRequestForm -from src.models.user import User +from models.user import User from src.utils.routes_utils import render_custom_template as render_template from flask import flash, redirect, request, url_for from flask_login import current_user, login_user, logout_user diff --git a/backend/src/establishment/candidates/routes.py b/backend/src/establishment/candidates/routes.py index db4c54a..9e8796c 100644 --- a/backend/src/establishment/candidates/routes.py +++ b/backend/src/establishment/candidates/routes.py @@ -3,7 +3,7 @@ from flask_login import current_user, login_required from . import bp from .forms import EvaluateCandidateForm from src import db, LOGGER -from src.models import Establishment, EstablishmentCandidate, LoginToken, User +from models import Establishment, EstablishmentCandidate, LoginToken, User from src.utils.routes_utils import render_custom_template as render_template from src.utils.database_utils import generate_token diff --git a/backend/src/establishment/list/routes.py b/backend/src/establishment/list/routes.py index 05bfd52..263e77b 100644 --- a/backend/src/establishment/list/routes.py +++ b/backend/src/establishment/list/routes.py @@ -5,8 +5,8 @@ from . import bp from .forms import JoinEstablishmentForm from .utils import backend_validation from src import db -from src.models import Establishment -from src.models import EstablishmentCandidate +from models import Establishment +from models import EstablishmentCandidate from src.utils.routes_utils import render_custom_template as render_template diff --git a/backend/src/establishment/list/utils.py b/backend/src/establishment/list/utils.py index feb773a..d5bef30 100644 --- a/backend/src/establishment/list/utils.py +++ b/backend/src/establishment/list/utils.py @@ -1,5 +1,5 @@ from flask_login import current_user -from src.models import Establishment +from models import Establishment def backend_validation(join_establishment_form): diff --git a/backend/src/establishment/new/routes.py b/backend/src/establishment/new/routes.py index 1b28589..b5f9ee2 100644 --- a/backend/src/establishment/new/routes.py +++ b/backend/src/establishment/new/routes.py @@ -1,7 +1,7 @@ from . import bp from .forms import NewEstablishmentForm from src import db, LOGGER -from src.models import Establishment, LoginToken +from models import Establishment, LoginToken from src.utils import database_utils from src.utils.routes_utils import render_custom_template as render_template from flask import redirect, url_for diff --git a/backend/src/establishment/overview/routes.py b/backend/src/establishment/overview/routes.py index b49454e..e468775 100644 --- a/backend/src/establishment/overview/routes.py +++ b/backend/src/establishment/overview/routes.py @@ -3,7 +3,7 @@ from flask.json import jsonify from flask_login import current_user, login_required from . import bp from src import LOGGER -from src.models import Establishment +from models import Establishment from src.utils import view_utils, database_utils from src.utils.routes_utils import render_custom_template as render_template diff --git a/backend/src/establishment/payment/forms.py b/backend/src/establishment/payment/forms.py index 5e8aeb8..ed51109 100644 --- a/backend/src/establishment/payment/forms.py +++ b/backend/src/establishment/payment/forms.py @@ -1,4 +1,4 @@ -from src.models import LoginToken +from models import LoginToken from flask_wtf import FlaskForm from wtforms import DateField, FloatField, IntegerField, SelectField, SelectMultipleField, StringField, SubmitField from wtforms.validators import DataRequired, Optional diff --git a/backend/src/establishment/payment/routes.py b/backend/src/establishment/payment/routes.py index d9cf12e..b852319 100644 --- a/backend/src/establishment/payment/routes.py +++ b/backend/src/establishment/payment/routes.py @@ -3,7 +3,7 @@ from flask_login import current_user, login_required from . import bp from .forms import NewPaymentForm from src import db, LOGGER -from src.models import Establishment, Payment +from models import Establishment, Payment from src.utils.routes_utils import render_custom_template as render_template diff --git a/backend/src/item/__init__.py b/backend/src/item/__init__.py index e687561..8e6463e 100644 --- a/backend/src/item/__init__.py +++ b/backend/src/item/__init__.py @@ -4,4 +4,8 @@ bp = Blueprint('item', __name__, url_prefix='/item') from .new import bp as bp_new_item bp.register_blueprint(bp_new_item) from .list import bp as bp_item_list -bp.register_blueprint(bp_item_list) \ No newline at end of file +bp.register_blueprint(bp_item_list) +from .details import bp as bp_item_details +bp.register_blueprint(bp_item_details) +from .update import bp as bp_item_update +bp.register_blueprint(bp_item_update) \ No newline at end of file diff --git a/backend/src/item/details/__init__.py b/backend/src/item/details/__init__.py new file mode 100644 index 0000000..f4e0a11 --- /dev/null +++ b/backend/src/item/details/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('details', __name__, url_prefix='/details') + +from . import routes \ No newline at end of file diff --git a/backend/src/item/details/routes.py b/backend/src/item/details/routes.py new file mode 100644 index 0000000..f0a4757 --- /dev/null +++ b/backend/src/item/details/routes.py @@ -0,0 +1,14 @@ +# from flask_login import login_required +from . import bp +from models import Item +from models.schemas import ItemSchema +from src.utils.routes_utils import render_custom_template as render_template + +@bp.route('/', methods=['GET']) +def show_item(item: int): + itemobj = Item.query.get_or_404(item) + itemschema = ItemSchema().dump(itemobj) + itemschema['PriceChange'].sort(key=lambda d: d['date'], reverse=True) + itemschema['AmountChange'].sort(key=lambda d: d['date'], reverse=True) + print(itemschema) + return render_template('item/details/show_item.html', item = itemschema) \ No newline at end of file diff --git a/backend/src/item/list/routes.py b/backend/src/item/list/routes.py index b2e906b..346b278 100644 --- a/backend/src/item/list/routes.py +++ b/backend/src/item/list/routes.py @@ -1,8 +1,8 @@ from flask import abort, current_app, request from flask_login import current_user, login_required from . import bp -from src.models import Item -from src.models.schemas import ItemSchema +from models import Item +from models.schemas import ItemSchema from src.utils.routes_utils import render_custom_template as render_template @bp.route('/show_items', methods=['GET', 'POST']) diff --git a/backend/src/item/new/forms.py b/backend/src/item/new/forms.py index e3ff3e8..47aec42 100644 --- a/backend/src/item/new/forms.py +++ b/backend/src/item/new/forms.py @@ -1,4 +1,4 @@ -from src.models import Brand, Category +from models import Brand, Category from flask_wtf import FlaskForm from wtforms import DateField, FloatField, IntegerField, SelectField, SelectMultipleField, StringField, SubmitField from wtforms.validators import DataRequired, Optional diff --git a/backend/src/item/new/routes.py b/backend/src/item/new/routes.py index 7cd19dd..11c5786 100644 --- a/backend/src/item/new/routes.py +++ b/backend/src/item/new/routes.py @@ -4,7 +4,7 @@ from flask_login import current_user, login_required from . import bp from .forms import NewItemForm from src import db, LOGGER -from src.models import AmountChange, Brand, Item, PriceChange +from models import AmountChange, Brand, Item, PriceChange from src.utils.routes_utils import render_custom_template as render_template @bp.route('/new_item', methods=['GET', 'POST']) diff --git a/backend/src/item/update/__init__.py b/backend/src/item/update/__init__.py new file mode 100644 index 0000000..2b1b2b1 --- /dev/null +++ b/backend/src/item/update/__init__.py @@ -0,0 +1,7 @@ +from flask import Blueprint + +bp = Blueprint('update', __name__, url_prefix='/update') +from .price_change import bp as bp_price_change +bp.register_blueprint(bp_price_change) +from .amount_change import bp as bp_amount_change +bp.register_blueprint(bp_amount_change) \ No newline at end of file diff --git a/backend/src/item/update/amount_change/__init__.py b/backend/src/item/update/amount_change/__init__.py new file mode 100644 index 0000000..2d2ed34 --- /dev/null +++ b/backend/src/item/update/amount_change/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('amount_change', __name__, url_prefix='/amount_change') + +from . import forms, routes \ No newline at end of file diff --git a/backend/src/item/update/amount_change/forms.py b/backend/src/item/update/amount_change/forms.py new file mode 100644 index 0000000..e79c5ef --- /dev/null +++ b/backend/src/item/update/amount_change/forms.py @@ -0,0 +1,9 @@ +from flask_wtf import FlaskForm +from wtforms import DateField, HiddenField, IntegerField, SubmitField +from wtforms.validators import DataRequired + +class NewAmountChangeForm(FlaskForm): + id = HiddenField("Product EAN", validators=[DataRequired()], render_kw={"class": "form-control"}) + date = DateField("Insert Date", validators=[DataRequired()], render_kw={"class": "form-control"}) + amount_change = IntegerField("Amount", validators=[DataRequired()], render_kw={"class": "form-control"}) + submit = SubmitField("Submit", render_kw={"class": "btn btn-primary mt-3"}) \ No newline at end of file diff --git a/backend/src/item/update/amount_change/routes.py b/backend/src/item/update/amount_change/routes.py new file mode 100644 index 0000000..9d390f9 --- /dev/null +++ b/backend/src/item/update/amount_change/routes.py @@ -0,0 +1,24 @@ +from flask import abort, redirect, url_for +from flask_login import current_user, login_required +from . import bp +from .forms import NewAmountChangeForm +from src import db, LOGGER +from models import AmountChange, Item +from src.utils.routes_utils import render_custom_template as render_template + + +@bp.route('/', methods=['GET', 'POST']) +@login_required +def amount_change(item: int): + if current_user.is_anonymous: + abort(403) + db_item = Item.query.get_or_404(item) + form = NewAmountChangeForm() + form.id.data = item + if form.validate_on_submit(): + db_amount_change = AmountChange( + item=form.id.data, date=form.date.data, amount=form.amount_change.data) + db.session.add(db_amount_change) + db.session.commit() + return redirect(url_for('main.index')) + return render_template('item/update/amount_change/amount_change.html', form=form, item=db_item) diff --git a/backend/src/item/update/price_change/__init__.py b/backend/src/item/update/price_change/__init__.py new file mode 100644 index 0000000..1b04f62 --- /dev/null +++ b/backend/src/item/update/price_change/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('price_change', __name__, url_prefix='/price_change') + +from . import forms, routes \ No newline at end of file diff --git a/backend/src/item/update/price_change/forms.py b/backend/src/item/update/price_change/forms.py new file mode 100644 index 0000000..db34f8b --- /dev/null +++ b/backend/src/item/update/price_change/forms.py @@ -0,0 +1,9 @@ +from flask_wtf import FlaskForm +from wtforms import DateField, HiddenField, FloatField, SubmitField +from wtforms.validators import DataRequired + +class NewPriceChangeForm(FlaskForm): + id = HiddenField("Product EAN", validators=[DataRequired()], render_kw={"class": "form-control"}) + date = DateField("Insert Date", validators=[DataRequired()], render_kw={"class": "form-control"}) + price_change = FloatField("Price", validators=[DataRequired()], render_kw={"class": "form-control"}) + submit = SubmitField("Submit", render_kw={"class": "btn btn-primary mt-3"}) \ No newline at end of file diff --git a/backend/src/item/update/price_change/routes.py b/backend/src/item/update/price_change/routes.py new file mode 100644 index 0000000..8044a18 --- /dev/null +++ b/backend/src/item/update/price_change/routes.py @@ -0,0 +1,24 @@ +from flask import abort, redirect, url_for +from flask_login import current_user, login_required +from . import bp +from .forms import NewPriceChangeForm +from src import db, LOGGER +from models import Item, PriceChange +from src.utils.routes_utils import render_custom_template as render_template + + +@bp.route('/', methods=['GET', 'POST']) +@login_required +def price_change(item: int): + if current_user.is_anonymous: + abort(403) + db_item = Item.query.get_or_404(item) + form = NewPriceChangeForm() + form.id.data = int(item) + if form.validate_on_submit(): + db_price_change = PriceChange( + item=form.id.data, date=form.date.data, price=form.price_change.data) + db.session.add(db_price_change) + db.session.commit() + return redirect(url_for('main.index')) + return render_template('item/update/price_change/price_change.html', form=form, item=db_item) diff --git a/backend/src/models/schemas/item.py b/backend/src/models/schemas/item.py deleted file mode 100644 index fa0743a..0000000 --- a/backend/src/models/schemas/item.py +++ /dev/null @@ -1,14 +0,0 @@ -from src import ma -from src.models import Item -from src.models.schemas import BrandSchema - - -class ItemSchema(ma.SQLAlchemySchema): - class Meta: - model = Item - include_fk = True - - id = ma.auto_field() - name = ma.auto_field() - description = ma.auto_field() - Brand = ma.Nested(BrandSchema) diff --git a/backend/src/receipts/confirm/__init__.py b/backend/src/receipts/confirm/__init__.py new file mode 100644 index 0000000..3acf3cd --- /dev/null +++ b/backend/src/receipts/confirm/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('confirm', __name__, url_prefix='/confirm') + +from . import forms, routes \ No newline at end of file diff --git a/backend/src/receipts/confirm/forms.py b/backend/src/receipts/confirm/forms.py new file mode 100644 index 0000000..9b99dee --- /dev/null +++ b/backend/src/receipts/confirm/forms.py @@ -0,0 +1,18 @@ +from flask_wtf import FlaskForm +from wtforms import SelectMultipleField, SubmitField, widgets + +class MultiCheckboxField(SelectMultipleField): + widget = widgets.ListWidget(prefix_label=False) + option_widget = widgets.CheckboxInput() + +class CheckItemsForm(FlaskForm): + items = MultiCheckboxField("Items") + submit = SubmitField("Submit", render_kw={"class": "btn btn-primary mt-3"}) + + #TODO create new() method which loads the form for a specific receipt + @classmethod + def new(cls, itemArray): + """ + """ + form = cls() + return form \ No newline at end of file diff --git a/backend/src/receipts/confirm/routes.py b/backend/src/receipts/confirm/routes.py new file mode 100644 index 0000000..49d9fe7 --- /dev/null +++ b/backend/src/receipts/confirm/routes.py @@ -0,0 +1,36 @@ +from flask import abort, request, url_for +from flask_login import current_user, login_required +from . import bp +from .forms import CheckItemsForm, UploadReceiptForm +from src import db, LOGGER +from models.receipt import Receipt +from models.login_token import LoginToken +from src.utils.pdf_receipt_parser import PDFReceipt +from src.utils.routes_utils import render_custom_template as render_template + +PDFDir = "./" + +@bp.route('/', methods=['GET', 'POST']) +@login_required +def confirm_receipt_items(receipt_id: int): + """Check items from a receipt if they should be accounted for payment. + Get those items from the receipt PDF itself.""" + if "receipt" in request.args: + receipt_details = Receipt.query.get(request.args['receipt']) + if current_user.is_anonymous and current_user.id == receipt_details.LoginToken.Establishment.owner: + receipt = PDFReceipt._getPDFReceiptFromFile(PDFDir + f"{receipt.date}_{receipt.id}.pdf") + form = CheckItemsForm() + # TODO: Precheck if items are already in database. If yes, check if item is present only once or multiple + # times and provide dropdown menu if necessary. If not, provide input field. + temp_choices = [] + for item in receipt.items: + match item: + case {"itemname": itemname, "price": price}: + temp_choices.append((itemname.replace(" ", "_"), f"{itemname, price}")) + case {"itemname": itemname, "price": price, "amount": amount}: + temp_choices.append((itemname.replace(" ", "_"), f"{itemname}, {price} * {amount}")) + form.choices = temp_choices + if form.validate_on_submit(): + pass # TODO + return render_template("receipts/confirm_items.html") + abort(403) \ No newline at end of file diff --git a/backend/src/receipts/routes.py b/backend/src/receipts/routes.py index 26c7992..7e6742b 100644 --- a/backend/src/receipts/routes.py +++ b/backend/src/receipts/routes.py @@ -1,10 +1,11 @@ from flask import abort, request, url_for from flask_login import current_user, login_required +from werkzeug.utils import secure_filename from . import bp -from .forms import CheckItemsForm, UploadReceiptForm +from .forms import UploadReceiptForm from src import db, LOGGER -from src.models.receipt import Receipt -from src.models.login_token import LoginToken +from models.receipt import Receipt +from models.login_token import LoginToken from src.utils.pdf_receipt_parser import PDFReceipt from src.utils.routes_utils import render_custom_template as render_template @@ -20,43 +21,15 @@ def upload_receipt(): if LoginToken.query.filter_by(establishment=request.args['establishment'], user=current_user.id).first(): form = UploadReceiptForm() LOGGER.debug(form.pdfReceipt.data) - if form.is_submitted(): - LOGGER.debug("submitted") - if form.validate(): - LOGGER.debug("valid") - else: - LOGGER.debug(form.errors) if form.validate_on_submit(): receipt = PDFReceipt(form.pdfReceipt.data) dbReceipt = Receipt(id = receipt.id, date = receipt.date, from_user = LoginToken.query.filter_by(establishment=request.args['establishment'], user=current_user.id).first().token) - form.pdfReceipt.data.save(PDFDir + f"{str(receipt.date)}_{receipt.id}.pdf") + form.pdfReceipt.data.save(PDFDir + secure_filename(f"{str(receipt.date)}_{receipt.id}.pdf")) db.session.add(dbReceipt) db.session.commit() return receipt.text.replace("\n", "
") + else: + LOGGER.debug(form.errors) return render_template("receipts/upload.html", form = form) - abort(403) - -@bp.route('/confirm_receipt', methods=['GET', 'POST']) -@login_required -def confirm_receipt_items(): - """Check items from a receipt if they should be accounted for payment.""" - if "receipt" in request.args: - receipt_details = Receipt.query.get(request.args['receipt']) - if current_user.is_anonymous and current_user.id == receipt_details.LoginToken.Establishment.owner: - receipt = PDFReceipt._getPDFReceiptFromFile(PDFDir + f"{receipt.date}_{receipt.id}.pdf") - form = CheckItemsForm() - # TODO: Precheck if items are already in database. If yes, check if item is present only once or multiple - # times and provide dropdown menu if necessary. If not, provide input field. - temp_choices = [] - for item in receipt.items: - match item: - case {"itemname": itemname, "price": price}: - temp_choices.append((itemname.replace(" ", "_"), f"{itemname, price}")) - case {"itemname": itemname, "price": price, "amount": amount}: - temp_choices.append((itemname.replace(" ", "_"), f"{itemname}, {price} * {amount}")) - form.choices = temp_choices - if form.validate_on_submit(): - pass # TODO - return render_template("receipts/confirm_items.html") abort(403) \ No newline at end of file diff --git a/backend/src/receipts/upload/__init__.py b/backend/src/receipts/upload/__init__.py new file mode 100644 index 0000000..ea287f0 --- /dev/null +++ b/backend/src/receipts/upload/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('upload', __name__, url_prefix='/upload') + +from . import forms, routes \ No newline at end of file diff --git a/backend/src/receipts/upload/forms.py b/backend/src/receipts/upload/forms.py new file mode 100644 index 0000000..b8fea00 --- /dev/null +++ b/backend/src/receipts/upload/forms.py @@ -0,0 +1,7 @@ +from flask_wtf import FlaskForm +from flask_wtf.file import FileAllowed, FileField, FileRequired +from wtforms import SubmitField + +class UploadReceiptForm(FlaskForm): + pdfReceipt = FileField("PDF", validators=[FileRequired(), FileAllowed(["pdf"], "Invalid Format, must be .pdf")]) + submit = SubmitField("Submit", render_kw={"class": "btn btn-primary mt-3"}) \ No newline at end of file diff --git a/backend/src/receipts/upload/routes.py b/backend/src/receipts/upload/routes.py new file mode 100644 index 0000000..aca1cf2 --- /dev/null +++ b/backend/src/receipts/upload/routes.py @@ -0,0 +1,37 @@ +from flask import abort, request, url_for +from flask_login import current_user, login_required +from werkzeug.utils import secure_filename +from . import bp +from .forms import UploadReceiptForm +from src import db, LOGGER +from models.receipt import Receipt +from models.login_token import LoginToken +from src.utils.pdf_receipt_parser import PDFReceipt +from src.utils.routes_utils import render_custom_template as render_template + +PDFDir = "./" +# TODO überarbeiten. PDFs müssen in der Datenbank eine eigene ID bekommen. +# Quittungen haben eine USt.-ID. Die muss als Unique Key in der Datenbank +# hinterlegt sein. +# Die laufende ID ist zum abspeichern der PDFs gedacht. +@bp.route('/', methods=['GET', 'POST']) +@login_required +def upload_receipt(establishment: int): + """Upload of a receipt.""" + if current_user.is_anonymous: + abort(403) + if LoginToken.query.filter_by(establishment=request.args['establishment'], user=current_user.id).first(): + form = UploadReceiptForm() + LOGGER.debug(form.pdfReceipt.data) + if form.validate_on_submit(): + receipt = PDFReceipt(form.pdfReceipt.data) + dbReceipt = Receipt(id = receipt.id, date = receipt.date, + from_user = LoginToken.query.filter_by(establishment=request.args['establishment'], user=current_user.id).first().token) + form.pdfReceipt.data.save(PDFDir + secure_filename(f"{str(receipt.date)}_{receipt.id}.pdf")) + db.session.add(dbReceipt) + db.session.commit() + return receipt.text.replace("\n", "
") + else: + LOGGER.debug(form.errors) + return render_template("receipts/upload.html", form = form) + abort(403) \ No newline at end of file diff --git a/backend/src/templates/item/list/show_items.html b/backend/src/templates/item/list/show_items.html deleted file mode 100644 index f6d594c..0000000 --- a/backend/src/templates/item/list/show_items.html +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "base.html" %} -{% import 'bootstrap/wtf.html' as wtf %} - -{% block app_content %} - - - - - - - - - - - - {% for item in items %} - - - - - - - {% endfor %} - -
#NameBeschreibungMarke
{{ item.id }}{{ item.name }}{{ item.description }}{{ item.Brand.name }}
-{% with pagination_object=items %} -{% include "utils/general/_page_navigation.html" %} -{% endwith %} -{% endblock %} \ No newline at end of file diff --git a/backend/src/utils/database_utils.py b/backend/src/utils/database_utils.py index aa84d08..7736a73 100644 --- a/backend/src/utils/database_utils.py +++ b/backend/src/utils/database_utils.py @@ -8,7 +8,7 @@ from sqlalchemy.dialects.postgresql import insert from string import ascii_letters, digits from .view_utils import bought_with_prices as bwp from src import db, LOGGER -from src.models import Bought, Establishment, Item, LoginToken, User +from models import Bought, Establishment, Item, LoginToken, User def insert_bought_items(token: str, dates: list[dict[str: any]]): diff --git a/backend/src/modules/flatastic/__init__.py b/backend/src/utils/modules/flatastic/__init__.py similarity index 100% rename from backend/src/modules/flatastic/__init__.py rename to backend/src/utils/modules/flatastic/__init__.py diff --git a/backend/src/modules/flatastic/flatastic.py b/backend/src/utils/modules/flatastic/flatastic.py similarity index 100% rename from backend/src/modules/flatastic/flatastic.py rename to backend/src/utils/modules/flatastic/flatastic.py diff --git a/backend/src/utils/view_utils.py b/backend/src/utils/view_utils.py index dfec2bc..f225402 100644 --- a/backend/src/utils/view_utils.py +++ b/backend/src/utils/view_utils.py @@ -1,8 +1,8 @@ from sqlalchemy_utils import create_view from src import db, LOGGER -from src.models.amount_change import AmountChange -from src.models.bought import Bought -from src.models.price_change import PriceChange +from models.amount_change import AmountChange +from models.bought import Bought +from models.price_change import PriceChange def group_results(results: tuple) -> list: result_list = [] diff --git a/backend/src/static/sidebars.css b/backend/web/static/sidebars.css similarity index 100% rename from backend/src/static/sidebars.css rename to backend/web/static/sidebars.css diff --git a/backend/src/templates/auth/login.html b/backend/web/templates/auth/login.html similarity index 100% rename from backend/src/templates/auth/login.html rename to backend/web/templates/auth/login.html diff --git a/backend/src/templates/auth/register.html b/backend/web/templates/auth/register.html similarity index 100% rename from backend/src/templates/auth/register.html rename to backend/web/templates/auth/register.html diff --git a/backend/src/templates/auth/reset_password.html b/backend/web/templates/auth/reset_password.html similarity index 100% rename from backend/src/templates/auth/reset_password.html rename to backend/web/templates/auth/reset_password.html diff --git a/backend/src/templates/auth/reset_password_request.html b/backend/web/templates/auth/reset_password_request.html similarity index 100% rename from backend/src/templates/auth/reset_password_request.html rename to backend/web/templates/auth/reset_password_request.html diff --git a/backend/src/templates/base.html b/backend/web/templates/base.html similarity index 100% rename from backend/src/templates/base.html rename to backend/web/templates/base.html diff --git a/backend/src/templates/email/reset_password.html b/backend/web/templates/email/reset_password.html similarity index 100% rename from backend/src/templates/email/reset_password.html rename to backend/web/templates/email/reset_password.html diff --git a/backend/src/templates/email/reset_password.txt b/backend/web/templates/email/reset_password.txt similarity index 100% rename from backend/src/templates/email/reset_password.txt rename to backend/web/templates/email/reset_password.txt diff --git a/backend/src/templates/errors/403.html b/backend/web/templates/errors/403.html similarity index 100% rename from backend/src/templates/errors/403.html rename to backend/web/templates/errors/403.html diff --git a/backend/src/templates/errors/404.html b/backend/web/templates/errors/404.html similarity index 100% rename from backend/src/templates/errors/404.html rename to backend/web/templates/errors/404.html diff --git a/backend/src/templates/errors/500.html b/backend/web/templates/errors/500.html similarity index 100% rename from backend/src/templates/errors/500.html rename to backend/web/templates/errors/500.html diff --git a/backend/src/templates/establishment/candidates/_candidate_evaluation.html b/backend/web/templates/establishment/candidates/_candidate_evaluation.html similarity index 100% rename from backend/src/templates/establishment/candidates/_candidate_evaluation.html rename to backend/web/templates/establishment/candidates/_candidate_evaluation.html diff --git a/backend/src/templates/establishment/candidates/candidates.html b/backend/web/templates/establishment/candidates/candidates.html similarity index 100% rename from backend/src/templates/establishment/candidates/candidates.html rename to backend/web/templates/establishment/candidates/candidates.html diff --git a/backend/src/templates/establishment/list/establishment_list.html b/backend/web/templates/establishment/list/establishment_list.html similarity index 100% rename from backend/src/templates/establishment/list/establishment_list.html rename to backend/web/templates/establishment/list/establishment_list.html diff --git a/backend/src/templates/establishment/list/establishment_request.html b/backend/web/templates/establishment/list/establishment_request.html similarity index 100% rename from backend/src/templates/establishment/list/establishment_request.html rename to backend/web/templates/establishment/list/establishment_request.html diff --git a/backend/src/templates/establishment/new/new_establishment.html b/backend/web/templates/establishment/new/new_establishment.html similarity index 100% rename from backend/src/templates/establishment/new/new_establishment.html rename to backend/web/templates/establishment/new/new_establishment.html diff --git a/backend/src/templates/establishment/new/new_establishment_form.html b/backend/web/templates/establishment/new/new_establishment_form.html similarity index 100% rename from backend/src/templates/establishment/new/new_establishment_form.html rename to backend/web/templates/establishment/new/new_establishment_form.html diff --git a/backend/src/templates/establishment/overview/overview.html b/backend/web/templates/establishment/overview/overview.html similarity index 100% rename from backend/src/templates/establishment/overview/overview.html rename to backend/web/templates/establishment/overview/overview.html diff --git a/backend/src/templates/establishment/payment/new_payment.html b/backend/web/templates/establishment/payment/new_payment.html similarity index 100% rename from backend/src/templates/establishment/payment/new_payment.html rename to backend/web/templates/establishment/payment/new_payment.html diff --git a/backend/src/templates/establishment/payment/new_payment_form.html b/backend/web/templates/establishment/payment/new_payment_form.html similarity index 100% rename from backend/src/templates/establishment/payment/new_payment_form.html rename to backend/web/templates/establishment/payment/new_payment_form.html diff --git a/backend/web/templates/item/details/show_item.html b/backend/web/templates/item/details/show_item.html new file mode 100644 index 0000000..fce5934 --- /dev/null +++ b/backend/web/templates/item/details/show_item.html @@ -0,0 +1,79 @@ +{% extends "base.html" %} +{% import 'bootstrap/wtf.html' as wtf %} + +{% block app_content %} + + + + + + + + + + + + + + + + + + + + + + + + +
EAN{{ item.id }}
Marke{{ item.Brand.name }}
Bezeichnung auf dem Kassenzettel{{ item.name }}
Beschreibung{{ item.description }}
+ {% if item.PriceChange %} + Momentaner Preis pro Scan€ + {% if item.AmountChange %} + {{ ((item.PriceChange[0].price / item.AmountChange[0].amount)/100)|round(2, 'ceil') }} + {% else %} + {{ (item.PriceChange[0].price)/100 }} + {% endif %} + {% else %} + Kein Preis vorhanden. + {% endif %} +
+
+ + + + + + + + + {% for price in item.PriceChange %} + + + + + {% endfor %} + +
Preishistorie + Einfügen +
{{ price.date }}€ {{ price.price/100 }}
+
+ + + + + + + + + {% for amount in item.AmountChange %} + + + + + {% endfor %} + +
Mengenhistorie + Einfügen +
{{ amount.date }}{{ amount.amount }}
+{% endblock %} \ No newline at end of file diff --git a/backend/web/templates/item/list/show_items.html b/backend/web/templates/item/list/show_items.html new file mode 100644 index 0000000..e6569ff --- /dev/null +++ b/backend/web/templates/item/list/show_items.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} +{% import 'bootstrap/wtf.html' as wtf %} + +{% block app_content %} +
+ + + + + + + + + + + {% for item in items %} + + + + + + + {% endfor %} + +
#NameBeschreibungMarke
+ {{ item.id }} + {{ item.name }}{{ item.description }}{{ item.Brand.name }}
+
+{% with pagination_object=items %} +{% include "utils/general/_page_navigation.html" %} +{% endwith %} +{% endblock %} \ No newline at end of file diff --git a/backend/src/templates/item/new/new_item.html b/backend/web/templates/item/new/new_item.html similarity index 100% rename from backend/src/templates/item/new/new_item.html rename to backend/web/templates/item/new/new_item.html diff --git a/backend/src/templates/item/new/new_item_form.html b/backend/web/templates/item/new/new_item_form.html similarity index 100% rename from backend/src/templates/item/new/new_item_form.html rename to backend/web/templates/item/new/new_item_form.html diff --git a/backend/web/templates/item/update/_item_to_change.html b/backend/web/templates/item/update/_item_to_change.html new file mode 100644 index 0000000..8856408 --- /dev/null +++ b/backend/web/templates/item/update/_item_to_change.html @@ -0,0 +1 @@ +

({{ item.id }}) {{ item.name }}

\ No newline at end of file diff --git a/backend/web/templates/item/update/amount_change/amount_change.html b/backend/web/templates/item/update/amount_change/amount_change.html new file mode 100644 index 0000000..a018576 --- /dev/null +++ b/backend/web/templates/item/update/amount_change/amount_change.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} +{% import 'bootstrap/wtf.html' as wtf %} + +{% block app_content %} +{% include 'item/update/_item_to_change.html' ignore missing %} +{% include 'item/update/amount_change/amount_change_form.html' %} +{% endblock %} \ No newline at end of file diff --git a/backend/web/templates/item/update/amount_change/amount_change_form.html b/backend/web/templates/item/update/amount_change/amount_change_form.html new file mode 100644 index 0000000..9259e98 --- /dev/null +++ b/backend/web/templates/item/update/amount_change/amount_change_form.html @@ -0,0 +1,7 @@ +{% from 'utils/form/_render_field.html' import render_field %} +
+ {{ form.hidden_tag() }} + {{ render_field(form.date) }} + {{ render_field(form.amount_change) }} + {{ form.submit }} +
\ No newline at end of file diff --git a/backend/web/templates/item/update/price_change/price_change.html b/backend/web/templates/item/update/price_change/price_change.html new file mode 100644 index 0000000..465543b --- /dev/null +++ b/backend/web/templates/item/update/price_change/price_change.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} +{% import 'bootstrap/wtf.html' as wtf %} + +{% block app_content %} +{% include 'item/update/_item_to_change.html' ignore missing %} +{% include 'item/update/price_change/price_change_form.html' %} +{% endblock %} \ No newline at end of file diff --git a/backend/web/templates/item/update/price_change/price_change_form.html b/backend/web/templates/item/update/price_change/price_change_form.html new file mode 100644 index 0000000..af3d6c5 --- /dev/null +++ b/backend/web/templates/item/update/price_change/price_change_form.html @@ -0,0 +1,7 @@ +{% from 'utils/form/_render_field.html' import render_field %} +
+ {{ form.hidden_tag() }} + {{ render_field(form.date) }} + {{ render_field(form.price_change) }} + {{ form.submit }} +
\ No newline at end of file diff --git a/backend/src/templates/main/overview.html b/backend/web/templates/main/overview.html similarity index 100% rename from backend/src/templates/main/overview.html rename to backend/web/templates/main/overview.html diff --git a/backend/src/templates/receipts/confirm_items.html b/backend/web/templates/receipts/confirm_items.html similarity index 100% rename from backend/src/templates/receipts/confirm_items.html rename to backend/web/templates/receipts/confirm_items.html diff --git a/backend/src/templates/receipts/upload.html b/backend/web/templates/receipts/upload.html similarity index 100% rename from backend/src/templates/receipts/upload.html rename to backend/web/templates/receipts/upload.html diff --git a/backend/src/templates/utils/form/_render_field.html b/backend/web/templates/utils/form/_render_field.html similarity index 100% rename from backend/src/templates/utils/form/_render_field.html rename to backend/web/templates/utils/form/_render_field.html diff --git a/backend/src/templates/utils/general/_page_navigation.html b/backend/web/templates/utils/general/_page_navigation.html similarity index 100% rename from backend/src/templates/utils/general/_page_navigation.html rename to backend/web/templates/utils/general/_page_navigation.html