Compare commits

..

No commits in common. "main" and "v0.12.1" have entirely different histories.

228 changed files with 2048 additions and 6008 deletions

View File

@ -4,47 +4,19 @@ on:
tags: tags:
- '*' - '*'
jobs: jobs:
release: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: https://gitea.com/actions/checkout@master - uses: actions/checkout@master
- name: Zip Artifacts - name: Archive Server
uses: https://github.com/thedoctor0/zip-release@master uses: 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: https://gitea.com/actions/gitea-release-action@v1 uses: ncipollo/release-action@v1
with: with:
server_url: https://gitea.wpgcommunity.net allowUpdates: true
files: 'server.zip' artifacts: "server.zip"
docker: token: ${{ secrets.GITHUB_TOKEN }}
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 }}

10
.gitignore vendored
View File

@ -339,9 +339,7 @@ pip-selfcheck.json
# Misc # Misc
config.yaml config.yaml
scans.json scans.json
test_*.*
test.* test.*
tests*
*.db *.db
.vscode .vscode
*.tar *.tar
@ -349,10 +347,4 @@ tests*
.env* .env*
.flaskenv* .flaskenv*
!.env.project !.env.project
!.env.vault !.env.vault
*.ps1
*.pdf
*.backup
Dockerfile.*
docker-compose.*
*debug.py

View File

@ -1,25 +1,23 @@
FROM python@sha256:c66cf219ac0083a9af2ff90e16530f16cd503c59eb7909feb3b8f3524dc1a87e FROM python@sha256:075fe10ae13ea0f081540bead850eeb7b6c71d07ed4766d75f8529abd0101c44
# python:3.12.2-slim-bullseye (amd64) # python:3.10.10-slim-bullseye
RUN useradd costhive RUN useradd costhive
WORKDIR /home/costhive WORKDIR /home/costhive
RUN apt update && apt -y upgrade; \ RUN apt update && apt -y upgrade
apt install -y libpq-dev gcc g++ swig make cmake m4; \ RUN apt install -y libpq-dev gcc g++ swig make
rm -rf /var/lib/apt/lists
COPY boot.sh backend/requirements.txt ./ COPY boot.sh requirements.txt ./
RUN python -m venv venv; \ RUN python -m venv venv
venv/bin/pip install --upgrade pip; \ RUN venv/bin/pip install -r requirements.txt
venv/bin/pip install wheel gunicorn; \ RUN venv/bin/pip install gunicorn
venv/bin/pip install -r requirements.txt RUN chmod +x boot.sh
COPY backend backend COPY backend backend
ENV FLASK_APP=run.py ENV FLASK_APP run.py
RUN chmod +x boot.sh; \ RUN chown -R costhive:costhive ./
chown -R costhive:costhive .
USER costhive USER costhive

12
Pipfile Normal file
View File

@ -0,0 +1,12 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
flask-cors = "*"
[dev-packages]
[requires]
python_version = "3.10"

141
Pipfile.lock generated Normal file
View File

