Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f24880c09a | |||
| 3622cbca05 | |||
| 637a5f7ad5 | |||
| 15ba3c060a | |||
| bde9a50767 | |||
| 60e221146a | |||
| d34f2adb2f | |||
| a6f229e7fb | |||
| 5a453a140e | |||
| 0f6f76a66b | |||
| 14b7e1f84c | |||
| 560016cc18 | |||
| b57dbba5d6 | |||
| 7ae57ae3a4 | |||
| 04a13635dc | |||
| 5c46a24338 | |||
| f41fdd076b | |||
| 4d1e7eb944 | |||
| 6c0fa5a58b | |||
| 5e4a59e15f | |||
| d311b6f8cf | |||
| 8e17a2fb25 | |||
| dceda1446f | |||
| b21284f640 | |||
| 597725f46c | |||
| 8069a794e2 | |||
| 2e33f9b5a8 | |||
| 764738b20d | |||
| b997e25a08 | |||
| c716c7c3ba | |||
| 6cf5a91c8c | |||
| 22e45857ff |
10
.dockerignore
Normal file
10
.dockerignore
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Ignore pycaches
|
||||||
|
|
||||||
|
logs
|
||||||
|
__pycache__
|
||||||
|
Pipfile*
|
||||||
|
|
||||||
|
.env*
|
||||||
|
.flaskenv*
|
||||||
|
!.env.project
|
||||||
|
!.env.vault
|
||||||
12
.env.vault
Normal file
12
.env.vault
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#################################################################################
|
||||||
|
# #
|
||||||
|
# This file uniquely identifies your project in dotenv-vault. #
|
||||||
|
# You SHOULD commit this file to source control. #
|
||||||
|
# #
|
||||||
|
# Generated with 'npx dotenv-vault new' #
|
||||||
|
# #
|
||||||
|
# Learn more at https://dotenv.org/env-vault #
|
||||||
|
# #
|
||||||
|
#################################################################################
|
||||||
|
|
||||||
|
DOTENV_VAULT=vlt_54536d38674329461d10b74ec7e56be43df6021bb5267bedec1f774758371784
|
||||||
44
.github/workflows/main.yml
vendored
44
.github/workflows/main.yml
vendored
@ -4,19 +4,47 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: https://gitea.com/actions/checkout@master
|
||||||
- name: Archive Server
|
- name: Zip Artifacts
|
||||||
uses: thedoctor0/zip-release@master
|
uses: https://github.com/thedoctor0/zip-release@master
|
||||||
with:
|
with:
|
||||||
type: 'zip'
|
type: 'zip'
|
||||||
filename: 'server.zip'
|
filename: 'server.zip'
|
||||||
exclusions: '*.git*'
|
exclusions: '*.git*'
|
||||||
- name: Release Archive
|
- name: Release Archive
|
||||||
uses: ncipollo/release-action@v1
|
uses: https://gitea.com/actions/gitea-release-action@v1
|
||||||
with:
|
with:
|
||||||
allowUpdates: true
|
server_url: https://gitea.wpgcommunity.net
|
||||||
artifacts: "server.zip"
|
files: 'server.zip'
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: https://gitea.com/actions/checkout@master
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
${{ vars.DOCKER_REPO }}/costhive
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
with:
|
||||||
|
config-inline: |
|
||||||
|
[registry."${{ vars.DOCKER_REPO }}"]
|
||||||
|
http = true
|
||||||
|
insecure = true
|
||||||
|
- name: Login to Gitea Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ vars.DOCKER_REPO }}
|
||||||
|
username: ${{ vars.DOCKER_USER }}
|
||||||
|
password: ${{ secrets.DOCKER_PASS }}
|
||||||
|
- name: Build and push
|
||||||
|
uses: https://github.com/docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
context: .
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
235
.gitignore
vendored
235
.gitignore
vendored
@ -1,3 +1,45 @@
|
|||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/flask,python,git,visualstudiocode,angular,venv
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=flask,python,git,visualstudiocode,angular,venv
|
||||||
|
|
||||||
|
### Angular ###
|
||||||
|
## Angular ##
|
||||||
|
# compiled output
|
||||||
|
dist/
|
||||||
|
tmp/
|
||||||
|
app/**/*.js
|
||||||
|
app/**/*.js.map
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
node_modules/
|
||||||
|
bower_components/
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.sass-cache/
|
||||||
|
connect.lock/
|
||||||
|
coverage/
|
||||||
|
libpeerconnection.log/
|
||||||
|
npm-debug.log
|
||||||
|
testem.log
|
||||||
|
typings/
|
||||||
|
.angular/
|
||||||
|
|
||||||
|
# e2e
|
||||||
|
e2e/*.js
|
||||||
|
e2e/*.map
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store/
|
||||||
|
|
||||||
|
### Flask ###
|
||||||
|
instance/*
|
||||||
|
!instance/.gitignore
|
||||||
|
.webassets-cache
|
||||||
|
.env
|
||||||
|
|
||||||
|
### Flask.Python Stack ###
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
@ -10,7 +52,6 @@ __pycache__/
|
|||||||
.Python
|
.Python
|
||||||
build/
|
build/
|
||||||
develop-eggs/
|
develop-eggs/
|
||||||
dist/
|
|
||||||
downloads/
|
downloads/
|
||||||
eggs/
|
eggs/
|
||||||
.eggs/
|
.eggs/
|
||||||
@ -20,7 +61,6 @@ parts/
|
|||||||
sdist/
|
sdist/
|
||||||
var/
|
var/
|
||||||
wheels/
|
wheels/
|
||||||
pip-wheel-metadata/
|
|
||||||
share/python-wheels/
|
share/python-wheels/
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
.installed.cfg
|
.installed.cfg
|
||||||
@ -50,6 +90,7 @@ coverage.xml
|
|||||||
*.py,cover
|
*.py,cover
|
||||||
.hypothesis/
|
.hypothesis/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
*.mo
|
*.mo
|
||||||
@ -63,7 +104,6 @@ db.sqlite3-journal
|
|||||||
|
|
||||||
# Flask stuff:
|
# Flask stuff:
|
||||||
instance/
|
instance/
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
# Scrapy stuff:
|
||||||
.scrapy
|
.scrapy
|
||||||
@ -72,6 +112,7 @@ instance/
|
|||||||
docs/_build/
|
docs/_build/
|
||||||
|
|
||||||
# PyBuilder
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
target/
|
target/
|
||||||
|
|
||||||
# Jupyter Notebook
|
# Jupyter Notebook
|
||||||
@ -82,7 +123,9 @@ profile_default/
|
|||||||
ipython_config.py
|
ipython_config.py
|
||||||
|
|
||||||
# pyenv
|
# pyenv
|
||||||
.python-version
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
# pipenv
|
# pipenv
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
@ -91,7 +134,22 @@ ipython_config.py
|
|||||||
# install all needed dependencies.
|
# install all needed dependencies.
|
||||||
#Pipfile.lock
|
#Pipfile.lock
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
#pdm.lock
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/#use-with-ide
|
||||||
|
.pdm.toml
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
__pypackages__/
|
__pypackages__/
|
||||||
|
|
||||||
# Celery stuff
|
# Celery stuff
|
||||||
@ -102,9 +160,7 @@ celerybeat.pid
|
|||||||
*.sage.py
|
*.sage.py
|
||||||
|
|
||||||
# Environments
|
# Environments
|
||||||
.env
|
|
||||||
.venv
|
.venv
|
||||||
.flaskenv
|
|
||||||
env/
|
env/
|
||||||
venv/
|
venv/
|
||||||
ENV/
|
ENV/
|
||||||
@ -129,9 +185,174 @@ dmypy.json
|
|||||||
# Pyre type checker
|
# Pyre type checker
|
||||||
.pyre/
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
### Git ###
|
||||||
|
# Created by git for backups. To disable backups in Git:
|
||||||
|
# $ git config --global mergetool.keepBackup false
|
||||||
|
*.orig
|
||||||
|
|
||||||
|
# Created by git when using merge tools for conflicts
|
||||||
|
*.BACKUP.*
|
||||||
|
*.BASE.*
|
||||||
|
*.LOCAL.*
|
||||||
|
*.REMOTE.*
|
||||||
|
*_BACKUP_*.txt
|
||||||
|
*_BASE_*.txt
|
||||||
|
*_LOCAL_*.txt
|
||||||
|
*_REMOTE_*.txt
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/#use-with-ide
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
|
||||||
|
### Python Patch ###
|
||||||
|
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
||||||
|
poetry.toml
|
||||||
|
|
||||||
|
# ruff
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
### venv ###
|
||||||
|
# Virtualenv
|
||||||
|
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
|
||||||
|
[Bb]in
|
||||||
|
[Ii]nclude
|
||||||
|
[Ll]ib
|
||||||
|
[Ll]ib64
|
||||||
|
[Ll]ocal
|
||||||
|
[Ss]cripts
|
||||||
|
pyvenv.cfg
|
||||||
|
pip-selfcheck.json
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/*.code-snippets
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Built Visual Studio Code Extensions
|
||||||
|
*.vsix
|
||||||
|
|
||||||
|
### VisualStudioCode Patch ###
|
||||||
|
# Ignore all local history of files
|
||||||
|
.history
|
||||||
|
.ionide
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/flask,python,git,visualstudiocode,angular,venv
|
||||||
|
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
config.yaml
|
config.yaml
|
||||||
scans.json
|
scans.json
|
||||||
|
test_*.*
|
||||||
test.*
|
test.*
|
||||||
|
tests*
|
||||||
*.db
|
*.db
|
||||||
.vscode
|
.vscode
|
||||||
|
*.tar
|
||||||
|
*.code-workspace
|
||||||
|
.env*
|
||||||
|
.flaskenv*
|
||||||
|
!.env.project
|
||||||
|
!.env.vault
|
||||||
|
*.ps1
|
||||||
|
*.pdf
|
||||||
|
*.backup
|
||||||
|
Dockerfile.*
|
||||||
|
docker-compose.*
|
||||||
|
*debug.py
|
||||||
34
Dockerfile
34
Dockerfile
@ -1,27 +1,27 @@
|
|||||||
FROM python@sha256:38000b248a186dcae150fe2f64d23bd44a0730347d1e5e4d1faedd449a9a4913
|
FROM python@sha256:c66cf219ac0083a9af2ff90e16530f16cd503c59eb7909feb3b8f3524dc1a87e
|
||||||
|
# python:3.12.2-slim-bullseye (amd64)
|
||||||
|
RUN useradd costhive
|
||||||
|
|
||||||
RUN useradd scan2kasse
|
WORKDIR /home/costhive
|
||||||
|
|
||||||
WORKDIR /home/scan2kasse
|
RUN apt update && apt -y upgrade; \
|
||||||
|
apt install -y libpq-dev gcc g++ swig make cmake m4; \
|
||||||
|
rm -rf /var/lib/apt/lists
|
||||||
|
|
||||||
RUN apt update && apt upgrade
|
COPY boot.sh backend/requirements.txt ./
|
||||||
RUN apt install -y libpq-dev gcc g++
|
RUN python -m venv venv; \
|
||||||
|
venv/bin/pip install --upgrade pip; \
|
||||||
|
venv/bin/pip install wheel gunicorn; \
|
||||||
|
venv/bin/pip install -r requirements.txt
|
||||||
|
|
||||||
COPY requirements.txt requirements.txt
|
COPY backend backend
|
||||||
RUN python -m venv venv
|
|
||||||
RUN venv/bin/pip install -r requirements.txt
|
|
||||||
RUN venv/bin/pip install gunicorn
|
|
||||||
|
|
||||||
COPY app app
|
ENV FLASK_APP=run.py
|
||||||
COPY migrations migrations
|
|
||||||
COPY configs configs
|
|
||||||
COPY run.py boot.sh ./
|
|
||||||
RUN chmod +x boot.sh
|
|
||||||
|
|
||||||
ENV FLASK_APP run.py
|
RUN chmod +x boot.sh; \
|
||||||
|
chown -R costhive:costhive .
|
||||||
|
|
||||||
RUN chown -R scan2kasse:scan2kasse ./
|
USER costhive
|
||||||
USER scan2kasse
|
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
ENTRYPOINT ["./boot.sh"]
|
ENTRYPOINT ["./boot.sh"]
|
||||||
@ -1,51 +0,0 @@
|
|||||||
from configs.config import Config
|
|
||||||
from flask import Flask
|
|
||||||
from flask_bootstrap import Bootstrap
|
|
||||||
from flask_login import LoginManager
|
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
|
||||||
from flask_migrate import Migrate
|
|
||||||
from logging import getLogger
|
|
||||||
from logging.config import fileConfig
|
|
||||||
from os import makedirs
|
|
||||||
from os.path import dirname, exists
|
|
||||||
|
|
||||||
try:
|
|
||||||
dir_name = dirname(__file__)
|
|
||||||
if dir_name:
|
|
||||||
DIR = dir_name + "/"
|
|
||||||
else:
|
|
||||||
DIR = "./"
|
|
||||||
except NameError:
|
|
||||||
DIR = "./"
|
|
||||||
|
|
||||||
if not exists(DIR + "../logs"):
|
|
||||||
makedirs(DIR + "../logs")
|
|
||||||
|
|
||||||
fileConfig(DIR + "../configs/log.conf")
|
|
||||||
LOGGER = getLogger("root")
|
|
||||||
|
|
||||||
bootstrap = Bootstrap()
|
|
||||||
db = SQLAlchemy()
|
|
||||||
login = LoginManager()
|
|
||||||
login.login_view = 'web_login'
|
|
||||||
migrate = Migrate()
|
|
||||||
|
|
||||||
|
|
||||||
def create_app(config_class=Config):
|
|
||||||
app = Flask(__name__)
|
|
||||||
app.config.from_object(config_class)
|
|
||||||
bootstrap.init_app(app)
|
|
||||||
db.init_app(app)
|
|
||||||
login.init_app(app)
|
|
||||||
migrate.init_app(app, db, render_as_batch=True)
|
|
||||||
|
|
||||||
from app.auth import bp as auth_bp
|
|
||||||
app.register_blueprint(auth_bp, url_prefix='/auth')
|
|
||||||
from app.errors import bp as errors_bp
|
|
||||||
app.register_blueprint(errors_bp)
|
|
||||||
from app.main import bp as main_bp
|
|
||||||
app.register_blueprint(main_bp)
|
|
||||||
|
|
||||||
return app
|
|
||||||
|
|
||||||
from app import models
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
from flask import Blueprint
|
|
||||||
|
|
||||||
bp = Blueprint('auth', __name__)
|
|
||||||
|
|
||||||
from app.auth import forms, routes
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
from app import db
|
|
||||||
from app.auth import bp
|
|
||||||
from app.auth.forms import LoginForm, RegistrationForm
|
|
||||||
from app.models import User
|
|
||||||
from app.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
|
|
||||||
from werkzeug.urls import url_parse
|
|
||||||
|
|
||||||
@bp.route(f'/register', methods=['GET', 'POST'])
|
|
||||||
def web_register():
|
|
||||||
if current_user.is_authenticated:
|
|
||||||
return redirect(url_for('main.index'))
|
|
||||||
form = RegistrationForm()
|
|
||||||
if form.validate_on_submit():
|
|
||||||
user = User(email=form.email.data)
|
|
||||||
user.set_password(form.password.data)
|
|
||||||
db.session.add(user)
|
|
||||||
db.session.commit()
|
|
||||||
flash('Congratulations, you are now a registered user!')
|
|
||||||
return redirect(url_for('auth.web_login'))
|
|
||||||
return render_template('auth/register.html', title='Register', form=form)
|
|
||||||
|
|
||||||
@bp.route(f'/login', methods=['GET', 'POST'])
|
|
||||||
def web_login():
|
|
||||||
if current_user.is_authenticated:
|
|
||||||
return redirect(url_for('main.index'))
|
|
||||||
form = LoginForm()
|
|
||||||
if form.validate_on_submit():
|
|
||||||
user = User.query.filter_by(email=form.email.data).first()
|
|
||||||
if user is None or not user.check_password(form.password.data):
|
|
||||||
flash('Invalid email or password')
|
|
||||||
return redirect(url_for('auth.web_login'))
|
|
||||||
login_user(user, remember=form.remember_me.data)
|
|
||||||
next_page = request.args.get('next')
|
|
||||||
if not next_page or url_parse(next_page).netloc != '':
|
|
||||||
next_page = url_for('main.index')
|
|
||||||
return redirect(next_page)
|
|
||||||
return render_template('auth/login.html', title='Sign In', form=form)
|
|
||||||
|
|
||||||
@bp.route(f'/logout')
|
|
||||||
def web_logout():
|
|
||||||
logout_user()
|
|
||||||
return redirect(url_for('main.index'))
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
from flask import Blueprint
|
|
||||||
|
|
||||||
bp = Blueprint('errors', __name__)
|
|
||||||
|
|
||||||
from app.errors import handlers
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
from app import db, LOGGER
|
|
||||||
from app.main.forms import NewItemForm
|
|
||||||
from app.main import bp
|
|
||||||
from app.models import AmountChange, Brand, Establishment, LoginToken, Item, PriceChange
|
|
||||||
from app.utils import view_utils, database_utils
|
|
||||||
from app.utils.routes_utils import render_custom_template as render_template
|
|
||||||
from datetime import date
|
|
||||||
from flask import abort, redirect, request, url_for
|
|
||||||
from flask.json import jsonify
|
|
||||||
from flask_login import current_user, login_required
|
|
||||||
|
|
||||||
@bp.route('/')
|
|
||||||
@bp.route('/index')
|
|
||||||
def index():
|
|
||||||
return render_template("base.html")
|
|
||||||
|
|
||||||
# @bp.route('/')
|
|
||||||
# def test():
|
|
||||||
# return "Hello World"
|
|
||||||
|
|
||||||
@bp.route('/overview', methods=['GET'])
|
|
||||||
@login_required
|
|
||||||
def get_report_from_user():
|
|
||||||
if current_user.is_anonymous:
|
|
||||||
abort(403)
|
|
||||||
if 'month' in request.args:
|
|
||||||
try:
|
|
||||||
month = int(request.args['month'])
|
|
||||||
except Exception as e:
|
|
||||||
LOGGER.exception("")
|
|
||||||
abort(400)
|
|
||||||
else:
|
|
||||||
if (month > 12 or month < 1):
|
|
||||||
abort(400)
|
|
||||||
LOGGER.info("Getting results.")
|
|
||||||
results = database_utils.get_report(**request.args)
|
|
||||||
LOGGER.debug(f"Results received.")
|
|
||||||
# LOGGER.debug(str(results))
|
|
||||||
if results:
|
|
||||||
result_list = view_utils.group_results(results)
|
|
||||||
else:
|
|
||||||
result_list = []
|
|
||||||
if request.content_type == "application/json":
|
|
||||||
return jsonify(result_list)
|
|
||||||
else:
|
|
||||||
if "establishment" in request.args:
|
|
||||||
return render_template("main/overview.html", results=result_list, establishment = Establishment.query.get(int(request.args['establishment'])))
|
|
||||||
else:
|
|
||||||
return render_template("main/overview.html", results=result_list)
|
|
||||||
|
|
||||||
@bp.route('/token_authorization')
|
|
||||||
def token_authorization():
|
|
||||||
LOGGER.debug("Token Login")
|
|
||||||
if not request.json or 'login' not in request.json:
|
|
||||||
abort(400)
|
|
||||||
if not LoginToken.query.filter_by(token=request.json['login']).first():
|
|
||||||
abort(403)
|
|
||||||
return jsonify({}), 200
|
|
||||||
|
|
||||||
@bp.route('/token_insert', methods=['POST'])
|
|
||||||
def insert():
|
|
||||||
match request.json:
|
|
||||||
case {'user': user, 'items': items, 'date': date}:
|
|
||||||
failed = database_utils.insert_bought_items(user, items, date)
|
|
||||||
case {'user': user, 'items': items}:
|
|
||||||
failed = database_utils.insert_bought_items(user, items)
|
|
||||||
case _:
|
|
||||||
abort(400)
|
|
||||||
if failed:
|
|
||||||
return jsonify(failed), 400
|
|
||||||
return jsonify({'inserted': True}), 201
|
|
||||||
|
|
||||||
@bp.route('/new_item', methods=['GET', 'POST'])
|
|
||||||
@login_required
|
|
||||||
def new_item():
|
|
||||||
if current_user.is_anonymous:
|
|
||||||
abort(403)
|
|
||||||
form=NewItemForm.new()
|
|
||||||
if form.is_submitted():
|
|
||||||
LOGGER.debug("submitted")
|
|
||||||
if form.validate():
|
|
||||||
LOGGER.debug("valid")
|
|
||||||
else:
|
|
||||||
LOGGER.debug(form.errors)
|
|
||||||
if form.validate_on_submit():
|
|
||||||
LOGGER.debug("valid form")
|
|
||||||
brand = Brand.query.get(form.brand.data)
|
|
||||||
new_item = Item(id = form.id.data, name = form.name.data, brand = brand.id, description = form.description.data)
|
|
||||||
# if form.category.data:
|
|
||||||
# category = Category.query.get(id = form.category.data)
|
|
||||||
# new_item.Category = category
|
|
||||||
new_item.PriceChange = [PriceChange(Item = new_item, date = date(2021, 12, 1), price = form.price_change.data)]
|
|
||||||
if form.amount_change.data:
|
|
||||||
new_item.AmountChange = [AmountChange(Item = new_item, date = date(2021, 12, 1), amount = form.amount_change.data)]
|
|
||||||
db.session.add(new_item)
|
|
||||||
db.session.commit()
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
return render_template('main/new_item.html', form=form)
|
|
||||||
|
|
||||||
@bp.route('/overview/register_boughts', methods=['GET'])
|
|
||||||
@login_required
|
|
||||||
def check_unregistered_items():
|
|
||||||
if current_user.is_anonymous or not request.args or 'establishment' not in request.args:
|
|
||||||
abort(403)
|
|
||||||
establishment = Establishment.query.get(int(request.args['establishment']))
|
|
||||||
if current_user.id != establishment.owner:
|
|
||||||
abort(403)
|
|
||||||
results = database_utils.get_unregistered_and_register(establishment.id)
|
|
||||||
if results:
|
|
||||||
result_list = view_utils.group_results(results)
|
|
||||||
else:
|
|
||||||
result_list = []
|
|
||||||
if request.content_type == "application/json":
|
|
||||||
return jsonify(result_list)
|
|
||||||
else:
|
|
||||||
return render_template("main/overview.html", results=result_list)
|
|
||||||
126
app/models.py
126
app/models.py
@ -1,126 +0,0 @@
|
|||||||
from app import db, login
|
|
||||||
from datetime import date
|
|
||||||
from flask_login import UserMixin
|
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
|
||||||
|
|
||||||
item_category = db.Table("item_category",
|
|
||||||
db.Column("item", db.ForeignKey("item.id"), primary_key=True, server_onupdate=db.FetchedValue()),
|
|
||||||
db.Column("category", db.ForeignKey("category.id"), primary_key=True, server_onupdate=db.FetchedValue())
|
|
||||||
)
|
|
||||||
|
|
||||||
class User(UserMixin, db.Model):
|
|
||||||
id = db.Column(db.BigInteger, primary_key=True)
|
|
||||||
email = db.Column(db.String(255), nullable=False, unique=True)
|
|
||||||
password_hash = db.Column(db.String(128), nullable=False)
|
|
||||||
|
|
||||||
LoginToken = db.relationship("LoginToken", backref='User', lazy='dynamic')
|
|
||||||
Bought = db.relationship("Bought", secondary="login_token",
|
|
||||||
lazy='dynamic', overlaps="User,LoginToken")
|
|
||||||
|
|
||||||
def set_password(self, password):
|
|
||||||
self.password_hash = generate_password_hash(password)
|
|
||||||
|
|
||||||
def check_password(self, password):
|
|
||||||
return check_password_hash(self.password_hash, password)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<User {self.id} ({self.email})>"
|
|
||||||
|
|
||||||
class Establishment(db.Model):
|
|
||||||
id = db.Column(db.BigInteger, primary_key=True)
|
|
||||||
name = db.Column(db.String(64), nullable=False)
|
|
||||||
owner = db.Column(db.ForeignKey('user.id'), nullable=False)
|
|
||||||
|
|
||||||
LoginToken = db.relationship("LoginToken", backref='Establishment', lazy='dynamic')
|
|
||||||
Bought = db.relationship("Bought", secondary="login_token",
|
|
||||||
lazy='dynamic', overlaps="Establishment,LoginToken,Bought")
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Establishment {self.id} ({self.name})>"
|
|
||||||
|
|
||||||
class LoginToken(db.Model):
|
|
||||||
user = db.Column(db.ForeignKey('user.id'), primary_key=True, server_onupdate=db.FetchedValue())
|
|
||||||
establishment = db.Column(db.ForeignKey('establishment.id'), primary_key=True, server_onupdate=db.FetchedValue())
|
|
||||||
token = db.Column(db.String(15), nullable=True, unique=True)
|
|
||||||
paid = db.Column(db.BigInteger, nullable=False, server_default=str(0))
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"LoginToken {self.token}"
|
|
||||||
|
|
||||||
class Brand(db.Model):
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
name = db.Column(db.String(32), nullable=False)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Brand {self.id} ({self.name})>"
|
|
||||||
|
|
||||||
class Category(db.Model):
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
name = db.Column(db.String(32), nullable=False, unique=True)
|
|
||||||
|
|
||||||
Item = db.relationship("Item", secondary=item_category, lazy="dynamic", back_populates="Category")
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Category {self.id} ({self.name})>"
|
|
||||||
|
|
||||||
class Item(db.Model):
|
|
||||||
id = db.Column(db.BigInteger, primary_key=True, autoincrement=False)
|
|
||||||
name = db.Column(db.String(64), nullable=False)
|
|
||||||
brand = db.Column(db.ForeignKey('brand.id'), nullable=False, server_onupdate=db.FetchedValue())
|
|
||||||
description = db.Column(db.Text, nullable=False)
|
|
||||||
|
|
||||||
Category = db.relationship("Category", secondary=item_category, lazy="dynamic", back_populates="Item")
|
|
||||||
Bought = db.relationship("Bought", backref='Item', lazy='dynamic')
|
|
||||||
PriceChange = db.relationship("PriceChange", backref='Item', lazy='dynamic')
|
|
||||||
AmountChange = db.relationship("AmountChange", backref='Item', lazy='dynamic')
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Item {self.id} ({self.name})>"
|
|
||||||
|
|
||||||
class Bought(db.Model):
|
|
||||||
token = db.Column(db.ForeignKey('login_token.token'), primary_key=True, server_onupdate=db.FetchedValue())
|
|
||||||
item = db.Column(db.ForeignKey('item.id'), primary_key=True, server_onupdate=db.FetchedValue())
|
|
||||||
date = db.Column(db.Date, primary_key=True)
|
|
||||||
amount = db.Column(db.SmallInteger, nullable=False)
|
|
||||||
registered = db.Column(db.Boolean, nullable=False, server_default=str(False))
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Bought Object>"
|
|
||||||
|
|
||||||
class PriceChange(db.Model):
|
|
||||||
item = db.Column(db.ForeignKey('item.id'), primary_key=True, server_onupdate=db.FetchedValue())
|
|
||||||
date = db.Column(db.Date, primary_key=True, server_default=str(date(2021, 12, 1)))
|
|
||||||
price = db.Column(db.SmallInteger, nullable=False)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Price_Change {self.item} ({self.date})>"
|
|
||||||
|
|
||||||
class AmountChange(db.Model):
|
|
||||||
item = db.Column(db.ForeignKey('item.id'), primary_key=True, server_onupdate=db.FetchedValue())
|
|
||||||
date = db.Column(db.Date, primary_key=True, server_default=str(date(2021, 12, 1)))
|
|
||||||
amount = db.Column(db.SmallInteger, nullable=False, server_default=str(1))
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Amount_Change {self.item} ({self.date})>"
|
|
||||||
|
|
||||||
class Receipt(db.Model):
|
|
||||||
id = db.Column(db.Numeric(precision=24, scale=0), primary_key=True, autoincrement=False)
|
|
||||||
date = db.Column(db.Date, nullable=False)
|
|
||||||
from_user = db.Column(db.ForeignKey("login_token.token"), server_onupdate=db.FetchedValue())
|
|
||||||
registered = db.Column(db.Boolean, nullable=False, server_default=str(False))
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Receipt {self.id}>"
|
|
||||||
|
|
||||||
class ItemReceipt(db.Model):
|
|
||||||
receipt = db.Column(db.ForeignKey("receipt.id"), primary_key=True, server_onupdate=db.FetchedValue())
|
|
||||||
item = db.Column(db.ForeignKey("item.id"), primary_key=True, server_onupdate=db.FetchedValue())
|
|
||||||
amount = db.Column(db.SmallInteger, nullable=False)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<ItemReceipt {self.receipt}: {self.item}>"
|
|
||||||
|
|
||||||
|
|
||||||
@login.user_loader
|
|
||||||
def load_user(id):
|
|
||||||
return User.query.get(int(id))
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
{% import 'bootstrap/wtf.html' as wtf %}
|
|
||||||
|
|
||||||
{% block app_content %}
|
|
||||||
<h1>Sign In</h1>
|
|
||||||
<form action="" method="post" novalidate>
|
|
||||||
{{ form.hidden_tag() }}
|
|
||||||
<p>
|
|
||||||
{{ wtf.form_field(form.email) }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{{ wtf.form_field(form.password) }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{{ wtf.form_field(form.remember_me) }}
|
|
||||||
</p>
|
|
||||||
{{ wtf.form_field(form.submit, class=form.submit.render_kw["class"]) }}
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
{% import 'bootstrap/wtf.html' as wtf %}
|
|
||||||
|
|
||||||
{% block app_content %}
|
|
||||||
<h1>Register</h1>
|
|
||||||
<form action="" method="post">
|
|
||||||
{{ form.hidden_tag() }}
|
|
||||||
<p>
|
|
||||||
{{ wtf.form_field(form.email) }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{{ wtf.form_field(form.password) }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{{ wtf.form_field(form.password2) }}
|
|
||||||
</p>
|
|
||||||
{{ wtf.form_field(form.submit, class=form.submit.render_kw["class"]) }}
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
{% extends "bootstrap/base.html" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{% if title %}
|
|
||||||
{{ title }}
|
|
||||||
{% else %}
|
|
||||||
Scan2Kasse
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block metas %}
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block styles %}
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
|
||||||
<link rel="stylesheet" href={{ url_for('static', filename="sidebars.css")}}>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block navbar %}
|
|
||||||
<main>
|
|
||||||
<div class="flex-shrink-0 p-3 bg-black bg-opacity-10 scrollbar-primary h-100 position-fixed" style="width: 280px;">
|
|
||||||
<a href="/" class="d-flex align-items-center pb-3 mb-3 link-dark text-decoration-none border-bottom border-dark">
|
|
||||||
<svg class="bi me-2" width="30" height="24"><use xlink:href="#bootstrap"></use></svg>
|
|
||||||
<span class="fs-5 fw-semibold">Scan2Kasse</span>
|
|
||||||
</a>
|
|
||||||
<ul class="list-unstyled ps-0">
|
|
||||||
<li class="mb-1">
|
|
||||||
<button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#home-collapse" aria-expanded="true">
|
|
||||||
Home (WIP)
|
|
||||||
</button>
|
|
||||||
<div class="collapse show" id="home-collapse">
|
|
||||||
<ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
|
|
||||||
<li><a href="#" class="link-dark rounded">Übersicht</a></li>
|
|
||||||
<li><a href="#" class="link-dark rounded">Updates</a></li>
|
|
||||||
<li><a href="#" class="link-dark rounded">Reports</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="mb-1">
|
|
||||||
<button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#dashboard-collapse" aria-expanded="false">
|
|
||||||
Übersicht
|
|
||||||
</button>
|
|
||||||
<div class="collapse" id="dashboard-collapse">
|
|
||||||
<ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
|
|
||||||
{% if establishments %}
|
|
||||||
<li><a href="#" class="link-dark rounded">Allgemein</a></li>
|
|
||||||
{% for establishment in establishments %}
|
|
||||||
<li><a href="{{ url_for('main.get_report_from_user', establishment=establishment.id) }}" class="link-dark rounded">{{ establishment.name }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<!-- <li class="mb-1">
|
|
||||||
<button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#orders-collapse" aria-expanded="false">
|
|
||||||
Orders
|
|
||||||
</button>
|
|
||||||
<div class="collapse" id="orders-collapse">
|
|
||||||
<ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
|
|
||||||
<li><a href="#" class="link-dark rounded">New</a></li>
|
|
||||||
<li><a href="#" class="link-dark rounded">Processed</a></li>
|
|
||||||
<li><a href="#" class="link-dark rounded">Shipped</a></li>
|
|
||||||
<li><a href="#" class="link-dark rounded">Returned</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</li> -->
|
|
||||||
<li class="border-top border-dark my-3"></li>
|
|
||||||
<li class="mb-1">
|
|
||||||
<button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#account-collapse" aria-expanded="false">
|
|
||||||
Account
|
|
||||||
</button>
|
|
||||||
<div class="collapse" id="account-collapse" style="">
|
|
||||||
<ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
|
|
||||||
<!-- <li><a href="#" class="link-dark rounded">New...</a></li>
|
|
||||||
<li><a href="#" class="link-dark rounded">Settings</a></li> -->
|
|
||||||
{% if current_user.is_authenticated %}
|
|
||||||
<!-- <li><a href="#" class="link-dark rounded">Profile</a></li> -->
|
|
||||||
<li><a href={{ url_for('auth.web_logout') }} class="link-dark rounded">Sign out</a></li>
|
|
||||||
{% else %}
|
|
||||||
<li><a href={{ url_for('auth.web_register') }} class="link-dark rounded">Register</a></li>
|
|
||||||
<li><a href={{ url_for('auth.web_login') }} class="link-dark rounded">Sign in</a></li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
{% with messages = get_flashed_messages() %}
|
|
||||||
{% if messages %}
|
|
||||||
<ul>
|
|
||||||
{% for message in messages %}
|
|
||||||
<li>{{ message }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
<div style="width: 280px;"></div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="row my-3"></div>
|
|
||||||
<div class="row-md-3">
|
|
||||||
{% block app_content %}{% endblock %}
|
|
||||||
</div>
|
|
||||||
<div class="row my-3"></div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block scripts %}
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
|
||||||
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> -->
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block app_content %}
|
|
||||||
<form action="" method="post">
|
|
||||||
{{ form.hidden_tag() }}
|
|
||||||
<div class="row">{{form.id.label}}</div>
|
|
||||||
<div class="row">{{form.id()}}</div>
|
|
||||||
<div class="row">{{form.name.label}}</div>
|
|
||||||
<div class="row">{{form.name()}}</div>
|
|
||||||
<div class="row">{{form.description.label}}</div>
|
|
||||||
<div class="row">{{form.description()}}</div>
|
|
||||||
<div class="row">{{form.date.label}}</div>
|
|
||||||
<div class="row">{{form.date()}}</div>
|
|
||||||
<div class="row">{{form.price_change.label}}</div>
|
|
||||||
<div class="row">{{form.price_change()}}</div>
|
|
||||||
<div class="row">{{form.amount_change.label}}</div>
|
|
||||||
<div class="row">{{form.amount_change()}}</div>
|
|
||||||
<div class="row">{{form.category.label}}</div>
|
|
||||||
<div class="row">{{form.category()}}</div>
|
|
||||||
<div class="row">{{form.brand.label}}</div>
|
|
||||||
<div class="row">{{form.brand()}}</div>
|
|
||||||
<div class="row">{{form.submit()}}</div>
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block app_content %}
|
|
||||||
{% if establishment %}
|
|
||||||
{% if current_user.id == establishment.owner %}
|
|
||||||
<button type="button" class="btn btn-outline-dark px-2" data-bs-toggle="button" autocomplete="off" onclick="window.location.href='{{ url_for('main.check_unregistered_items', establishment=establishment.id) }}'">
|
|
||||||
Abrechnung
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% for user in results %}
|
|
||||||
<div class="card">
|
|
||||||
<button class="btn btn-primary" data-bs-toggle="collapse" data-bs-target="#b{{ user.id }}" aria-expanded="true">
|
|
||||||
<div class="card-header">
|
|
||||||
<h3>{{ user.email }}: {{ user.sum/100 }} €</h3>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<div class="collapse" id="b{{ user.id }}">
|
|
||||||
{% for item_infos in user.item_infos %}
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="col-sm-1"></div>
|
|
||||||
<div class="col">
|
|
||||||
<h4>{{ item_infos.date }}</h4>
|
|
||||||
{% for item in item_infos.item_list %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-1"></div>
|
|
||||||
<div class="col">
|
|
||||||
{{ item.amount }}x {{ item.name }} je {{ item.price/100 }} €
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
APPNAME = "scan2kasse"
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
from app import db, LOGGER
|
|
||||||
from app.models import Bought, Establishment, Item, LoginToken, User
|
|
||||||
from app.utils.view_utils import bought_with_prices as bwp
|
|
||||||
from copy import deepcopy
|
|
||||||
from datetime import date as dtdate, timedelta
|
|
||||||
from flask_login import current_user
|
|
||||||
from psycopg2 import errors
|
|
||||||
from random import choice as rndchoice
|
|
||||||
from sqlalchemy import and_, text
|
|
||||||
from sqlalchemy.dialects.postgresql import insert
|
|
||||||
from string import ascii_letters, digits
|
|
||||||
|
|
||||||
def insert_bought_items(token: str, items: dict, date: str = None):
|
|
||||||
if not date:
|
|
||||||
date = dtdate.today()
|
|
||||||
for item, amount in deepcopy(items).items():
|
|
||||||
query_insert = insert(Bought).values(token=token, item=int(item), date=date, amount=int(amount))
|
|
||||||
query_insert = query_insert.on_conflict_do_update("bought_pkey", set_=dict(amount=text(f'bought.amount + {amount}')))
|
|
||||||
try:
|
|
||||||
db.session.execute(query_insert)
|
|
||||||
db.session.commit()
|
|
||||||
except errors.ForeignKeyViolation as e:
|
|
||||||
db.session.rollback()
|
|
||||||
except Exception as e:
|
|
||||||
db.session.rollback()
|
|
||||||
LOGGER.exception("")
|
|
||||||
else:
|
|
||||||
del(items[item])
|
|
||||||
return {'user':token, 'date': date, 'items': items} if items else {}
|
|
||||||
|
|
||||||
def get_report(**kwargs):
|
|
||||||
query_select = db.session.query(bwp.c.token, User.email, bwp.c.date, bwp.c.item, Item.name, bwp.c.amount, bwp.c.price)
|
|
||||||
query_select = query_select.select_from(bwp).join(LoginToken, LoginToken.token==bwp.c.token).join(User, LoginToken.user==User.id).join(Item, Item.id==bwp.c.item)
|
|
||||||
match kwargs:
|
|
||||||
case {"token": token}:
|
|
||||||
LOGGER.debug("Token present")
|
|
||||||
query_select = query_select.filter_by(token == token)
|
|
||||||
case {"establishment": establishment}:
|
|
||||||
LOGGER.debug("Establishment present")
|
|
||||||
if current_user.id == Establishment.query.get(int(establishment)).owner:
|
|
||||||
_filter = db.session.query(LoginToken.token).filter_by(establishment = int(establishment))
|
|
||||||
else:
|
|
||||||
_filter = db.session.query(LoginToken.token).filter_by(establishment = int(establishment), user=current_user.id)
|
|
||||||
query_select = query_select.filter(bwp.c.token.in_(_filter))
|
|
||||||
# LOGGER.debug(str(query_select))
|
|
||||||
match kwargs:
|
|
||||||
case {"month": month}:
|
|
||||||
LOGGER.debug("Month present")
|
|
||||||
year = kwargs["year"] if "year" in kwargs else dtdate.today().year
|
|
||||||
query_select = query_select.filter(bwp.c.date.between(dtdate(int(year), int(month), 1), dtdate(int(year), int(month)+1, 1)-timedelta(days=1)))
|
|
||||||
case {"year": year}:
|
|
||||||
LOGGER.debug("Year present")
|
|
||||||
query_select = query_select.filter(bwp.c.date.between(dtdate(int(year), 1, 1), dtdate(int(year), 12, 31)))
|
|
||||||
query_select = query_select.order_by(bwp.c.token, bwp.c.date, bwp.c.item)
|
|
||||||
# LOGGER.debug(str(query_select))
|
|
||||||
results = query_select.all()
|
|
||||||
return tuple(results)
|
|
||||||
|
|
||||||
def get_unregistered_and_register(intEstablishment: int):
|
|
||||||
LOGGER.debug("Getting unregistered")
|
|
||||||
establishment = Establishment.query.get(intEstablishment)
|
|
||||||
if current_user.id != establishment.owner:
|
|
||||||
LOGGER.debug("!!!Wrong User!!!")
|
|
||||||
return False
|
|
||||||
query_select = db.session.query(bwp.c.token, User.email, bwp.c.date, bwp.c.item, Item.name, bwp.c.amount, bwp.c.price)
|
|
||||||
query_select = query_select.select_from(bwp).join(LoginToken, LoginToken.token==bwp.c.token).join(User, LoginToken.user==User.id)
|
|
||||||
query_select = query_select.join(Item, Item.id==bwp.c.item).join(Bought, and_(Bought.token==bwp.c.token, Bought.item==bwp.c.item, Bought.date==bwp.c.date))
|
|
||||||
query_select = query_select.filter(bwp.c.token.in_(db.session.query(LoginToken.token).filter_by(establishment = intEstablishment)))
|
|
||||||
query_select = query_select.filter(Bought.registered == False)
|
|
||||||
query_select = query_select.order_by(bwp.c.token, bwp.c.date, bwp.c.item)
|
|
||||||
results = query_select.all()
|
|
||||||
unregistered_boughts = establishment.Bought.filter_by(registered = False).all()
|
|
||||||
for x in unregistered_boughts:
|
|
||||||
x.registered = True
|
|
||||||
db.session.commit()
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
def generate_token(length = 15, allowed_chars = ascii_letters + digits):
|
|
||||||
new_token = "".join((rndchoice(allowed_chars) for i in range(length)))
|
|
||||||
if not LoginToken.query.filter_by(token=new_token).first():
|
|
||||||
return new_token
|
|
||||||
return generate_token()
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
from app import db, LOGGER
|
|
||||||
from app.models import AmountChange, Bought, PriceChange
|
|
||||||
from sqlalchemy_utils import create_view
|
|
||||||
|
|
||||||
def group_results(results: tuple) -> list:
|
|
||||||
result_list = []
|
|
||||||
LOGGER.debug("Grouping...")
|
|
||||||
for result in results:
|
|
||||||
try:
|
|
||||||
result_user_index = [result[0] == result_item['id'] for result_item in result_list].index(True)
|
|
||||||
except ValueError as e:
|
|
||||||
result_list.append({"id": result[0], "email": result[1], "sum": 0, "item_infos": []})
|
|
||||||
result_user_index = -1
|
|
||||||
result_user = result_list[result_user_index]
|
|
||||||
try:
|
|
||||||
result_date_index = [result[2] == result_list_date['date'] for result_list_date in result_user["item_infos"]].index(True)
|
|
||||||
except ValueError as e:
|
|
||||||
result_user["item_infos"].append({'date': result[2], 'item_list': []})
|
|
||||||
result_date_index = -1
|
|
||||||
result_date = result_user['item_infos'][result_date_index]
|
|
||||||
result_date['item_list'].append({'id': result[3], 'name': result[4], 'amount': result[5], 'price': result[6]})
|
|
||||||
for result_user in result_list:
|
|
||||||
for result_date in result_user['item_infos']:
|
|
||||||
for result_item in result_date['item_list']:
|
|
||||||
result_user['sum'] += result_item['amount'] * result_item['price']
|
|
||||||
LOGGER.debug("Grouped.")
|
|
||||||
return result_list
|
|
||||||
|
|
||||||
def selectable_price_per_amount_view():
|
|
||||||
p = db.aliased(PriceChange, name="p")
|
|
||||||
a = db.aliased(AmountChange, name="a")
|
|
||||||
date = db.func.greatest(p.date, a.date).label("date")
|
|
||||||
price = db.func.ceil(p.price.cast(db.Float)/db.func.coalesce(a.amount, 1)).label("price")
|
|
||||||
select = db.select(p.item.label("item"), date, price)
|
|
||||||
select = select.distinct(p.item, date)
|
|
||||||
select = select.join(a, p.item==a.item, isouter=True)
|
|
||||||
select = select.order_by(p.item, db.desc(db.func.greatest(p.date, a.date)))
|
|
||||||
return select
|
|
||||||
|
|
||||||
price_per_amount = create_view("price_per_amount", selectable_price_per_amount_view(), db.metadata)
|
|
||||||
|
|
||||||
def selectable_bought_with_prices_view():
|
|
||||||
b = db.aliased(Bought, name="b")
|
|
||||||
ppa = price_per_amount.alias("ppa")
|
|
||||||
select = db.select(b.token.label("token"), b.date.label("date"), b.item.label("item"), b.amount.label("amount"), ppa.c.price.label("price"))
|
|
||||||
select = select.distinct(b.token, b.date, b.item)
|
|
||||||
select = select.join(ppa, b.item==ppa.c.item)
|
|
||||||
select = select.where(ppa.c.date<=b.date)
|
|
||||||
select = select.order_by(db.desc(b.token), db.desc(b.date), db.desc(b.item), db.desc(ppa.c.date))
|
|
||||||
return select
|
|
||||||
|
|
||||||
bought_with_prices = create_view("bought_with_prices", selectable_bought_with_prices_view(), db.metadata)
|
|
||||||
31
backend/Pipfile
Normal file
31
backend/Pipfile
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
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 = "*"
|
||||||
|
requests = "*"
|
||||||
|
sqlalchemy-utils = "*"
|
||||||
|
wtforms-sqlalchemy = "*"
|
||||||
|
pytest = "*"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.11"
|
||||||
|
python_full_version = "3.11.4"
|
||||||
721
backend/Pipfile.lock
generated
Normal file
721
backend/Pipfile.lock
generated
Normal file
@ -0,0 +1,721 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "6f12189a28bcfca261128bb19798f69649619d796466a01c69fe3a8df6457fbf"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_full_version": "3.11.4",
|
||||||
|
"python_version": "3.11"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"alembic": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:47d52e3dfb03666ed945becb723d6482e52190917fdb47071440cfdba05d92cb",
|
||||||
|
"sha256:bca5877e9678b454706347bc10b97cb7d67f300320fa5c3a94423e8266e2823f"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==1.12.1"
|
||||||
|
},
|
||||||
|
"blinker": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9",
|
||||||
|
"sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==1.7.0"
|
||||||
|
},
|
||||||
|
"certifi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
|
||||||
|
"sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
|
"version": "==2023.7.22"
|
||||||
|
},
|
||||||
|
"charset-normalizer": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027",
|
||||||
|
"sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087",
|
||||||
|
"sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786",
|
||||||
|
"sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8",
|
||||||
|
"sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09",
|
||||||
|
"sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185",
|
||||||
|
"sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574",
|
||||||
|
"sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e",
|
||||||
|
"sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519",
|
||||||
|
"sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898",
|
||||||
|
"sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269",
|
||||||
|
"sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3",
|
||||||
|
"sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f",
|
||||||
|
"sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6",
|
||||||
|
"sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8",
|
||||||
|
"sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a",
|
||||||
|
"sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73",
|
||||||
|
"sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc",
|
||||||
|
"sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714",
|
||||||
|
"sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2",
|
||||||
|
"sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc",
|
||||||
|
"sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce",
|
||||||
|
"sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d",
|
||||||
|
"sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e",
|
||||||
|
"sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6",
|
||||||
|
"sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269",
|
||||||
|
"sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96",
|
||||||
|
"sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d",
|
||||||
|
"sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a",
|
||||||
|
"sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4",
|
||||||
|
"sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77",
|
||||||
|
"sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d",
|
||||||
|
"sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0",
|
||||||
|
"sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed",
|
||||||
|
"sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068",
|
||||||
|
"sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac",
|
||||||
|
"sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25",
|
||||||
|
"sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8",
|
||||||
|
"sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab",
|
||||||
|
"sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26",
|
||||||
|
"sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2",
|
||||||
|
"sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db",
|
||||||
|
"sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f",
|
||||||
|
"sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5",
|
||||||
|
"sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99",
|
||||||
|
"sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c",
|
||||||
|
"sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d",
|
||||||
|
"sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811",
|
||||||
|
"sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa",
|
||||||
|
"sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a",
|
||||||
|
"sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03",
|
||||||
|
"sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b",
|
||||||
|
"sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04",
|
||||||
|
"sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c",
|
||||||
|
"sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001",
|
||||||
|
"sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458",
|
||||||
|
"sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389",
|
||||||
|
"sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99",
|
||||||
|
"sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985",
|
||||||
|
"sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537",
|
||||||
|
"sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238",
|
||||||
|
"sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f",
|
||||||
|
"sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d",
|
||||||
|
"sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796",
|
||||||
|
"sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a",
|
||||||
|
"sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143",
|
||||||
|
"sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8",
|
||||||
|
"sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c",
|
||||||
|
"sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5",
|
||||||
|
"sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5",
|
||||||
|
"sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711",
|
||||||
|
"sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4",
|
||||||
|
"sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6",
|
||||||
|
"sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c",
|
||||||
|
"sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7",
|
||||||
|
"sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4",
|
||||||
|
"sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b",
|
||||||
|
"sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae",
|
||||||
|
"sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12",
|
||||||
|
"sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c",
|
||||||
|
"sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae",
|
||||||
|
"sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8",
|
||||||
|
"sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887",
|
||||||
|
"sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b",
|
||||||
|
"sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4",
|
||||||
|
"sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f",
|
||||||
|
"sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5",
|
||||||
|
"sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33",
|
||||||
|
"sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519",
|
||||||
|
"sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"
|
||||||
|
],
|
||||||
|
"markers": "python_full_version >= '3.7.0'",
|
||||||
|
"version": "==3.3.2"
|
||||||
|
},
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
|
||||||
|
"sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==8.1.7"
|
||||||
|
},
|
||||||
|
"colorama": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
|
||||||
|
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
|
||||||
|
],
|
||||||
|
"markers": "sys_platform == 'win32'",
|
||||||
|
"version": "==0.4.6"
|
||||||
|
},
|
||||||
|
"dnspython": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8",
|
||||||
|
"sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8' and python_version < '4.0'",
|
||||||
|
"version": "==2.4.2"
|
||||||
|
},
|
||||||
|
"dominate": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1a916479c45b95fedba0d077b081d77c2d2e0f0f484ac827105087af23661d73",
|
||||||
|
"sha256:4c90c3befaf88e612b71f4b39af7bcbef8977acfa855cec957225a8fbf504007"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==2.8.0"
|
||||||
|
},
|
||||||
|
"email-validator": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:a4b0bd1cf55f073b924258d19321b1f3aa74b4b5a71a42c305575dba920e1a44",
|
||||||
|
"sha256:c973053efbeddfef924dc0bd93f6e77a1ea7ee0fce935aea7103c7a3d6d2d637"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.1.0.post1"
|
||||||
|
},
|
||||||
|
"flask": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:21128f47e4e3b9d597a3e8521a329bf56909b690fcc3fa3e477725aa81367638",
|
||||||
|
"sha256:cfadcdb638b609361d29ec22360d6070a77d7463dcb3ab08d2c2f2f168845f58"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.0.0"
|
||||||
|
},
|
||||||
|
"flask-bootstrap": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:cb08ed940183f6343a64e465e83b3a3f13c53e1baabb8d72b5da4545ef123ac8"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.3.7.1"
|
||||||
|
},
|
||||||
|
"flask-cors": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:bc3492bfd6368d27cfe79c7821df5a8a319e1a6d5eab277a3794be19bdc51783",
|
||||||
|
"sha256:f268522fcb2f73e2ecdde1ef45e2fd5c71cc48fe03cffb4b441c6d1b40684eb0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==4.0.0"
|
||||||
|
},
|
||||||
|
"flask-login": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5e23d14a607ef12806c699590b89d0f0e0d67baeec599d75947bf9c147330333",
|
||||||
|
"sha256:849b25b82a436bf830a054e74214074af59097171562ab10bfa999e6b78aae5d"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.6.3"
|
||||||
|
},
|
||||||
|
"flask-mail": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:22e5eb9a940bf407bcf30410ecc3708f3c56cc44b29c34e1726fe85006935f41"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.9.1"
|
||||||
|
},
|
||||||
|
"flask-marshmallow": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2083ae55bebb5142fff98c6bbd483a2f5dbc531a8bc1be2180ed5f75e7f3fccc",
|
||||||
|
"sha256:ce08a153f74da6ebfffd8065d1687508b0179df37fff7fc0c8f28ccfb64f1b56"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.15.0"
|
||||||
|
},
|
||||||
|
"flask-migrate": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:613a2df703998e78716cace68cd83972960834424457f5b67f56e74fff950aef",
|
||||||
|
"sha256:d3f437a8b5f3849d1bb1b60e1b818efc564c66e3fefe90b62e5db08db295e1b1"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==4.0.5"
|
||||||
|
},
|
||||||
|
"flask-sqlalchemy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4ba4be7f419dc72f4efd8802d69974803c37259dd42f3913b0dcf75c9447e0a0",
|
||||||
|
"sha256:e4b68bb881802dda1a7d878b2fc84c06d1ee57fb40b874d3dc97dabfa36b8312"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.1.1"
|
||||||
|
},
|
||||||
|
"flask-wtf": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:8bb269eb9bb46b87e7c8233d7e7debdf1f8b74bf90cc1789988c29b37a97b695",
|
||||||
|
"sha256:fa6793f2fb7e812e0fe9743b282118e581fb1b6c45d414b8af05e659bd653287"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.2.1"
|
||||||
|
},
|
||||||
|
"greenlet": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0a02d259510b3630f330c86557331a3b0e0c79dac3d166e449a39363beaae174",
|
||||||
|
"sha256:0b6f9f8ca7093fd4433472fd99b5650f8a26dcd8ba410e14094c1e44cd3ceddd",
|
||||||
|
"sha256:100f78a29707ca1525ea47388cec8a049405147719f47ebf3895e7509c6446aa",
|
||||||
|
"sha256:1757936efea16e3f03db20efd0cd50a1c86b06734f9f7338a90c4ba85ec2ad5a",
|
||||||
|
"sha256:19075157a10055759066854a973b3d1325d964d498a805bb68a1f9af4aaef8ec",
|
||||||
|
"sha256:19bbdf1cce0346ef7341705d71e2ecf6f41a35c311137f29b8a2dc2341374565",
|
||||||
|
"sha256:20107edf7c2c3644c67c12205dc60b1bb11d26b2610b276f97d666110d1b511d",
|
||||||
|
"sha256:22f79120a24aeeae2b4471c711dcf4f8c736a2bb2fabad2a67ac9a55ea72523c",
|
||||||
|
"sha256:2847e5d7beedb8d614186962c3d774d40d3374d580d2cbdab7f184580a39d234",
|
||||||
|
"sha256:28e89e232c7593d33cac35425b58950789962011cc274aa43ef8865f2e11f46d",
|
||||||
|
"sha256:329c5a2e5a0ee942f2992c5e3ff40be03e75f745f48847f118a3cfece7a28546",
|
||||||
|
"sha256:337322096d92808f76ad26061a8f5fccb22b0809bea39212cd6c406f6a7060d2",
|
||||||
|
"sha256:3fcc780ae8edbb1d050d920ab44790201f027d59fdbd21362340a85c79066a74",
|
||||||
|
"sha256:41bdeeb552d814bcd7fb52172b304898a35818107cc8778b5101423c9017b3de",
|
||||||
|
"sha256:4eddd98afc726f8aee1948858aed9e6feeb1758889dfd869072d4465973f6bfd",
|
||||||
|
"sha256:52e93b28db27ae7d208748f45d2db8a7b6a380e0d703f099c949d0f0d80b70e9",
|
||||||
|
"sha256:55d62807f1c5a1682075c62436702aaba941daa316e9161e4b6ccebbbf38bda3",
|
||||||
|
"sha256:5805e71e5b570d490938d55552f5a9e10f477c19400c38bf1d5190d760691846",
|
||||||
|
"sha256:599daf06ea59bfedbec564b1692b0166a0045f32b6f0933b0dd4df59a854caf2",
|
||||||
|
"sha256:60d5772e8195f4e9ebf74046a9121bbb90090f6550f81d8956a05387ba139353",
|
||||||
|
"sha256:696d8e7d82398e810f2b3622b24e87906763b6ebfd90e361e88eb85b0e554dc8",
|
||||||
|
"sha256:6e6061bf1e9565c29002e3c601cf68569c450be7fc3f7336671af7ddb4657166",
|
||||||
|
"sha256:80ac992f25d10aaebe1ee15df45ca0d7571d0f70b645c08ec68733fb7a020206",
|
||||||
|
"sha256:816bd9488a94cba78d93e1abb58000e8266fa9cc2aa9ccdd6eb0696acb24005b",
|
||||||
|
"sha256:85d2b77e7c9382f004b41d9c72c85537fac834fb141b0296942d52bf03fe4a3d",
|
||||||
|
"sha256:87c8ceb0cf8a5a51b8008b643844b7f4a8264a2c13fcbcd8a8316161725383fe",
|
||||||
|
"sha256:89ee2e967bd7ff85d84a2de09df10e021c9b38c7d91dead95b406ed6350c6997",
|
||||||
|
"sha256:8bef097455dea90ffe855286926ae02d8faa335ed8e4067326257cb571fc1445",
|
||||||
|
"sha256:8d11ebbd679e927593978aa44c10fc2092bc454b7d13fdc958d3e9d508aba7d0",
|
||||||
|
"sha256:91e6c7db42638dc45cf2e13c73be16bf83179f7859b07cfc139518941320be96",
|
||||||
|
"sha256:97e7ac860d64e2dcba5c5944cfc8fa9ea185cd84061c623536154d5a89237884",
|
||||||
|
"sha256:990066bff27c4fcf3b69382b86f4c99b3652bab2a7e685d968cd4d0cfc6f67c6",
|
||||||
|
"sha256:9fbc5b8f3dfe24784cee8ce0be3da2d8a79e46a276593db6868382d9c50d97b1",
|
||||||
|
"sha256:ac4a39d1abae48184d420aa8e5e63efd1b75c8444dd95daa3e03f6c6310e9619",
|
||||||
|
"sha256:b2c02d2ad98116e914d4f3155ffc905fd0c025d901ead3f6ed07385e19122c94",
|
||||||
|
"sha256:b2d3337dcfaa99698aa2377c81c9ca72fcd89c07e7eb62ece3f23a3fe89b2ce4",
|
||||||
|
"sha256:b489c36d1327868d207002391f662a1d163bdc8daf10ab2e5f6e41b9b96de3b1",
|
||||||
|
"sha256:b641161c302efbb860ae6b081f406839a8b7d5573f20a455539823802c655f63",
|
||||||
|
"sha256:b8ba29306c5de7717b5761b9ea74f9c72b9e2b834e24aa984da99cbfc70157fd",
|
||||||
|
"sha256:b9934adbd0f6e476f0ecff3c94626529f344f57b38c9a541f87098710b18af0a",
|
||||||
|
"sha256:ce85c43ae54845272f6f9cd8320d034d7a946e9773c693b27d620edec825e376",
|
||||||
|
"sha256:cf868e08690cb89360eebc73ba4be7fb461cfbc6168dd88e2fbbe6f31812cd57",
|
||||||
|
"sha256:d2905ce1df400360463c772b55d8e2518d0e488a87cdea13dd2c71dcb2a1fa16",
|
||||||
|
"sha256:d57e20ba591727da0c230ab2c3f200ac9d6d333860d85348816e1dca4cc4792e",
|
||||||
|
"sha256:d6a8c9d4f8692917a3dc7eb25a6fb337bff86909febe2f793ec1928cd97bedfc",
|
||||||
|
"sha256:d923ff276f1c1f9680d32832f8d6c040fe9306cbfb5d161b0911e9634be9ef0a",
|
||||||
|
"sha256:daa7197b43c707462f06d2c693ffdbb5991cbb8b80b5b984007de431493a319c",
|
||||||
|
"sha256:dbd4c177afb8a8d9ba348d925b0b67246147af806f0b104af4d24f144d461cd5",
|
||||||
|
"sha256:dc4d815b794fd8868c4d67602692c21bf5293a75e4b607bb92a11e821e2b859a",
|
||||||
|
"sha256:e9d21aaa84557d64209af04ff48e0ad5e28c5cca67ce43444e939579d085da72",
|
||||||
|
"sha256:ea6b8aa9e08eea388c5f7a276fabb1d4b6b9d6e4ceb12cc477c3d352001768a9",
|
||||||
|
"sha256:eabe7090db68c981fca689299c2d116400b553f4b713266b130cfc9e2aa9c5a9",
|
||||||
|
"sha256:f2f6d303f3dee132b322a14cd8765287b8f86cdc10d2cb6a6fae234ea488888e",
|
||||||
|
"sha256:f33f3258aae89da191c6ebaa3bc517c6c4cbc9b9f689e5d8452f7aedbb913fa8",
|
||||||
|
"sha256:f7bfb769f7efa0eefcd039dd19d843a4fbfbac52f1878b1da2ed5793ec9b1a65",
|
||||||
|
"sha256:f89e21afe925fcfa655965ca8ea10f24773a1791400989ff32f467badfe4a064",
|
||||||
|
"sha256:fa24255ae3c0ab67e613556375a4341af04a084bd58764731972bcbc8baeba36"
|
||||||
|
],
|
||||||
|
"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": "==3.0.1"
|
||||||
|
},
|
||||||
|
"idna": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
|
||||||
|
"sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
|
"version": "==3.4"
|
||||||
|
},
|
||||||
|
"iniconfig": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
|
||||||
|
"sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==2.0.0"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"mako": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:57d4e997349f1a92035aa25c17ace371a4213f2ca42f99bee9a602500cfd54d9",
|
||||||
|
"sha256:e3a9d388fd00e87043edbe8792f45880ac0114e9c4adc69f6e9bfb2c55e3b11b"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==1.3.0"
|
||||||
|
},
|
||||||
|
"markupsafe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e",
|
||||||
|
"sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e",
|
||||||
|
"sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431",
|
||||||
|
"sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686",
|
||||||
|
"sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c",
|
||||||
|
"sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559",
|
||||||
|
"sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc",
|
||||||
|
"sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb",
|
||||||
|
"sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939",
|
||||||
|
"sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c",
|
||||||
|
"sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0",
|
||||||
|
"sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4",
|
||||||
|
"sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9",
|
||||||
|
"sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575",
|
||||||
|
"sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba",
|
||||||
|
"sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d",
|
||||||
|
"sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd",
|
||||||
|
"sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3",
|
||||||
|
"sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00",
|
||||||
|
"sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155",
|
||||||
|
"sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac",
|
||||||
|
"sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52",
|
||||||
|
"sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f",
|
||||||
|
"sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8",
|
||||||
|
"sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b",
|
||||||
|
"sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007",
|
||||||
|
"sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24",
|
||||||
|
"sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea",
|
||||||
|
"sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198",
|
||||||
|
"sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0",
|
||||||
|
"sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee",
|
||||||
|
"sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be",
|
||||||
|
"sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2",
|
||||||
|
"sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1",
|
||||||
|
"sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707",
|
||||||
|
"sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6",
|
||||||
|
"sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c",
|
||||||
|
"sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58",
|
||||||
|
"sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823",
|
||||||
|
"sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779",
|
||||||
|
"sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636",
|
||||||
|
"sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c",
|
||||||
|
"sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad",
|
||||||
|
"sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee",
|
||||||
|
"sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc",
|
||||||
|
"sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2",
|
||||||
|
"sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48",
|
||||||
|
"sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7",
|
||||||
|
"sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e",
|
||||||
|
"sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b",
|
||||||
|
"sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa",
|
||||||
|
"sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5",
|
||||||
|
"sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e",
|
||||||
|
"sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb",
|
||||||
|
"sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9",
|
||||||
|
"sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57",
|
||||||
|
"sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc",
|
||||||
|
"sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc",
|
||||||
|
"sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2",
|
||||||
|
"sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==2.1.3"
|
||||||
|
},
|
||||||
|
"marshmallow": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889",
|
||||||
|
"sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==3.20.1"
|
||||||
|
},
|
||||||
|
"marshmallow-sqlalchemy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3523a774390ef0c1c0f7c708a7519809c5396cf608720f14f55c36f74ff5bbec",
|
||||||
|
"sha256:3cee0bf61ed10687c0a41448e1916649b28222334a02f7b937c39d1c69c18bee"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.29.0"
|
||||||
|
},
|
||||||
|
"packaging": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5",
|
||||||
|
"sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==23.2"
|
||||||
|
},
|
||||||
|
"pluggy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12",
|
||||||
|
"sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==1.3.0"
|
||||||
|
},
|
||||||
|
"psycopg2-binary": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9",
|
||||||
|
"sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77",
|
||||||
|
"sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e",
|
||||||
|
"sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84",
|
||||||
|
"sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3",
|
||||||
|
"sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2",
|
||||||
|
"sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67",
|
||||||
|
"sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876",
|
||||||
|
"sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152",
|
||||||
|
"sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f",
|
||||||
|
"sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a",
|
||||||
|
"sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6",
|
||||||
|
"sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503",
|
||||||
|
"sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f",
|
||||||
|
"sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493",
|
||||||
|
"sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996",
|
||||||
|
"sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f",
|
||||||
|
"sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e",
|
||||||
|
"sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59",
|
||||||
|
"sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94",
|
||||||
|
"sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7",
|
||||||
|
"sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682",
|
||||||
|
"sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420",
|
||||||
|
"sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae",
|
||||||
|
"sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291",
|
||||||
|
"sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe",
|
||||||
|
"sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980",
|
||||||
|
"sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93",
|
||||||
|
"sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692",
|
||||||
|
"sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119",
|
||||||
|
"sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716",
|
||||||
|
"sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472",
|
||||||
|
"sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b",
|
||||||
|
"sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2",
|
||||||
|
"sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc",
|
||||||
|
"sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c",
|
||||||
|
"sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5",
|
||||||
|
"sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab",
|
||||||
|
"sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984",
|
||||||
|
"sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9",
|
||||||
|
"sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf",
|
||||||
|
"sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0",
|
||||||
|
"sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f",
|
||||||
|
"sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212",
|
||||||
|
"sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb",
|
||||||
|
"sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be",
|
||||||
|
"sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90",
|
||||||
|
"sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041",
|
||||||
|
"sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7",
|
||||||
|
"sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860",
|
||||||
|
"sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d",
|
||||||
|
"sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245",
|
||||||
|
"sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27",
|
||||||
|
"sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417",
|
||||||
|
"sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359",
|
||||||
|
"sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202",
|
||||||
|
"sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0",
|
||||||
|
"sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7",
|
||||||
|
"sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba",
|
||||||
|
"sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1",
|
||||||
|
"sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd",
|
||||||
|
"sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07",
|
||||||
|
"sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98",
|
||||||
|
"sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55",
|
||||||
|
"sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d",
|
||||||
|
"sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972",
|
||||||
|
"sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f",
|
||||||
|
"sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e",
|
||||||
|
"sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26",
|
||||||
|
"sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957",
|
||||||
|
"sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53",
|
||||||
|
"sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.9.9"
|
||||||
|
},
|
||||||
|
"pyjwt": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de",
|
||||||
|
"sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.8.0"
|
||||||
|
},
|
||||||
|
"pymupdf": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0f852d125defc26716878b1796f4d68870e9065041d00cf46bde317fd8d30e68",
|
||||||
|
"sha256:1103eea4ab727e32b9cb93347b35f71562033018c333a7f3a17d115e980fea4a",
|
||||||
|
"sha256:19d1711d5908c4527ad2deef5af2d066649f3f9a12950faf30be5f7251d18abc",
|
||||||
|
"sha256:1cbcf05c06f314fdf3042ceee674e9a0ac7fae598347d5442e2138c6046d4e82",
|
||||||
|
"sha256:224c341fe254adda97c8f06a4c5838cdbcf609fa89e70b1fb179752533378f2f",
|
||||||
|
"sha256:271bdf6059bb8347f9c9c6b721329bd353a933681b1fc62f43241b410e7ab7ae",
|
||||||
|
"sha256:2885a26220a32fb45ea443443b72194bb7107d6862d8d546b59e4ad0c8a1f2c9",
|
||||||
|
"sha256:2c141f33e2733e48de8524dfd2de56d889feef0c7773b20a8cd216c03ab24793",
|
||||||
|
"sha256:2e27857a15c8a810d0b66455b8c8a79013640b6267a9b4ea808a5fe1f47711f2",
|
||||||
|
"sha256:361cab1be45481bd3dc4e00ec82628ebc189b4f4b6fd9bd78a00cfeed54e0034",
|
||||||
|
"sha256:3ce2d3678dbf822cff213b1902f2e59756313e543efd516a2b4f15bb0353bd6c",
|
||||||
|
"sha256:3f0f9b76bc4f039e7587003cbd40684d93a98441549dd033cab38ca07d61988d",
|
||||||
|
"sha256:4ac9673a6d6ee7e80cb242dacb43f9ca097b502d9c5e44687dbdffc2bce7961a",
|
||||||
|
"sha256:4d06751d5cd213e96f84f2faaa71a51cf4d641851e07579247ca1190121f173b",
|
||||||
|
"sha256:526b26a5207e923aab65877ad305644402851823a352cb92d362053426899354",
|
||||||
|
"sha256:57725e15872f7ab67a9fb3e06e5384d1047b2121e85755c93a6d4266d3ca8983",
|
||||||
|
"sha256:57e22bea69690450197b34dcde16bd9fe0265ac4425b4033535ccc5c044246fb",
|
||||||
|
"sha256:5bdf7020b90987412381acc42427dd1b7a03d771ee9ec273de003e570164ec1a",
|
||||||
|
"sha256:5cd05700c8f18c9dafef63ac2ed3b1099ca06017ca0c32deea13093cea1b8671",
|
||||||
|
"sha256:618b8e884190ac1cca9df1c637f87669d2d532d421d4ee7e4763c848dc4f3a1e",
|
||||||
|
"sha256:6e319c1f49476e07b9a12017c2d031687617713f8a46b7adcec03c636ed04607",
|
||||||
|
"sha256:761501a4965264e81acdd8f2224f993020bf24474e9b34fcdb5805a6826eda1c",
|
||||||
|
"sha256:8fd9c4ee1dd4744a515b9190d8ba9133348b0d94c362293ed77726aa1c13b0a6",
|
||||||
|
"sha256:951d280c1daafac2fd6a664b031f7f98b27eb2def55d39c92a19087bd8041c5d",
|
||||||
|
"sha256:991a37e1cba43775ce094da87cf0bf72172a5532a09644003276bc8bfdfe9f1a",
|
||||||
|
"sha256:c4eb71b88a22c1008f764b3121b36a9d25340f9920b870508356050a365d9ca1",
|
||||||
|
"sha256:c8ea81964c1433ea163ad4b53c56053a87a9ef6e1bd7a879d4d368a3988b60d1",
|
||||||
|
"sha256:e047571d799b30459ad7ee0bc6e68900a7f6b928876f956c976f279808814e72",
|
||||||
|
"sha256:e2d64799c6d9a3735be9e162a5d11061c0b7fbcb1e5fc7446e0993d0f815a93a",
|
||||||
|
"sha256:e33f8ec5ba7265fe78b30332840b8f454184addfa79f9c27f160f19789aa5ffd",
|
||||||
|
"sha256:fd8388e82b6045807d19addf310d8119d32908e89f76cc8bbf8cf1ec36fce947"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.23.6"
|
||||||
|
},
|
||||||
|
"pymupdfb": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:009e2cff166059e13bf71f93919e688f46b8fc11d122433574cfb0cc9134690e",
|
||||||
|
"sha256:7132b30e6ad6ff2013344e3a481b2287fe0be3710d80694807dd6e0d8635f085",
|
||||||
|
"sha256:7bef75988e6979b10ca804cf9487f817aae43b0fff1c6e315b3b9ee0cf1cc32f",
|
||||||
|
"sha256:9925816cbe3e05e920f9be925e5752c2eef42b793885b62075bb0f6a69178598",
|
||||||
|
"sha256:9d24ddadc204e895bee5000ddc7507c801643548e59f5a56aad6d32981d17eeb",
|
||||||
|
"sha256:e5af77580aad3d1103aeec57009d156bfca429cecda14a17c573fcbe97bafb30"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==1.23.6"
|
||||||
|
},
|
||||||
|
"pytest": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac",
|
||||||
|
"sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==7.4.3"
|
||||||
|
},
|
||||||
|
"python-dotenv": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba",
|
||||||
|
"sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.0.0"
|
||||||
|
},
|
||||||
|
"requests": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
|
||||||
|
"sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.31.0"
|
||||||
|
},
|
||||||
|
"sqlalchemy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0666031df46b9badba9bed00092a1ffa3aa063a5e68fa244acd9f08070e936d3",
|
||||||
|
"sha256:0a8c6aa506893e25a04233bc721c6b6cf844bafd7250535abb56cb6cc1368884",
|
||||||
|
"sha256:0e680527245895aba86afbd5bef6c316831c02aa988d1aad83c47ffe92655e74",
|
||||||
|
"sha256:14aebfe28b99f24f8a4c1346c48bc3d63705b1f919a24c27471136d2f219f02d",
|
||||||
|
"sha256:1e018aba8363adb0599e745af245306cb8c46b9ad0a6fc0a86745b6ff7d940fc",
|
||||||
|
"sha256:227135ef1e48165f37590b8bfc44ed7ff4c074bf04dc8d6f8e7f1c14a94aa6ca",
|
||||||
|
"sha256:31952bbc527d633b9479f5f81e8b9dfada00b91d6baba021a869095f1a97006d",
|
||||||
|
"sha256:3e983fa42164577d073778d06d2cc5d020322425a509a08119bdcee70ad856bf",
|
||||||
|
"sha256:42d0b0290a8fb0165ea2c2781ae66e95cca6e27a2fbe1016ff8db3112ac1e846",
|
||||||
|
"sha256:42ede90148b73fe4ab4a089f3126b2cfae8cfefc955c8174d697bb46210c8306",
|
||||||
|
"sha256:4895a63e2c271ffc7a81ea424b94060f7b3b03b4ea0cd58ab5bb676ed02f4221",
|
||||||
|
"sha256:4af79c06825e2836de21439cb2a6ce22b2ca129bad74f359bddd173f39582bf5",
|
||||||
|
"sha256:5f94aeb99f43729960638e7468d4688f6efccb837a858b34574e01143cf11f89",
|
||||||
|
"sha256:616fe7bcff0a05098f64b4478b78ec2dfa03225c23734d83d6c169eb41a93e55",
|
||||||
|
"sha256:62d9e964870ea5ade4bc870ac4004c456efe75fb50404c03c5fd61f8bc669a72",
|
||||||
|
"sha256:638c2c0b6b4661a4fd264f6fb804eccd392745c5887f9317feb64bb7cb03b3ea",
|
||||||
|
"sha256:63bfc3acc970776036f6d1d0e65faa7473be9f3135d37a463c5eba5efcdb24c8",
|
||||||
|
"sha256:6463aa765cf02b9247e38b35853923edbf2f6fd1963df88706bc1d02410a5577",
|
||||||
|
"sha256:64ac935a90bc479fee77f9463f298943b0e60005fe5de2aa654d9cdef46c54df",
|
||||||
|
"sha256:683ef58ca8eea4747737a1c35c11372ffeb84578d3aab8f3e10b1d13d66f2bc4",
|
||||||
|
"sha256:75eefe09e98043cff2fb8af9796e20747ae870c903dc61d41b0c2e55128f958d",
|
||||||
|
"sha256:787af80107fb691934a01889ca8f82a44adedbf5ef3d6ad7d0f0b9ac557e0c34",
|
||||||
|
"sha256:7c424983ab447dab126c39d3ce3be5bee95700783204a72549c3dceffe0fc8f4",
|
||||||
|
"sha256:7e0dc9031baa46ad0dd5a269cb7a92a73284d1309228be1d5935dac8fb3cae24",
|
||||||
|
"sha256:87a3d6b53c39cd173990de2f5f4b83431d534a74f0e2f88bd16eabb5667e65c6",
|
||||||
|
"sha256:89a01238fcb9a8af118eaad3ffcc5dedaacbd429dc6fdc43fe430d3a941ff965",
|
||||||
|
"sha256:9585b646ffb048c0250acc7dad92536591ffe35dba624bb8fd9b471e25212a35",
|
||||||
|
"sha256:964971b52daab357d2c0875825e36584d58f536e920f2968df8d581054eada4b",
|
||||||
|
"sha256:967c0b71156f793e6662dd839da54f884631755275ed71f1539c95bbada9aaab",
|
||||||
|
"sha256:9ca922f305d67605668e93991aaf2c12239c78207bca3b891cd51a4515c72e22",
|
||||||
|
"sha256:a86cb7063e2c9fb8e774f77fbf8475516d270a3e989da55fa05d08089d77f8c4",
|
||||||
|
"sha256:aeb397de65a0a62f14c257f36a726945a7f7bb60253462e8602d9b97b5cbe204",
|
||||||
|
"sha256:b41f5d65b54cdf4934ecede2f41b9c60c9f785620416e8e6c48349ab18643855",
|
||||||
|
"sha256:bd45a5b6c68357578263d74daab6ff9439517f87da63442d244f9f23df56138d",
|
||||||
|
"sha256:c14eba45983d2f48f7546bb32b47937ee2cafae353646295f0e99f35b14286ab",
|
||||||
|
"sha256:c1bda93cbbe4aa2aa0aa8655c5aeda505cd219ff3e8da91d1d329e143e4aff69",
|
||||||
|
"sha256:c4722f3bc3c1c2fcc3702dbe0016ba31148dd6efcd2a2fd33c1b4897c6a19693",
|
||||||
|
"sha256:c80c38bd2ea35b97cbf7c21aeb129dcbebbf344ee01a7141016ab7b851464f8e",
|
||||||
|
"sha256:cabafc7837b6cec61c0e1e5c6d14ef250b675fa9c3060ed8a7e38653bd732ff8",
|
||||||
|
"sha256:cc1d21576f958c42d9aec68eba5c1a7d715e5fc07825a629015fe8e3b0657fb0",
|
||||||
|
"sha256:d0f7fb0c7527c41fa6fcae2be537ac137f636a41b4c5a4c58914541e2f436b45",
|
||||||
|
"sha256:d4041ad05b35f1f4da481f6b811b4af2f29e83af253bf37c3c4582b2c68934ab",
|
||||||
|
"sha256:d5578e6863eeb998980c212a39106ea139bdc0b3f73291b96e27c929c90cd8e1",
|
||||||
|
"sha256:e3b5036aa326dc2df50cba3c958e29b291a80f604b1afa4c8ce73e78e1c9f01d",
|
||||||
|
"sha256:e599a51acf3cc4d31d1a0cf248d8f8d863b6386d2b6782c5074427ebb7803bda",
|
||||||
|
"sha256:f3420d00d2cb42432c1d0e44540ae83185ccbbc67a6054dcc8ab5387add6620b",
|
||||||
|
"sha256:f48ed89dd11c3c586f45e9eec1e437b355b3b6f6884ea4a4c3111a3358fd0c18",
|
||||||
|
"sha256:f508ba8f89e0a5ecdfd3761f82dda2a3d7b678a626967608f4273e0dba8f07ac",
|
||||||
|
"sha256:fd54601ef9cc455a0c61e5245f690c8a3ad67ddb03d3b91c361d076def0b4c60"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==2.0.23"
|
||||||
|
},
|
||||||
|
"sqlalchemy-utils": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6c96b0768ea3f15c0dc56b363d386138c562752b84f647fb8d31a2223aaab801",
|
||||||
|
"sha256:a2181bff01eeb84479e38571d2c0718eb52042f9afd8c194d0d02877e84b7d74"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.41.1"
|
||||||
|
},
|
||||||
|
"typing-extensions": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0",
|
||||||
|
"sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==4.8.0"
|
||||||
|
},
|
||||||
|
"urllib3": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84",
|
||||||
|
"sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==2.0.7"
|
||||||
|
},
|
||||||
|
"visitor": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2c737903b2b6864ebc6167eef7cf3b997126f1aa94bdf590f90f1436d23e480a"
|
||||||
|
],
|
||||||
|
"version": "==0.1.3"
|
||||||
|
},
|
||||||
|
"werkzeug": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc",
|
||||||
|
"sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==3.0.1"
|
||||||
|
},
|
||||||
|
"wtforms": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5e51df8af9a60f6beead75efa10975e97768825a82146a65c7cbf5b915990620",
|
||||||
|
"sha256:ae7c54b29806c70f7bce8eb9f24afceb10ca5c32af3d9f04f74d2f66ccc5c7e0"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==3.1.1"
|
||||||
|
},
|
||||||
|
"wtforms-sqlalchemy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7ca42824ad7c453a036f502b42d9c17d4ad8398ff9248a62ed538d1ce0bc41c3",
|
||||||
|
"sha256:90195d7592bf256d82498c42c79d416832e4a4e6fbca4f1e745a018f66d26c47"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
||||||
0
backend/README.md
Normal file
0
backend/README.md
Normal file
23
backend/configs/config.py
Normal file
23
backend/configs/config.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
load_dotenv(os.path.join(basedir, '.env'))
|
||||||
|
|
||||||
|
os.environ["TESSDATA_PREFIX"] = os.path.join(basedir, 'tessdata')
|
||||||
|
class Config(object):
|
||||||
|
SECRET_KEY = os.environ.get('SECRET_KEY') or "s0m37h!n6-obfu5c471ng"
|
||||||
|
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL', '').replace(
|
||||||
|
'postgres://', 'postgresql://') or \
|
||||||
|
(f"postgresql://{os.environ.get('DATABASE_USER', 'costhive')}:{os.environ.get('DATABASE_PASS', 'asdf1337')}"
|
||||||
|
f"@{os.environ.get('DATABASE_HOST', 'localhost')}:{os.environ.get('DATABASE_PORT', '5432')}"
|
||||||
|
f"/{os.environ.get('DATABASE_DB', '') or os.environ.get('DATABASE_USER', 'costhive')}")
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
MAIL_SERVER = os.environ.get('MAIL_SERVER')
|
||||||
|
MAIL_PORT = int(os.environ.get('MAIL_PORT'))
|
||||||
|
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
|
||||||
|
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
|
||||||
|
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
|
||||||
|
ADMINS = ['postmaster@wpgcommunity.net']
|
||||||
|
POSTS_PER_PAGE = 15
|
||||||
|
RECEIPT_FOLDER = f"{basedir}/../PDFReceipts"
|
||||||
@ -2,20 +2,25 @@
|
|||||||
keys=root, main
|
keys=root, main
|
||||||
|
|
||||||
[handlers]
|
[handlers]
|
||||||
keys=console, file
|
keys=console, file, void
|
||||||
|
|
||||||
[formatters]
|
[formatters]
|
||||||
keys=stdout
|
keys=stdout
|
||||||
|
|
||||||
[logger_root]
|
[logger_root]
|
||||||
handlers = console, file
|
handlers = void
|
||||||
level = DEBUG
|
level = CRITICAL
|
||||||
|
|
||||||
[logger_main]
|
[logger_main]
|
||||||
handlers = console, file
|
handlers = console, file
|
||||||
level = DEBUG
|
level = DEBUG
|
||||||
qualname = main
|
qualname = main
|
||||||
|
|
||||||
|
[handler_void]
|
||||||
|
class = logging.StreamHandler
|
||||||
|
level = CRITICAL
|
||||||
|
formatter = stdout
|
||||||
|
|
||||||
[handler_console]
|
[handler_console]
|
||||||
class = logging.StreamHandler
|
class = logging.StreamHandler
|
||||||
level = DEBUG
|
level = DEBUG
|
||||||
BIN
backend/configs/tessdata/ScrollView.jar
Normal file
BIN
backend/configs/tessdata/ScrollView.jar
Normal file
Binary file not shown.
1
backend/configs/tessdata/configs/alto
Normal file
1
backend/configs/tessdata/configs/alto
Normal file
@ -0,0 +1 @@
|
|||||||
|
tessedit_create_alto 1
|
||||||
7
backend/configs/tessdata/configs/ambigs.train
Normal file
7
backend/configs/tessdata/configs/ambigs.train
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
tessedit_ambigs_training 1
|
||||||
|
load_freq_dawg 0
|
||||||
|
load_punc_dawg 0
|
||||||
|
load_system_dawg 0
|
||||||
|
load_number_dawg 0
|
||||||
|
ambigs_debug_level 3
|
||||||
|
load_fixed_length_dawgs 0
|
||||||
1
backend/configs/tessdata/configs/api_config
Normal file
1
backend/configs/tessdata/configs/api_config
Normal file
@ -0,0 +1 @@
|
|||||||
|
tessedit_zero_rejection T
|
||||||
5
backend/configs/tessdata/configs/bigram
Normal file
5
backend/configs/tessdata/configs/bigram
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
load_bigram_dawg True
|
||||||
|
tessedit_enable_bigram_correction True
|
||||||
|
tessedit_bigram_debug 3
|
||||||
|
save_raw_choices True
|
||||||
|
save_alt_choices True
|
||||||
12
backend/configs/tessdata/configs/box.train
Normal file
12
backend/configs/tessdata/configs/box.train
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
disable_character_fragments T
|
||||||
|
file_type .bl
|
||||||
|
textord_fast_pitch_test T
|
||||||
|
tessedit_zero_rejection T
|
||||||
|
tessedit_minimal_rejection F
|
||||||
|
tessedit_write_rep_codes F
|
||||||
|
edges_children_fix F
|
||||||
|
edges_childarea 0.65
|
||||||
|
edges_boxarea 0.9
|
||||||
|
tessedit_resegment_from_boxes T
|
||||||
|
tessedit_train_from_boxes T
|
||||||
|
textord_no_rejects T
|
||||||
13
backend/configs/tessdata/configs/box.train.stderr
Normal file
13
backend/configs/tessdata/configs/box.train.stderr
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
file_type .bl
|
||||||
|
#tessedit_use_nn F
|
||||||
|
textord_fast_pitch_test T
|
||||||
|
tessedit_zero_rejection T
|
||||||
|
tessedit_minimal_rejection F
|
||||||
|
tessedit_write_rep_codes F
|
||||||
|
edges_children_fix F
|
||||||
|
edges_childarea 0.65
|
||||||
|
edges_boxarea 0.9
|
||||||
|
tessedit_resegment_from_boxes T
|
||||||
|
tessedit_train_from_boxes T
|
||||||
|
#textord_repeat_extraction F
|
||||||
|
textord_no_rejects T
|
||||||
1
backend/configs/tessdata/configs/digits
Normal file
1
backend/configs/tessdata/configs/digits
Normal file
@ -0,0 +1 @@
|
|||||||
|
tessedit_char_whitelist 0123456789-.
|
||||||
1
backend/configs/tessdata/configs/get.images
Normal file
1
backend/configs/tessdata/configs/get.images
Normal file
@ -0,0 +1 @@
|
|||||||
|
tessedit_write_images T
|
||||||
2
backend/configs/tessdata/configs/hocr
Normal file
2
backend/configs/tessdata/configs/hocr
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
tessedit_create_hocr 1
|
||||||
|
hocr_font_info 0
|
||||||
2
backend/configs/tessdata/configs/inter
Normal file
2
backend/configs/tessdata/configs/inter
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
interactive_display_mode T
|
||||||
|
tessedit_display_outwords T
|
||||||
4
backend/configs/tessdata/configs/kannada
Normal file
4
backend/configs/tessdata/configs/kannada
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
textord_skewsmooth_offset 8
|
||||||
|
textord_skewsmooth_offset2 8
|
||||||
|
textord_merge_desc 0.5
|
||||||
|
textord_no_rejects 1
|
||||||
2
backend/configs/tessdata/configs/linebox
Normal file
2
backend/configs/tessdata/configs/linebox
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
tessedit_resegment_from_line_boxes 1
|
||||||
|
tessedit_make_boxes_from_boxes 1
|
||||||
1
backend/configs/tessdata/configs/logfile
Normal file
1
backend/configs/tessdata/configs/logfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
debug_file tesseract.log
|
||||||
11
backend/configs/tessdata/configs/lstm.train
Normal file
11
backend/configs/tessdata/configs/lstm.train
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
file_type .bl
|
||||||
|
textord_fast_pitch_test T
|
||||||
|
tessedit_zero_rejection T
|
||||||
|
tessedit_minimal_rejection F
|
||||||
|
tessedit_write_rep_codes F
|
||||||
|
edges_children_fix F
|
||||||
|
edges_childarea 0.65
|
||||||
|
edges_boxarea 0.9
|
||||||
|
tessedit_train_line_recognizer T
|
||||||
|
textord_no_rejects T
|
||||||
|
tessedit_init_config_only T
|
||||||
1
backend/configs/tessdata/configs/lstmbox
Normal file
1
backend/configs/tessdata/configs/lstmbox
Normal file
@ -0,0 +1 @@
|
|||||||
|
tessedit_create_lstmbox 1
|
||||||
4
backend/configs/tessdata/configs/lstmdebug
Normal file
4
backend/configs/tessdata/configs/lstmdebug
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
stopper_debug_level 1
|
||||||
|
classify_debug_level 1
|
||||||
|
segsearch_debug_level 1
|
||||||
|
language_model_debug_level 3
|
||||||
1
backend/configs/tessdata/configs/makebox
Normal file
1
backend/configs/tessdata/configs/makebox
Normal file
@ -0,0 +1 @@
|
|||||||
|
tessedit_create_boxfile 1
|
||||||
1
backend/configs/tessdata/configs/pdf
Normal file
1
backend/configs/tessdata/configs/pdf
Normal file
@ -0,0 +1 @@
|
|||||||
|
tessedit_create_pdf 1
|
||||||
1
backend/configs/tessdata/configs/quiet
Normal file
1
backend/configs/tessdata/configs/quiet
Normal file
@ -0,0 +1 @@
|
|||||||
|
debug_file /dev/null
|
||||||
2
backend/configs/tessdata/configs/rebox
Normal file
2
backend/configs/tessdata/configs/rebox
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
tessedit_resegment_from_boxes 1
|
||||||
|
tessedit_make_boxes_from_boxes 1
|
||||||
12
backend/configs/tessdata/configs/strokewidth
Normal file
12
backend/configs/tessdata/configs/strokewidth
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
textord_show_blobs 0
|
||||||
|
textord_debug_tabfind 3
|
||||||
|
textord_tabfind_show_partitions 1
|
||||||
|
textord_tabfind_show_initial_partitions 1
|
||||||
|
textord_tabfind_show_columns 1
|
||||||
|
textord_tabfind_show_blocks 1
|
||||||
|
textord_tabfind_show_initialtabs 1
|
||||||
|
textord_tabfind_show_finaltabs 1
|
||||||
|
textord_tabfind_show_strokewidths 1
|
||||||
|
textord_tabfind_show_vlines 0
|
||||||
|
textord_tabfind_show_images 1
|
||||||
|
tessedit_dump_pageseg_images 0
|
||||||
1
backend/configs/tessdata/configs/tsv
Normal file
1
backend/configs/tessdata/configs/tsv
Normal file
@ -0,0 +1 @@
|
|||||||
|
tessedit_create_tsv 1
|
||||||
3
backend/configs/tessdata/configs/txt
Normal file
3
backend/configs/tessdata/configs/txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# This config file should be used with other config files which create renderers.
|
||||||
|
# usage example: tesseract eurotext.tif eurotext txt hocr pdf
|
||||||
|
tessedit_create_txt 1
|
||||||
2
backend/configs/tessdata/configs/unlv
Normal file
2
backend/configs/tessdata/configs/unlv
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
tessedit_write_unlv 1
|
||||||
|
unlv_tilde_crunching T
|
||||||
1
backend/configs/tessdata/configs/wordstrbox
Normal file
1
backend/configs/tessdata/configs/wordstrbox
Normal file
@ -0,0 +1 @@
|
|||||||
|
tessedit_create_wordstrbox 1
|
||||||
BIN
backend/configs/tessdata/deu.traineddata
Normal file
BIN
backend/configs/tessdata/deu.traineddata
Normal file
Binary file not shown.
BIN
backend/configs/tessdata/deu.traineddata.old
Normal file
BIN
backend/configs/tessdata/deu.traineddata.old
Normal file
Binary file not shown.
BIN
backend/configs/tessdata/eng.traineddata
Normal file
BIN
backend/configs/tessdata/eng.traineddata
Normal file
Binary file not shown.
2
backend/configs/tessdata/eng.user-patterns
Normal file
2
backend/configs/tessdata/eng.user-patterns
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
1-\d\d\d-GOOG-411
|
||||||
|
www.\n\\\*.com
|
||||||
5
backend/configs/tessdata/eng.user-words
Normal file
5
backend/configs/tessdata/eng.user-words
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
the
|
||||||
|
quick
|
||||||
|
brown
|
||||||
|
fox
|
||||||
|
jumped
|
||||||
BIN
backend/configs/tessdata/jaxb-api-2.3.1.jar
Normal file
BIN
backend/configs/tessdata/jaxb-api-2.3.1.jar
Normal file
Binary file not shown.
BIN
backend/configs/tessdata/osd.traineddata
Normal file
BIN
backend/configs/tessdata/osd.traineddata
Normal file
Binary file not shown.
BIN
backend/configs/tessdata/pdf.ttf
Normal file
BIN
backend/configs/tessdata/pdf.ttf
Normal file
Binary file not shown.
BIN
backend/configs/tessdata/piccolo2d-core-3.0.1.jar
Normal file
BIN
backend/configs/tessdata/piccolo2d-core-3.0.1.jar
Normal file
Binary file not shown.
BIN
backend/configs/tessdata/piccolo2d-extras-3.0.1.jar
Normal file
BIN
backend/configs/tessdata/piccolo2d-extras-3.0.1.jar
Normal file
Binary file not shown.
1
backend/configs/tessdata/tessconfigs/batch
Normal file
1
backend/configs/tessdata/tessconfigs/batch
Normal file
@ -0,0 +1 @@
|
|||||||
|
# No content needed as all defaults are correct.
|
||||||
2
backend/configs/tessdata/tessconfigs/batch.nochop
Normal file
2
backend/configs/tessdata/tessconfigs/batch.nochop
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
chop_enable 0
|
||||||
|
wordrec_enable_assoc 0
|
||||||
7
backend/configs/tessdata/tessconfigs/matdemo
Normal file
7
backend/configs/tessdata/tessconfigs/matdemo
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#################################################
|
||||||
|
# Adaptive Matcher Using PreAdapted Templates
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
classify_enable_adaptive_debugger 1
|
||||||
|
matcher_debug_flags 6
|
||||||
|
matcher_debug_level 1
|
||||||
12
backend/configs/tessdata/tessconfigs/msdemo
Normal file
12
backend/configs/tessdata/tessconfigs/msdemo
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#################################################
|
||||||
|
# Adaptive Matcher Using PreAdapted Templates
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
classify_enable_adaptive_debugger 1
|
||||||
|
matcher_debug_flags 6
|
||||||
|
matcher_debug_level 1
|
||||||
|
|
||||||
|
wordrec_display_splits 0
|
||||||
|
wordrec_display_all_blobs 1
|
||||||
|
wordrec_display_segmentations 2
|
||||||
|
classify_debug_level 1
|
||||||
1
backend/configs/tessdata/tessconfigs/nobatch
Normal file
1
backend/configs/tessdata/tessconfigs/nobatch
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
9
backend/configs/tessdata/tessconfigs/segdemo
Normal file
9
backend/configs/tessdata/tessconfigs/segdemo
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#################################################
|
||||||
|
# Adaptive Matcher Using PreAdapted Templates
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
wordrec_display_splits 0
|
||||||
|
wordrec_display_all_blobs 1
|
||||||
|
wordrec_display_segmentations 2
|
||||||
|
classify_debug_level 1
|
||||||
|
stopper_debug_level 1
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
"""Add table for logintoken de-/activation dates
|
||||||
|
|
||||||
|
Revision ID: 015f4256bb4c
|
||||||
|
Revises: 9a8c73f0ab11
|
||||||
|
Create Date: 2023-11-19 20:52:03.377745
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '015f4256bb4c'
|
||||||
|
down_revision = '9a8c73f0ab11'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('login_token_dates',
|
||||||
|
sa.Column('token', sa.String(length=15), nullable=False),
|
||||||
|
sa.Column('activation_date', sa.Date(), server_default=sa.text('now()'), nullable=False),
|
||||||
|
sa.Column('deactivation_date', sa.Date(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['token'], ['login_token.token'], ),
|
||||||
|
sa.PrimaryKeyConstraint('token', 'activation_date')
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('login_token_dates')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
"""receipt id serial
|
||||||
|
|
||||||
|
Revision ID: 0fa2ef37e440
|
||||||
|
Revises: f6f97ed9c053
|
||||||
|
Create Date: 2023-07-25 21:26:25.353435
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '0fa2ef37e440'
|
||||||
|
down_revision = 'f6f97ed9c053'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.execute("CREATE SEQUENCE receipt_id_seq;")
|
||||||
|
|
||||||
|
with op.batch_alter_table('receipt', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('id',
|
||||||
|
existing_type=sa.BIGINT(),
|
||||||
|
type_=sa.Integer(),
|
||||||
|
existing_nullable=False,
|
||||||
|
server_default=sa.sql.func.next_value(sa.Sequence('receipt_id_seq')))
|
||||||
|
|
||||||
|
with op.batch_alter_table('receipt_item', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('receipt',
|
||||||
|
existing_type=sa.BIGINT(),
|
||||||
|
type_=sa.Integer(),
|
||||||
|
existing_nullable=False)
|
||||||
|
|
||||||
|
op.execute("ALTER SEQUENCE receipt_id_seq OWNED BY 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.Integer(),
|
||||||
|
type_=sa.BIGINT(),
|
||||||
|
existing_nullable=False)
|
||||||
|
|
||||||
|
with op.batch_alter_table('receipt', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('id',
|
||||||
|
existing_type=sa.Integer(),
|
||||||
|
type_=sa.BIGINT(),
|
||||||
|
existing_nullable=False)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
"""new table for bought entries with unknown items 2
|
||||||
|
|
||||||
|
Revision ID: 2a64d3b9235a
|
||||||
|
Revises: 015f4256bb4c
|
||||||
|
Create Date: 2024-06-02 13:19:59.901053
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '2a64d3b9235a'
|
||||||
|
down_revision = '015f4256bb4c'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('bought_with_unknown_item',
|
||||||
|
sa.Column('token', sa.String(length=15), nullable=False),
|
||||||
|
sa.Column('item', sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column('date', sa.Date(), nullable=False),
|
||||||
|
sa.Column('amount', sa.SmallInteger(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['token'], ['login_token.token'], ),
|
||||||
|
sa.PrimaryKeyConstraint('token', 'item', 'date')
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('bought_with_unknown_item')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -8,8 +8,8 @@ Create Date: 2022-02-20 16:33:01.900378
|
|||||||
from alembic import op
|
from alembic import op
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from app import db
|
from src import db
|
||||||
from app.utils.view_utils import selectable_price_per_amount_view, selectable_bought_with_prices_view
|
from src.utils.view_utils import selectable_price_per_amount_view, selectable_bought_with_prices_view
|
||||||
from sqlalchemy_utils import create_view
|
from sqlalchemy_utils import create_view
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
@ -20,6 +20,7 @@ depends_on = None
|
|||||||
|
|
||||||
|
|
||||||
def upgrade():
|
def upgrade():
|
||||||
|
op.rename_table("item_receipt", "receipt_item")
|
||||||
metadata = sa.MetaData()
|
metadata = sa.MetaData()
|
||||||
create_view('price_per_amount',
|
create_view('price_per_amount',
|
||||||
selectable_price_per_amount_view(),
|
selectable_price_per_amount_view(),
|
||||||
@ -36,3 +37,4 @@ def downgrade():
|
|||||||
with db.engine.connect() as con:
|
with db.engine.connect() as con:
|
||||||
con.execute("DROP VIEW bought_with_prices;")
|
con.execute("DROP VIEW bought_with_prices;")
|
||||||
con.execute("DROP VIEW price_per_amount;")
|
con.execute("DROP VIEW price_per_amount;")
|
||||||
|
op.rename_table("receipt_item", "item_receipt")
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
"""Remove accepted from receiptitem
|
||||||
|
|
||||||
|
Revision ID: 36f532800705
|
||||||
|
Revises: cdbe3f5e3b30
|
||||||
|
Create Date: 2023-11-11 10:45:44.652161
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '36f532800705'
|
||||||
|
down_revision = 'cdbe3f5e3b30'
|
||||||
|
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.drop_column('accepted')
|
||||||
|
|
||||||
|
# ### 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.add_column(sa.Column('accepted', sa.BOOLEAN(), autoincrement=False, nullable=False))
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
"""Delete unnecessary columns
|
||||||
|
|
||||||
|
Revision ID: 4fec22c35530
|
||||||
|
Revises: 610854a6e2a0
|
||||||
|
Create Date: 2023-05-28 08:10:27.689070
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '4fec22c35530'
|
||||||
|
down_revision = '610854a6e2a0'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('bought', schema=None) as batch_op:
|
||||||
|
batch_op.drop_column('registered')
|
||||||
|
|
||||||
|
with op.batch_alter_table('login_token', schema=None) as batch_op:
|
||||||
|
batch_op.drop_column('paid')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('login_token', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('paid', sa.BIGINT(), server_default=sa.text("'0'::bigint"), autoincrement=False, nullable=False))
|
||||||
|
|
||||||
|
with op.batch_alter_table('bought', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('registered', sa.BOOLEAN(), server_default=sa.text('false'), autoincrement=False, nullable=False))
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
"""establishment candidate table
|
||||||
|
|
||||||
|
Revision ID: 610854a6e2a0
|
||||||
|
Revises: 2be4d1ae5493
|
||||||
|
Create Date: 2023-03-18 13:36:12.953900
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '610854a6e2a0'
|
||||||
|
down_revision = '2be4d1ae5493'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('establishment_candidate',
|
||||||
|
sa.Column('user', sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column('establishment', sa.BigInteger(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['establishment'], ['establishment.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['user'], ['user.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('user', 'establishment')
|
||||||
|
)
|
||||||
|
op.create_table('payment',
|
||||||
|
sa.Column('id', sa.BigInteger(), nullable=False, autoincrement=True),
|
||||||
|
sa.Column('token', sa.String(length=15), nullable=False),
|
||||||
|
sa.Column('date', sa.Date(), server_default=sa.text('now()'), nullable=False),
|
||||||
|
sa.Column('amount', sa.BigInteger(), server_default='0', nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['token'], ['login_token.token'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id', 'token')
|
||||||
|
)
|
||||||
|
with op.batch_alter_table('login_token', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('token',
|
||||||
|
existing_type=sa.VARCHAR(length=15),
|
||||||
|
nullable=False)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('login_token', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('token',
|
||||||
|
existing_type=sa.VARCHAR(length=15),
|
||||||
|
nullable=True)
|
||||||
|
|
||||||
|
op.drop_table('payment')
|
||||||
|
op.drop_table('establishment_candidate')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
"""raise password char length
|
||||||
|
|
||||||
|
Revision ID: 782a2409df41
|
||||||
|
Revises: 926395732c3e
|
||||||
|
Create Date: 2025-06-03 21:01:23.169897
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '782a2409df41'
|
||||||
|
down_revision = '926395732c3e'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('password_hash',
|
||||||
|
existing_type=sa.VARCHAR(length=128),
|
||||||
|
type_=sa.String(length=255),
|
||||||
|
existing_nullable=False)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('password_hash',
|
||||||
|
existing_type=sa.String(length=255),
|
||||||
|
type_=sa.VARCHAR(length=128),
|
||||||
|
existing_nullable=False)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
"""raise bonid digits
|
||||||
|
|
||||||
|
Revision ID: 926395732c3e
|
||||||
|
Revises: 2a64d3b9235a
|
||||||
|
Create Date: 2024-08-24 10:33:39.109944
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '926395732c3e'
|
||||||
|
down_revision = '2a64d3b9235a'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('receipt', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('bonid',
|
||||||
|
existing_type=sa.NUMERIC(precision=24, scale=0),
|
||||||
|
type_=sa.Numeric(precision=28, scale=0),
|
||||||
|
existing_nullable=True)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('receipt', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('bonid',
|
||||||
|
existing_type=sa.Numeric(precision=28, scale=0),
|
||||||
|
type_=sa.NUMERIC(precision=24, scale=0),
|
||||||
|
existing_nullable=True)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
"""add receiptitem names
|
||||||
|
|
||||||
|
Revision ID: 9a8c73f0ab11
|
||||||
|
Revises: 36f532800705
|
||||||
|
Create Date: 2023-11-18 23:38:56.865780
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '9a8c73f0ab11'
|
||||||
|
down_revision = '36f532800705'
|
||||||
|
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('name', sa.String(), nullable=True))
|
||||||
|
op.execute("UPDATE receipt_item SET name='Unknown' WHERE name IS NULL;")
|
||||||
|
with op.batch_alter_table('receipt_item', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('name', nullable=False)
|
||||||
|
|
||||||
|
# ### 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.drop_column('name')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
"""Remove item.receiptitem relationship
|
||||||
|
|
||||||
|
Revision ID: cdbe3f5e3b30
|
||||||
|
Revises: 0fa2ef37e440
|
||||||
|
Create Date: 2023-09-19 19:02:23.003034
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'cdbe3f5e3b30'
|
||||||
|
down_revision = '0fa2ef37e440'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('receipt', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('id',
|
||||||
|
existing_type=sa.INTEGER(),
|
||||||
|
type_=sa.BigInteger(),
|
||||||
|
existing_nullable=False,
|
||||||
|
autoincrement=True)
|
||||||
|
|
||||||
|
with op.batch_alter_table('receipt_item', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('price', sa.SmallInteger(), nullable=False))
|
||||||
|
batch_op.alter_column('receipt',
|
||||||
|
existing_type=sa.INTEGER(),
|
||||||
|
type_=sa.BigInteger(),
|
||||||
|
existing_nullable=False)
|
||||||
|
batch_op.alter_column('item',
|
||||||
|
existing_type=sa.BIGINT(),
|
||||||
|
type_=sa.SmallInteger(),
|
||||||
|
existing_nullable=False)
|
||||||
|
batch_op.drop_constraint('item_receipt_item_fkey', type_='foreignkey')
|
||||||
|
|
||||||
|
# ### 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.create_foreign_key('item_receipt_item_fkey', 'item', ['item'], ['id'])
|
||||||
|
batch_op.alter_column('item',
|
||||||
|
existing_type=sa.SmallInteger(),
|
||||||
|
type_=sa.BIGINT(),
|
||||||
|
existing_nullable=False)
|
||||||
|
batch_op.alter_column('receipt',
|
||||||
|
existing_type=sa.BigInteger(),
|
||||||
|
type_=sa.INTEGER(),
|
||||||
|
existing_nullable=False)
|
||||||
|
batch_op.drop_column('price')
|
||||||
|
|
||||||
|
with op.batch_alter_table('receipt', schema=None) as batch_op:
|
||||||
|
batch_op.alter_column('id',
|
||||||
|
existing_type=sa.BigInteger(),
|
||||||
|
type_=sa.INTEGER(),
|
||||||
|
existing_nullable=False,
|
||||||
|
autoincrement=True)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -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 ###
|
||||||
18
backend/models/__init__.py
Normal file
18
backend/models/__init__.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from .payment import Payment
|
||||||
|
from .receipt_item import ReceiptItem
|
||||||
|
from .receipt import Receipt
|
||||||
|
from .login_token import LoginToken
|
||||||
|
from .bought import Bought
|
||||||
|
from .bought_with_unknown_item import BoughtWithUnknownItem
|
||||||
|
from .establishment import Establishment
|
||||||
|
from .establishment_candidate import EstablishmentCandidate
|
||||||
|
from .user import User
|
||||||
|
from .amount_change import AmountChange
|
||||||
|
from .price_change import PriceChange
|
||||||
|
from .category import Category
|
||||||
|
from .item import Item
|
||||||
|
from .brand import Brand
|
||||||
|
from .item_category import item_category
|
||||||
|
from .login_token_dates import LoginTokenDates
|
||||||
|
|
||||||
|
from .schemas import *
|
||||||
13
backend/models/amount_change.py
Normal file
13
backend/models/amount_change.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from datetime import date
|
||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class AmountChange(db.Model):
|
||||||
|
item = db.Column(db.ForeignKey('item.id'), primary_key=True,
|
||||||
|
server_onupdate=db.FetchedValue())
|
||||||
|
date = db.Column(db.Date, primary_key=True,
|
||||||
|
server_default=str(date(2021, 12, 1)))
|
||||||
|
amount = db.Column(db.SmallInteger, nullable=False, server_default=str(1))
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Amount_Change {self.item} ({self.date})>"
|
||||||
13
backend/models/bought.py
Normal file
13
backend/models/bought.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class Bought(db.Model):
|
||||||
|
token = db.Column(db.ForeignKey('login_token.token'),
|
||||||
|
primary_key=True, server_onupdate=db.FetchedValue())
|
||||||
|
item = db.Column(db.ForeignKey('item.id'), primary_key=True,
|
||||||
|
server_onupdate=db.FetchedValue())
|
||||||
|
date = db.Column(db.Date, primary_key=True)
|
||||||
|
amount = db.Column(db.SmallInteger, nullable=False)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Bought Object>"
|
||||||
14
backend/models/bought_with_unknown_item.py
Normal file
14
backend/models/bought_with_unknown_item.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from src import db
|
||||||
|
from .bought import Bought
|
||||||
|
|
||||||
|
|
||||||
|
class BoughtWithUnknownItem(db.Model):
|
||||||
|
token = db.Column(db.ForeignKey('login_token.token'),
|
||||||
|
primary_key=True, server_onupdate=db.FetchedValue())
|
||||||
|
item = db.Column(db.BigInteger, primary_key=True,
|
||||||
|
server_onupdate=db.FetchedValue())
|
||||||
|
date = db.Column(db.Date, primary_key=True)
|
||||||
|
amount = db.Column(db.SmallInteger, nullable=False)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Bought Object>"
|
||||||
14
backend/models/brand.py
Normal file
14
backend/models/brand.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class Brand(db.Model):
|
||||||
|
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')
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Brand {self.id} ({self.name})>"
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"{self.name}"
|
||||||
13
backend/models/category.py
Normal file
13
backend/models/category.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from src import db
|
||||||
|
from .item_category import item_category
|
||||||
|
|
||||||
|
|
||||||
|
class Category(db.Model):
|
||||||
|
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,
|
||||||
|
lazy="dynamic", back_populates="Category")
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Category {self.id} ({self.name})>"
|
||||||
17
backend/models/establishment.py
Normal file
17
backend/models/establishment.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class Establishment(db.Model):
|
||||||
|
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)
|
||||||
|
|
||||||
|
LoginToken = db.relationship(
|
||||||
|
"LoginToken", backref='Establishment', lazy='dynamic')
|
||||||
|
Bought = db.relationship("Bought", secondary="login_token",
|
||||||
|
lazy='dynamic', overlaps="Establishment,LoginToken,Bought")
|
||||||
|
EstablishmentCandidate = db.relationship(
|
||||||
|
"EstablishmentCandidate", backref='Establishment', lazy='dynamic')
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Establishment {self.id} ({self.name})>"
|
||||||
10
backend/models/establishment_candidate.py
Normal file
10
backend/models/establishment_candidate.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class EstablishmentCandidate(db.Model):
|
||||||
|
user = db.Column(db.ForeignKey('user.id'), primary_key=True)
|
||||||
|
establishment = db.Column(db.ForeignKey(
|
||||||
|
'establishment.id'), primary_key=True)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<EstablishmentCandidate {self.user} ({self.establishment})>"
|
||||||
24
backend/models/item.py
Normal file
24
backend/models/item.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from src import db, ma
|
||||||
|
from .item_category import item_category
|
||||||
|
|
||||||
|
|
||||||
|
class Item(db.Model):
|
||||||
|
id = db.Column(db.BigInteger, primary_key=True, autoincrement=False)
|
||||||
|
name = db.Column(db.String(64), nullable=False)
|
||||||
|
brand = db.Column(db.ForeignKey('brand.id'), nullable=False,
|
||||||
|
server_onupdate=db.FetchedValue())
|
||||||
|
description = db.Column(db.Text, nullable=False)
|
||||||
|
|
||||||
|
AmountChange = db.relationship(
|
||||||
|
"AmountChange", backref='Item', lazy='dynamic')
|
||||||
|
Bought = db.relationship("Bought", backref='Item', lazy='dynamic')
|
||||||
|
Category = db.relationship(
|
||||||
|
"Category", secondary=item_category, lazy="dynamic", back_populates="Item")
|
||||||
|
PriceChange = db.relationship(
|
||||||
|
"PriceChange", backref='Item', lazy='dynamic')
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Item {self.id} ({self.name})>"
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"({self.id}) {self.description}"
|
||||||
6
backend/models/item_category.py
Normal file
6
backend/models/item_category.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
item_category = db.Table("item_category",
|
||||||
|
db.Column("item", db.ForeignKey("item.id"), primary_key=True, server_onupdate=db.FetchedValue()),
|
||||||
|
db.Column("category", db.ForeignKey("category.id"), primary_key=True, server_onupdate=db.FetchedValue())
|
||||||
|
)
|
||||||
16
backend/models/login_token.py
Normal file
16
backend/models/login_token.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class LoginToken(db.Model):
|
||||||
|
user = db.Column(db.ForeignKey('user.id'), primary_key=True,
|
||||||
|
server_onupdate=db.FetchedValue())
|
||||||
|
establishment = db.Column(db.ForeignKey(
|
||||||
|
'establishment.id'), primary_key=True, server_onupdate=db.FetchedValue())
|
||||||
|
token = db.Column(db.String(15), nullable=False, unique=True)
|
||||||
|
|
||||||
|
LoginTokenDates = db.relationship("LoginTokenDates", backref='LoginToken', lazy='dynamic')
|
||||||
|
Payment = db.relationship("Payment", backref='LoginToken', lazy='dynamic')
|
||||||
|
Receipt = db.relationship("Receipt", backref='LoginToken', lazy='dynamic')
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<LoginToken {self.token}>"
|
||||||
13
backend/models/login_token_dates.py
Normal file
13
backend/models/login_token_dates.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
class LoginTokenDates(db.Model):
|
||||||
|
token = db.Column(db.ForeignKey('login_token.token'),
|
||||||
|
nullable = False, primary_key=True,
|
||||||
|
server_onupdate=db.FetchedValue())
|
||||||
|
activation_date = db.Column(db.Date,
|
||||||
|
nullable=False, primary_key=True,
|
||||||
|
server_default=db.func.now())
|
||||||
|
deactivation_date = db.Column(db.Date, nullable=True)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<LoginTokenDates {self.token, self.activation_date, self.deactivation_date}>"
|
||||||
12
backend/models/payment.py
Normal file
12
backend/models/payment.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class Payment(db.Model):
|
||||||
|
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
token = db.Column(db.ForeignKey('login_token.token'),
|
||||||
|
server_onupdate=db.FetchedValue(), nullable=False)
|
||||||
|
date = db.Column(db.Date, nullable=False, server_default=db.func.now())
|
||||||
|
amount = db.Column(db.BigInteger, nullable=False, server_default=str(0))
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Payment {self.id}>"
|
||||||
13
backend/models/price_change.py
Normal file
13
backend/models/price_change.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from datetime import date
|
||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class PriceChange(db.Model):
|
||||||
|
item = db.Column(db.ForeignKey('item.id'), primary_key=True,
|
||||||
|
server_onupdate=db.FetchedValue())
|
||||||
|
date = db.Column(db.Date, primary_key=True,
|
||||||
|
server_default=str(date(2021, 12, 1)))
|
||||||
|
price = db.Column(db.SmallInteger, nullable=False)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Price_Change {self.item} ({self.date})>"
|
||||||
17
backend/models/receipt.py
Normal file
17
backend/models/receipt.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class Receipt(db.Model):
|
||||||
|
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
date = db.Column(db.Date, nullable=False)
|
||||||
|
bonid = db.Column(db.Numeric(precision=28, scale=0), unique=True)
|
||||||
|
from_user = db.Column(db.ForeignKey("login_token.token"),
|
||||||
|
server_onupdate=db.FetchedValue())
|
||||||
|
registered = db.Column(db.Boolean, nullable=False,
|
||||||
|
server_default=str(False))
|
||||||
|
|
||||||
|
ReceiptItem = db.relationship(
|
||||||
|
"ReceiptItem", backref='Receipt', lazy='dynamic')
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Receipt {self.id}>"
|
||||||
13
backend/models/receipt_item.py
Normal file
13
backend/models/receipt_item.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from src import db
|
||||||
|
|
||||||
|
|
||||||
|
class ReceiptItem(db.Model):
|
||||||
|
receipt = db.Column(db.ForeignKey("receipt.id"),
|
||||||
|
primary_key=True, server_onupdate=db.FetchedValue())
|
||||||
|
item = db.Column(db.SmallInteger, primary_key=True, nullable=False)
|
||||||
|
name = db.Column(db.String, nullable=False)
|
||||||
|
amount = db.Column(db.SmallInteger, nullable=False, default=str(1))
|
||||||
|
price = db.Column(db.SmallInteger, nullable=False)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<ReceiptItem {self.receipt}: {self.item}>"
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user