@ -0,0 +1,141 @@
{
"_meta": {
"hash": {
"sha256": "2f46680952b8ccfaf093f8ef1315053afb3d2e15fc244d50f313d0961890dfc3"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.10"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"click": {
"hashes": [
"sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
"sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
],
"markers": "python_version >= '3.7'",
"version": "==8.1.3"
},
"colorama": {
"hashes": [
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
],
"markers": "platform_system == 'Windows'",
"version": "==0.4.6"
},
"flask": {
"hashes": [
"sha256:7eb373984bf1c770023fce9db164ed0c3353cd0b53f130f4693da0ca756a2e6d",
"sha256:c0bec9477df1cb867e5a67c9e1ab758de9cb4a3e52dd70681f59fa40a62b3f2d"
],
"markers": "python_version >= '3.7'",
"version": "==2.2.3"
},
"flask-cors": {
"hashes": [
"sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438",
"sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"
],
"index": "pypi",
"version": "==3.0.10"
},
"itsdangerous": {
"hashes": [
"sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
"sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"
],
"markers": "python_version >= '3.7'",
"version": "==2.1.2"
},
"jinja2": {
"hashes": [
"sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
"sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
],
"markers": "python_version >= '3.7'",
"version": "==3.1.2"
},
"markupsafe": {
"hashes": [
"sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed",
"sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc",
"sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2",
"sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460",
"sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7",
"sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0",
"sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1",
"sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa",
"sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03",
"sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323",
"sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65",
"sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013",
"sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036",
"sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f",
"sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4",
"sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419",
"sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2",
"sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619",
"sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a",
"sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a",
"sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd",
"sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7",
"sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666",
"sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65",
"sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859",
"sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625",
"sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff",
"sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156",
"sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd",
"sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba",
"sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f",
"sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1",
"sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094",
"sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a",
"sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513",
"sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed",
"sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d",
"sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3",
"sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147",
"sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c",
"sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603",
"sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601",
"sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a",
"sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1",
"sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d",
"sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3",
"sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54",
"sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2",
"sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6",
"sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"
],
"markers": "python_version >= '3.7'",
"version": "==2.1.2"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==1.16.0"
},
"werkzeug": {
"hashes": [
"sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe",
"sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612"
],
"markers": "python_version >= '3.7'",
"version": "==2.2.3"
}
},
"develop": {}
}

View File

@ -7,25 +7,20 @@ name = "pypi"
email-validator = "*" email-validator = "*"
flask = "*" flask = "*"
flask-bootstrap = "*" flask-bootstrap = "*"
flask-cors = "*"
flask-login = "*" flask-login = "*"
flask-mail = "*" flask-mail = "*"
flask-marshmallow = "*"
flask-migrate = "*" flask-migrate = "*"
flask-sqlalchemy = "*" flask-sqlalchemy = "*"
flask-wtf = "*" flask-wtf = "*"
marshmallow-sqlalchemy = "*"
psycopg2-binary = "*" psycopg2-binary = "*"
pyjwt = "*" pyjwt = "*"
python-dotenv = "*" python-dotenv = "*"
pymupdf = "*" pymupdf = "*"
requests = "*"
sqlalchemy-utils = "*" sqlalchemy-utils = "*"
wtforms-sqlalchemy = "*" marshmallow = "*"
pytest = "*"
[dev-packages] [dev-packages]
[requires] [requires]
python_version = "3.11" python_version = "3.10"
python_full_version = "3.11.4" python_full_version = "3.10.10"

842
backend/Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@ from dotenv import load_dotenv
basedir = os.path.abspath(os.path.dirname(__file__)) basedir = os.path.abspath(os.path.dirname(__file__))
load_dotenv(os.path.join(basedir, '.env')) load_dotenv(os.path.join(basedir, '.env'))
os.environ["TESSDATA_PREFIX"] = os.path.join(basedir, 'tessdata')
class Config(object): class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or "s0m37h!n6-obfu5c471ng" SECRET_KEY = os.environ.get('SECRET_KEY') or "s0m37h!n6-obfu5c471ng"
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL', '').replace( SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL', '').replace(
@ -19,5 +18,4 @@ class Config(object):
MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
ADMINS = ['postmaster@wpgcommunity.net'] ADMINS = ['postmaster@wpgcommunity.net']
POSTS_PER_PAGE = 15 POSTS_PER_PAGE = 10
RECEIPT_FOLDER = f"{basedir}/../PDFReceipts"

View File

@ -1 +0,0 @@
tessedit_create_alto 1

View File

@ -1,7 +0,0 @@
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

View File

@ -1 +0,0 @@
tessedit_zero_rejection T

View File

@ -1,5 +0,0 @@
load_bigram_dawg True
tessedit_enable_bigram_correction True
tessedit_bigram_debug 3
save_raw_choices True
save_alt_choices True

View File

@ -1,12 +0,0 @@
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

View File

@ -1,13 +0,0 @@
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

View File

@ -1 +0,0 @@
tessedit_char_whitelist 0123456789-.

View File

@ -1 +0,0 @@
tessedit_write_images T

View File

@ -1,2 +0,0 @@
tessedit_create_hocr 1
hocr_font_info 0

View File

@ -1,2 +0,0 @@
interactive_display_mode T
tessedit_display_outwords T

View File

@ -1,4 +0,0 @@
textord_skewsmooth_offset 8
textord_skewsmooth_offset2 8
textord_merge_desc 0.5
textord_no_rejects 1

View File

@ -1,2 +0,0 @@
tessedit_resegment_from_line_boxes 1
tessedit_make_boxes_from_boxes 1

View File

@ -1 +0,0 @@
debug_file tesseract.log

View File

@ -1,11 +0,0 @@
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

View File

@ -1 +0,0 @@
tessedit_create_lstmbox 1

View File

@ -1,4 +0,0 @@
stopper_debug_level 1
classify_debug_level 1
segsearch_debug_level 1
language_model_debug_level 3

View File

@ -1 +0,0 @@
tessedit_create_boxfile 1

View File

@ -1 +0,0 @@
tessedit_create_pdf 1

View File

@ -1 +0,0 @@
debug_file /dev/null

View File

@ -1,2 +0,0 @@
tessedit_resegment_from_boxes 1
tessedit_make_boxes_from_boxes 1

View File

@ -1,12 +0,0 @@
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

View File

@ -1 +0,0 @@
tessedit_create_tsv 1

View File

@ -1,3 +0,0 @@
# 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

View File

@ -1,2 +0,0 @@
tessedit_write_unlv 1
unlv_tilde_crunching T

View File

@ -1 +0,0 @@
tessedit_create_wordstrbox 1

View File

@ -1,2 +0,0 @@
1-\d\d\d-GOOG-411
www.\n\\\*.com

View File

@ -1,5 +0,0 @@
the
quick
brown
fox
jumped

Binary file not shown.

View File

@ -1 +0,0 @@
# No content needed as all defaults are correct.

View File

@ -1,2 +0,0 @@
chop_enable 0
wordrec_enable_assoc 0

View File

@ -1,7 +0,0 @@
#################################################
# Adaptive Matcher Using PreAdapted Templates
#################################################
classify_enable_adaptive_debugger 1
matcher_debug_flags 6
matcher_debug_level 1

View File

@ -1,12 +0,0 @@
#################################################
# 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

View File

@ -1,9 +0,0 @@
#################################################
# 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

View File

@ -1,34 +0,0 @@
"""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 ###

View File

@ -1,54 +0,0 @@
"""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 ###

View File

@ -1,35 +0,0 @@
"""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 ###

View File

@ -1,32 +0,0 @@
"""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 ###

View File

@ -1,38 +0,0 @@
"""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 ###

View File

@ -26,7 +26,7 @@ def upgrade():
sa.PrimaryKeyConstraint('user', 'establishment') sa.PrimaryKeyConstraint('user', 'establishment')
) )
op.create_table('payment', op.create_table('payment',
sa.Column('id', sa.BigInteger(), nullable=False, autoincrement=True), sa.Column('id', sa.BigInteger(), nullable=False),
sa.Column('token', sa.String(length=15), nullable=False), sa.Column('token', sa.String(length=15), nullable=False),
sa.Column('date', sa.Date(), server_default=sa.text('now()'), 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.Column('amount', sa.BigInteger(), server_default='0', nullable=False),

View File

@ -1,38 +0,0 @@
"""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 ###

View File

@ -1,38 +0,0 @@
"""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 ###

View File

@ -1,35 +0,0 @@
"""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 ###

View File

@ -1,64 +0,0 @@
"""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 ###

View File

@ -1,64 +0,0 @@
"""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 ###

View File

@ -1,18 +0,0 @@
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 *

View File

@ -1,13 +0,0 @@
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>"

View File

@ -1,14 +0,0 @@
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>"

View File

@ -1,13 +0,0 @@
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})>"

View File

@ -1,17 +0,0 @@
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})>"

View File

@ -1,24 +0,0 @@
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}"

View File

@ -1,13 +0,0 @@
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}>"

View File

@ -1,12 +0,0 @@
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}>"

View File

@ -1,13 +0,0 @@
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})>"

View File

@ -1,17 +0,0 @@
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}>"

View File

@ -1,13 +0,0 @@
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}>"

View File

@ -1,13 +0,0 @@
from .brand import BrandSchema
from .item import ItemSchema
from .category import CategorySchema
from .price_change import PriceChangeSchema
from .amount_change import AmountChangeSchema
from .user import UserSchema
from .establishment import EstablishmentSchema
from .establishment_candidate import EstablishmentCandidateSchema
from .login_token import LoginTokenSchema
from .bought import BoughtSchema
from .receipt import ReceiptSchema
from .receipt_item import ReceiptItemSchema
from .payment import PaymentSchema

View File

@ -1,13 +0,0 @@
from src import ma
from ..amount_change import AmountChange
from .item import ItemSchema
class AmountChangeSchema(ma.SQLAlchemySchema):
class Meta:
model = AmountChange
include_fk = True
Item = ma.Nested(ItemSchema)
date = ma.auto_field()
amount = ma.auto_field()

View File

@ -1,15 +0,0 @@
from src import ma
from ..bought import Bought
from .login_token import LoginTokenSchema
from .item import ItemSchema
class BoughtSchema(ma.SQLAlchemySchema):
class Meta:
model = Bought
include_fk = True
LoginToken = ma.Nested(LoginTokenSchema)
Item = ma.Nested(ItemSchema)
date = ma.auto_field()
amount = ma.auto_field()

View File

@ -1,10 +0,0 @@
from src import ma
from ..brand import Brand
class BrandSchema(ma.SQLAlchemySchema):
class Meta:
model = Brand
id = ma.auto_field()
name = ma.auto_field()

View File

@ -1,11 +0,0 @@
# from marshmallow import Schema, fields
from src import ma
from ..category import Category
class CategorySchema(ma.SQLAlchemySchema):
class Meta:
model = Category
id = ma.auto_field()
name = ma.auto_field()

View File

@ -1,13 +0,0 @@
from src import ma
from ..establishment import Establishment
from .user import UserSchema
class EstablishmentSchema(ma.SQLAlchemySchema):
class Meta:
model = Establishment
include_fk = True
id = ma.auto_field()
name = ma.auto_field()
User = ma.Nested(UserSchema)

View File

@ -1,13 +0,0 @@
from src import ma
from ..establishment_candidate import EstablishmentCandidate
from .establishment import EstablishmentSchema
from .user import UserSchema
class EstablishmentCandidateSchema(ma.SQLAlchemySchema):
class Meta:
model = EstablishmentCandidate
include_fk = True
User = ma.Nested(UserSchema)
Establishment = ma.Nested(EstablishmentSchema)

View File

@ -1,18 +0,0 @@
from src import ma
from ..item import Item
from .brand import BrandSchema
class ItemSchema(ma.SQLAlchemySchema):
class Meta:
model = Item
include_fk = True
id = ma.auto_field()
name = ma.auto_field()
description = ma.auto_field()
Brand = ma.Nested(BrandSchema)
PriceChange = ma.List(ma.Nested(lambda: PriceChangeSchema(exclude=("Item",))))
AmountChange = ma.List(ma.Nested(lambda: AmountChangeSchema(exclude=("Item",))))
from .price_change import PriceChangeSchema
from .amount_change import AmountChangeSchema

View File

@ -1,14 +0,0 @@
from src import ma
from ..login_token import LoginToken
from .establishment import EstablishmentSchema
from .user import UserSchema
class LoginTokenSchema(ma.SQLAlchemySchema):
class Meta:
model = LoginToken
include_fk = True
User = ma.Nested(UserSchema)
Establishment = ma.Nested(EstablishmentSchema)
token = ma.auto_field()

View File

@ -1,14 +0,0 @@
from src import ma
from ..payment import Payment
from .login_token import LoginTokenSchema
class PaymentSchema(ma.SQLAlchemySchema):
class Meta:
model = Payment
include_fk = True
id = ma.auto_field()
LoginToken = ma.Nested(LoginTokenSchema)
date = ma.auto_field()
amount = ma.auto_field()

View File

@ -1,12 +0,0 @@
from src import ma
from .item import ItemSchema
from ..price_change import PriceChange
class PriceChangeSchema(ma.SQLAlchemySchema):
class Meta:
model = PriceChange
include_fk = True
Item = ma.Nested(ItemSchema)
date = ma.auto_field()
price = ma.auto_field()

View File

@ -1,15 +0,0 @@
from src import ma
from ..receipt import Receipt
from .login_token import LoginTokenSchema
class ReceiptSchema(ma.SQLAlchemySchema):
class Meta:
model = Receipt
include_fk = True
id = ma.auto_field()
date = ma.auto_field()
bonid = ma.auto_field()
registered = ma.auto_field()
LoginToken = ma.Nested(LoginTokenSchema)

View File

@ -1,16 +0,0 @@
from src import ma
from ..receipt_item import ReceiptItem
from .item import ItemSchema
from .receipt import ReceiptSchema
class ReceiptItemSchema(ma.SQLAlchemySchema):
class Meta:
model = ReceiptItem
include_fk = True
Receipt = ma.Nested(ReceiptSchema)
item = ma.auto_field()
name = ma.auto_field()
amount = ma.auto_field()
price = ma.auto_field()

View File

@ -1,10 +0,0 @@
from src import ma
from ..user import User
class UserSchema(ma.SQLAlchemySchema):
class Meta:
model = User
id = ma.auto_field()
email = ma.auto_field()
password_hash = ma.auto_field()

View File

@ -1,44 +0,0 @@
-i https://pypi.org/simple
alembic==1.12.1; python_version >= '3.7'
blinker==1.7.0; python_version >= '3.8'
certifi==2023.7.22; python_version >= '3.6'
charset-normalizer==3.3.2; python_full_version >= '3.7.0'
click==8.1.7; python_version >= '3.7'
colorama==0.4.6; sys_platform == 'win32'
dnspython==2.4.2; python_version >= '3.8' and python_version < '4.0'
dominate==2.8.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
email-validator==2.1.0.post1
flask==3.0.0
flask-bootstrap==3.3.7.1
flask-cors==4.0.0
flask-login==0.6.3
flask-mail==0.9.1
flask-marshmallow==0.15.0
flask-migrate==4.0.5
flask-sqlalchemy==3.1.1
flask-wtf==1.2.1
greenlet==3.0.1; 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')))))
idna==3.4; python_version >= '3.5'
iniconfig==2.0.0; python_version >= '3.7'
itsdangerous==2.1.2; python_version >= '3.7'
jinja2==3.1.2; python_version >= '3.7'
mako==1.3.0; python_version >= '3.8'
markupsafe==2.1.3; python_version >= '3.7'
marshmallow==3.20.1; python_version >= '3.8'
marshmallow-sqlalchemy==0.29.0
packaging==23.2; python_version >= '3.7'
pluggy==1.3.0; python_version >= '3.8'
psycopg2-binary==2.9.9
pyjwt==2.8.0
pymupdf==1.23.6
pytest==7.4.3
python-dotenv==1.0.0
requests==2.31.0
sqlalchemy==2.0.23; python_version >= '3.7'
sqlalchemy-utils==0.41.1
typing-extensions==4.8.0; python_version >= '3.8'
urllib3==2.0.7; python_version >= '3.7'
visitor==0.1.3
werkzeug==3.0.1; python_version >= '3.8'
wtforms==3.1.1; python_version >= '3.8'
wtforms-sqlalchemy==0.3

View File

@ -1,12 +1,10 @@
from src import create_app, db from src import create_app, db
from models import * from src.models import Bought, Establishment, Item, LoginToken, Receipt, User, UserSchema
app = create_app() app = create_app()
@app.shell_context_processor @app.shell_context_processor
def make_shell_context(): def make_shell_context():
return {'db': db, 'User': User, 'Bought': Bought, "Brand": Brand, 'Item': Item, return {'db': db, 'User': User, 'Bought': Bought, 'Item': Item,
"LoginToken": LoginToken, "Establishment": Establishment, "Receipt": Receipt, "LoginToken": LoginToken, "Establishment": Establishment, "Receipt": Receipt,
"brandschema": BrandSchema(), "itemschema": ItemSchema(), "testitem": Item.query.get(4311501628485), 'UserSchema': UserSchema}
"testuser": User.query.get(1)}

View File

@ -4,7 +4,6 @@ from flask_bootstrap import Bootstrap
from flask_cors import CORS from flask_cors import CORS
from flask_login import LoginManager from flask_login import LoginManager
from flask_mail import Mail from flask_mail import Mail
from flask_marshmallow import Marshmallow
from flask_migrate import Migrate from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from logging import getLogger from logging import getLogger
@ -32,21 +31,17 @@ cors = CORS()
db = SQLAlchemy() db = SQLAlchemy()
login = LoginManager() login = LoginManager()
login.login_view = 'auth.web_login' login.login_view = 'auth.web_login'
ma = Marshmallow()
mail = Mail() mail = Mail()
migrate = Migrate(transaction_per_migration=True) migrate = Migrate()
def create_app(config_class=Config): def create_app(config_class=Config):
if not exists(config_class.RECEIPT_FOLDER): app = Flask(__name__)
makedirs(config_class.RECEIPT_FOLDER)
app = Flask(__name__, template_folder="../web/templates", static_folder="../web/static")
app.config.from_object(config_class) app.config.from_object(config_class)
bootstrap.init_app(app) bootstrap.init_app(app)
cors.init_app(app) cors.init_app(app)
db.init_app(app) db.init_app(app)
login.init_app(app) login.init_app(app)
ma.init_app(app)
mail.init_app(app) mail.init_app(app)
migrate.init_app(app, db, render_as_batch=True) migrate.init_app(app, db, render_as_batch=True)
@ -67,4 +62,4 @@ def create_app(config_class=Config):
return app return app
from models import * from src.models import *

View File

@ -2,5 +2,5 @@ from flask import Blueprint
bp = Blueprint('api', __name__, url_prefix='/api') bp = Blueprint('api', __name__, url_prefix='/api')
from .v1 import bp as bp_v1 from src.api.v1 import bp as bp_v1
bp.register_blueprint(bp_v1) bp.register_blueprint(bp_v1)

View File

@ -2,4 +2,4 @@ from flask import Blueprint
bp = Blueprint('v1', __name__, url_prefix='/v1') bp = Blueprint('v1', __name__, url_prefix='/v1')
from . import routes from src.api.v1 import routes

View File

@ -1,6 +1,6 @@
from src import LOGGER from src import LOGGER
from src.api.v1 import bp from src.api.v1 import bp
from models.login_token import LoginToken from src.models.login_token import LoginToken
from src.utils import database_utils from src.utils import database_utils
from flask import abort, request from flask import abort, request
from flask.json import jsonify from flask.json import jsonify

View File

@ -2,4 +2,4 @@ from flask import Blueprint
bp = Blueprint('auth', __name__, url_prefix='/auth') bp = Blueprint('auth', __name__, url_prefix='/auth')
from . import forms, routes from src.auth import forms, routes

View File

@ -1,4 +1,4 @@
from models.user import User from src.models.user import User
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import BooleanField, PasswordField, StringField, SubmitField from wtforms import BooleanField, PasswordField, StringField, SubmitField
from wtforms.validators import DataRequired, Email, EqualTo, ValidationError from wtforms.validators import DataRequired, Email, EqualTo, ValidationError

View File

@ -1,12 +1,12 @@
from src import db from src import db
from . import bp from src.auth import bp
from .email import send_password_reset_email from src.auth.email import send_password_reset_email
from .forms import LoginForm, RegistrationForm, ResetPasswordForm, ResetPasswordRequestForm from src.auth.forms import LoginForm, RegistrationForm, ResetPasswordForm, ResetPasswordRequestForm
from models.user import User from src.models.user import User
from src.utils.routes_utils import render_custom_template as render_template from src.utils.routes_utils import render_custom_template as render_template
from flask import flash, redirect, request, url_for from flask import flash, redirect, request, url_for
from flask_login import current_user, login_user, logout_user from flask_login import current_user, login_user, logout_user
from urllib.parse import urlparse from werkzeug.urls import url_parse
@bp.route('/register', methods=['GET', 'POST']) @bp.route('/register', methods=['GET', 'POST'])
def web_register(): def web_register():
@ -34,7 +34,7 @@ def web_login():
return redirect(url_for('auth.web_login')) return redirect(url_for('auth.web_login'))
login_user(user, remember=form.remember_me.data) login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next') next_page = request.args.get('next')
if not next_page or urlparse(next_page).netloc != '': if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('main.index') next_page = url_for('main.index')
return redirect(next_page) return redirect(next_page)
return render_template('auth/login.html', title='Sign In', form=form) return render_template('auth/login.html', title='Sign In', form=form)

View File

@ -2,4 +2,4 @@ from flask import Blueprint
bp = Blueprint('error', __name__, url_prefix='/error') bp = Blueprint('error', __name__, url_prefix='/error')
from . import handlers from src.errors import handlers

View File

@ -1,13 +1,11 @@
from flask import Blueprint from flask import Blueprint
bp = Blueprint('establishment', __name__, url_prefix='/establishment') bp = Blueprint('establishment', __name__, url_prefix='/establishment')
from .candidates import bp as bp_candidates from src.establishment.new import bp as bp_new
bp.register_blueprint(bp_candidates)
from .list import bp as bp_list
bp.register_blueprint(bp_list)
from .new import bp as bp_new
bp.register_blueprint(bp_new) bp.register_blueprint(bp_new)
from .overview import bp as bp_overview from src.establishment.list import bp as bp_list
bp.register_blueprint(bp_list)
from src.establishment.overview import bp as bp_overview
bp.register_blueprint(bp_overview) bp.register_blueprint(bp_overview)
from .payment import bp as bp_payment from src.establishment.candidates import bp as bp_candidates
bp.register_blueprint(bp_payment) bp.register_blueprint(bp_candidates)

View File

@ -2,4 +2,4 @@ from flask import Blueprint
bp = Blueprint("candidates", __name__, url_prefix='candidates') bp = Blueprint("candidates", __name__, url_prefix='candidates')
from . import forms, routes from src.establishment.candidates import routes

View File

@ -1,9 +1,9 @@
from flask import abort, current_app, redirect, request, url_for from flask import abort, redirect, url_for
from flask_login import current_user, login_required from flask_login import current_user, login_required
from . import bp
from .forms import EvaluateCandidateForm
from src import db, LOGGER from src import db, LOGGER
from models import Establishment, EstablishmentCandidate, LoginToken, User from src.establishment.candidates import bp
from src.establishment.candidates.forms import EvaluateCandidateForm
from src.models import Establishment, EstablishmentCandidate, LoginToken, User
from src.utils.routes_utils import render_custom_template as render_template from src.utils.routes_utils import render_custom_template as render_template
from src.utils.database_utils import generate_token from src.utils.database_utils import generate_token
@ -12,10 +12,8 @@ from src.utils.database_utils import generate_token
def candidates(establishment_id): def candidates(establishment_id):
establishment = Establishment.query.get_or_404(establishment_id) establishment = Establishment.query.get_or_404(establishment_id)
if(current_user == establishment.User): if(current_user == establishment.User):
page = request.args.get('page', 1, type=int)
form = EvaluateCandidateForm() form = EvaluateCandidateForm()
establishment_candidates = EstablishmentCandidate.query.filter_by(establishment = establishment.id).order_by(EstablishmentCandidate.user.asc()).paginate( establishment_candidates = EstablishmentCandidate.query.filter_by(establishment = establishment.id).all()
page=page, per_page=current_app.config['POSTS_PER_PAGE'], error_out=False)
if(form.validate_on_submit()): if(form.validate_on_submit()):
if(form.accept.data): if(form.accept.data):
login_token = LoginToken(Establishment = establishment, User = User.query.get(form.candidate_id.data), token = generate_token()) login_token = LoginToken(Establishment = establishment, User = User.query.get(form.candidate_id.data), token = generate_token())

View File

@ -2,4 +2,4 @@ from flask import Blueprint
bp = Blueprint("list", __name__, url_prefix='list') bp = Blueprint("list", __name__, url_prefix='list')
from . import routes from src.establishment.list import routes

Some files were not shown because too many files have changed in this diff Show More